You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-10 13:00:37 +00:00
Added working version for user-defined function autocompletion
This commit is contained in:
@@ -3521,9 +3521,29 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||||||
} break;
|
} break;
|
||||||
case GDScriptParser::COMPLETION_OVERRIDE_METHOD: {
|
case GDScriptParser::COMPLETION_OVERRIDE_METHOD: {
|
||||||
GDScriptParser::DataType native_type = completion_context.current_class->base_type;
|
GDScriptParser::DataType native_type = completion_context.current_class->base_type;
|
||||||
|
GDScriptParser::FunctionNode *function_node = static_cast<GDScriptParser::FunctionNode *>(completion_context.node);
|
||||||
|
bool is_static = function_node != nullptr && function_node->is_static;
|
||||||
while (native_type.is_set() && native_type.kind != GDScriptParser::DataType::NATIVE) {
|
while (native_type.is_set() && native_type.kind != GDScriptParser::DataType::NATIVE) {
|
||||||
switch (native_type.kind) {
|
switch (native_type.kind) {
|
||||||
case GDScriptParser::DataType::CLASS: {
|
case GDScriptParser::DataType::CLASS: {
|
||||||
|
for (const GDScriptParser::ClassNode::Member &member : native_type.class_type->members) {
|
||||||
|
if (member.type != GDScriptParser::ClassNode::Member::FUNCTION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.has(member.function->identifier->name) || completion_context.current_class->has_function(member.function->identifier->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_static != member.function->is_static) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String display_name = member.function->identifier->name;
|
||||||
|
display_name += member.function->signature + ":";
|
||||||
|
ScriptLanguage::CodeCompletionOption option(display_name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
|
||||||
|
options.insert(member.function->identifier->name, option); // Insert name instead of display to track duplicates.
|
||||||
|
}
|
||||||
native_type = native_type.class_type->base_type;
|
native_type = native_type.class_type->base_type;
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
@@ -3544,17 +3564,20 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||||||
bool use_type_hint = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints").operator bool();
|
bool use_type_hint = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints").operator bool();
|
||||||
|
|
||||||
List<MethodInfo> virtual_methods;
|
List<MethodInfo> virtual_methods;
|
||||||
ClassDB::get_virtual_methods(class_name, &virtual_methods);
|
if (is_static) {
|
||||||
|
|
||||||
{
|
|
||||||
// Not truly a virtual method, but can also be "overridden".
|
// Not truly a virtual method, but can also be "overridden".
|
||||||
MethodInfo static_init("_static_init");
|
MethodInfo static_init("_static_init");
|
||||||
static_init.return_val.type = Variant::NIL;
|
static_init.return_val.type = Variant::NIL;
|
||||||
static_init.flags |= METHOD_FLAG_STATIC | METHOD_FLAG_VIRTUAL;
|
static_init.flags |= METHOD_FLAG_STATIC | METHOD_FLAG_VIRTUAL;
|
||||||
virtual_methods.push_back(static_init);
|
virtual_methods.push_back(static_init);
|
||||||
|
} else {
|
||||||
|
ClassDB::get_virtual_methods(class_name, &virtual_methods);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const MethodInfo &mi : virtual_methods) {
|
for (const MethodInfo &mi : virtual_methods) {
|
||||||
|
if (options.has(mi.name) || completion_context.current_class->has_function(mi.name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String method_hint = mi.name;
|
String method_hint = mi.name;
|
||||||
if (method_hint.contains_char(':')) {
|
if (method_hint.contains_char(':')) {
|
||||||
method_hint = method_hint.get_slicec(':', 0);
|
method_hint = method_hint.get_slicec(':', 0);
|
||||||
|
|||||||
@@ -1615,7 +1615,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum(bool p_is_abstract, bool p_
|
|||||||
return enum_node;
|
return enum_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type) {
|
void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type, int p_signature_start) {
|
||||||
if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) {
|
if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) {
|
||||||
bool default_used = false;
|
bool default_used = false;
|
||||||
do {
|
do {
|
||||||
@@ -1666,15 +1666,30 @@ void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNod
|
|||||||
current_class->has_static_data = true;
|
current_class->has_static_data = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (p_type == "function" && p_signature_start != -1) {
|
||||||
|
int signature_end_pos = tokenizer->get_current_position() - 1;
|
||||||
|
String source_code = tokenizer->get_source_code();
|
||||||
|
p_function->signature = source_code.substr(p_signature_start, signature_end_pos - p_signature_start);
|
||||||
|
}
|
||||||
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
// TODO: Improve token consumption so it synchronizes to a statement boundary. This way we can get into the function body with unrecognized tokens.
|
// TODO: Improve token consumption so it synchronizes to a statement boundary. This way we can get into the function body with unrecognized tokens.
|
||||||
consume(GDScriptTokenizer::Token::COLON, vformat(R"(Expected ":" after %s declaration.)", p_type));
|
consume(GDScriptTokenizer::Token::COLON, vformat(R"(Expected ":" after %s declaration.)", p_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
GDScriptParser::FunctionNode *GDScriptParser::parse_function(bool p_is_abstract, bool p_is_static) {
|
GDScriptParser::FunctionNode *GDScriptParser::parse_function(bool p_is_abstract, bool p_is_static) {
|
||||||
FunctionNode *function = alloc_node<FunctionNode>();
|
FunctionNode *function = alloc_node<FunctionNode>();
|
||||||
|
function->is_static = p_is_static;
|
||||||
|
|
||||||
make_completion_context(COMPLETION_OVERRIDE_METHOD, function);
|
make_completion_context(COMPLETION_OVERRIDE_METHOD, function);
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
// The signature is something like `(a: int, b: int = 0) -> void`.
|
||||||
|
// We start one token earlier, since the parser looks one token ahead.
|
||||||
|
const int signature_start_pos = tokenizer->get_current_position();
|
||||||
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) {
|
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) {
|
||||||
complete_extents(function);
|
complete_extents(function);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -1684,7 +1699,6 @@ GDScriptParser::FunctionNode *GDScriptParser::parse_function(bool p_is_abstract,
|
|||||||
current_function = function;
|
current_function = function;
|
||||||
|
|
||||||
function->identifier = parse_identifier();
|
function->identifier = parse_identifier();
|
||||||
function->is_static = p_is_static;
|
|
||||||
|
|
||||||
SuiteNode *body = alloc_node<SuiteNode>();
|
SuiteNode *body = alloc_node<SuiteNode>();
|
||||||
|
|
||||||
@@ -1693,13 +1707,18 @@ GDScriptParser::FunctionNode *GDScriptParser::parse_function(bool p_is_abstract,
|
|||||||
|
|
||||||
push_multiline(true);
|
push_multiline(true);
|
||||||
consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)");
|
consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)");
|
||||||
parse_function_signature(function, body, "function");
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
parse_function_signature(function, body, "function", signature_start_pos);
|
||||||
|
#else // !TOOLS_ENABLED
|
||||||
|
parse_function_signature(function, body, "function", -1);
|
||||||
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
current_suite = previous_suite;
|
current_suite = previous_suite;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
function->min_local_doc_line = previous.end_line + 1;
|
function->min_local_doc_line = previous.end_line + 1;
|
||||||
#endif
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
function->body = parse_suite("function declaration", body);
|
function->body = parse_suite("function declaration", body);
|
||||||
|
|
||||||
@@ -3619,7 +3638,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p
|
|||||||
SuiteNode *previous_suite = current_suite;
|
SuiteNode *previous_suite = current_suite;
|
||||||
current_suite = body;
|
current_suite = body;
|
||||||
|
|
||||||
parse_function_signature(function, body, "lambda");
|
parse_function_signature(function, body, "lambda", -1);
|
||||||
|
|
||||||
current_suite = previous_suite;
|
current_suite = previous_suite;
|
||||||
|
|
||||||
|
|||||||
@@ -863,6 +863,7 @@ public:
|
|||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
MemberDocData doc_data;
|
MemberDocData doc_data;
|
||||||
int min_local_doc_line = 0;
|
int min_local_doc_line = 0;
|
||||||
|
String signature; // For autocompletion.
|
||||||
#endif // TOOLS_ENABLED
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
bool resolved_signature = false;
|
bool resolved_signature = false;
|
||||||
@@ -1510,7 +1511,7 @@ private:
|
|||||||
EnumNode *parse_enum(bool p_is_abstract, bool p_is_static);
|
EnumNode *parse_enum(bool p_is_abstract, bool p_is_static);
|
||||||
ParameterNode *parse_parameter();
|
ParameterNode *parse_parameter();
|
||||||
FunctionNode *parse_function(bool p_is_abstract, bool p_is_static);
|
FunctionNode *parse_function(bool p_is_abstract, bool p_is_static);
|
||||||
void parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type);
|
void parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type, int p_signature_start);
|
||||||
SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr, bool p_for_lambda = false);
|
SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr, bool p_for_lambda = false);
|
||||||
// Annotations
|
// Annotations
|
||||||
AnnotationNode *parse_annotation(uint32_t p_valid_targets);
|
AnnotationNode *parse_annotation(uint32_t p_valid_targets);
|
||||||
|
|||||||
@@ -201,6 +201,12 @@ public:
|
|||||||
|
|
||||||
static String get_token_name(Token::Type p_token_type);
|
static String get_token_name(Token::Type p_token_type);
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
// This is a temporary solution, as Tokens are not able to store their position, only lines and columns.
|
||||||
|
virtual int get_current_position() const { return 0; }
|
||||||
|
virtual String get_source_code() const { return ""; }
|
||||||
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
virtual int get_cursor_line() const = 0;
|
virtual int get_cursor_line() const = 0;
|
||||||
virtual int get_cursor_column() const = 0;
|
virtual int get_cursor_column() const = 0;
|
||||||
virtual void set_cursor_position(int p_line, int p_column) = 0;
|
virtual void set_cursor_position(int p_line, int p_column) = 0;
|
||||||
@@ -287,6 +293,11 @@ public:
|
|||||||
|
|
||||||
const Vector<int> &get_continuation_lines() const { return continuation_lines; }
|
const Vector<int> &get_continuation_lines() const { return continuation_lines; }
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
virtual int get_current_position() const override { return position; }
|
||||||
|
virtual String get_source_code() const override { return source; }
|
||||||
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
virtual int get_cursor_line() const override;
|
virtual int get_cursor_line() const override;
|
||||||
virtual int get_cursor_column() const override;
|
virtual int get_cursor_column() const override;
|
||||||
virtual void set_cursor_position(int p_line, int p_column) override;
|
virtual void set_cursor_position(int p_line, int p_column) override;
|
||||||
|
|||||||
@@ -6,3 +6,18 @@ var property_of_a
|
|||||||
|
|
||||||
func func_of_a():
|
func func_of_a():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func _func_of_a_underscore():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
static func func_of_a_static():
|
||||||
|
pass
|
||||||
|
|
||||||
|
func func_of_a_args(a: int):
|
||||||
|
pass
|
||||||
|
|
||||||
|
func func_of_a_callable(call := func():
|
||||||
|
var x_of_a = 10):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
scene="res://completion/get_node/get_node.tscn"
|
||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
; GDScript: class_a.notest.gd
|
||||||
|
{"display": "func_of_a():"},
|
||||||
|
{"display": "func_of_a_args(a: int):"},
|
||||||
|
{"display": "func_of_a_callable(call := func():
|
||||||
|
var x_of_a = 10):"}
|
||||||
|
]
|
||||||
|
exclude=[
|
||||||
|
; GDScript: class_a.notest.gd
|
||||||
|
{"display": "_static_init() -> void:"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
extends "res://completion/class_a.notest.gd"
|
||||||
|
|
||||||
|
func ➡
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
scene="res://completion/get_node/get_node.tscn"
|
||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
; GDScript: class_a.notest.gd
|
||||||
|
{"display": "_static_init() -> void:"},
|
||||||
|
{"display": "func_of_a_static():"},
|
||||||
|
]
|
||||||
|
exclude=[
|
||||||
|
; GDScript: class_a.notest.gd
|
||||||
|
{"display": "func_of_a():"},
|
||||||
|
{"display": "func_of_a_args(a: int):"},
|
||||||
|
{"display": "func_of_a_callable(call := func():
|
||||||
|
var x_of_a = 10):"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
extends "res://completion/class_a.notest.gd"
|
||||||
|
|
||||||
|
static func ➡
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
scene="res://completion/get_node/get_node.tscn"
|
||||||
|
[output]
|
||||||
|
include=[
|
||||||
|
; GDScript: class_a.notest.gd
|
||||||
|
{"display": "_func_of_a_underscore():"},
|
||||||
|
]
|
||||||
|
exclude=[
|
||||||
|
; GDScript: class_a.notest.gd
|
||||||
|
{"display": "_static_init() -> void:"},
|
||||||
|
]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
extends "res://completion/class_a.notest.gd"
|
||||||
|
|
||||||
|
func _➡
|
||||||
Reference in New Issue
Block a user