mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Initial fix for double caret inserting in NodePath
Additional cases where prepending doubles up Moved code to helper function Added unit tests Lookup caret character instead of passing position Switched to using the parsed type Adding safety checks and various cleanup
This commit is contained in:
parent
48f361a6eb
commit
216c462277
5 changed files with 104 additions and 23 deletions
|
@ -2854,9 +2854,10 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co
|
|||
}
|
||||
}
|
||||
|
||||
static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) {
|
||||
static void _list_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const GDScriptParser::CallNode *p_call, int p_argidx, bool p_static, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) {
|
||||
Variant base = p_base.value;
|
||||
GDScriptParser::DataType base_type = p_base.type;
|
||||
const StringName &method = p_call->function_name;
|
||||
|
||||
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
|
||||
const bool use_string_names = EDITOR_GET("text_editor/completion/add_string_name_literals");
|
||||
|
@ -2865,7 +2866,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
while (base_type.is_set() && !base_type.is_variant()) {
|
||||
switch (base_type.kind) {
|
||||
case GDScriptParser::DataType::CLASS: {
|
||||
if (base_type.is_meta_type && p_method == SNAME("new")) {
|
||||
if (base_type.is_meta_type && method == SNAME("new")) {
|
||||
const GDScriptParser::ClassNode *current = base_type.class_type;
|
||||
|
||||
do {
|
||||
|
@ -2884,8 +2885,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
return;
|
||||
}
|
||||
|
||||
if (base_type.class_type->has_member(p_method)) {
|
||||
const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(p_method);
|
||||
if (base_type.class_type->has_member(method)) {
|
||||
const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(method);
|
||||
|
||||
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
|
||||
r_arghint = _make_arguments_hint(member.function, p_argidx);
|
||||
|
@ -2896,8 +2897,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
base_type = base_type.class_type->base_type;
|
||||
} break;
|
||||
case GDScriptParser::DataType::SCRIPT: {
|
||||
if (base_type.script_type->is_valid() && base_type.script_type->has_method(p_method)) {
|
||||
r_arghint = _make_arguments_hint(base_type.script_type->get_method_info(p_method), p_argidx);
|
||||
if (base_type.script_type->is_valid() && base_type.script_type->has_method(method)) {
|
||||
r_arghint = _make_arguments_hint(base_type.script_type->get_method_info(method), p_argidx);
|
||||
return;
|
||||
}
|
||||
Ref<Script> base_script = base_type.script_type->get_base_script();
|
||||
|
@ -2919,21 +2920,35 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
MethodInfo info;
|
||||
int method_args = 0;
|
||||
|
||||
if (ClassDB::get_method_info(class_name, p_method, &info)) {
|
||||
if (ClassDB::get_method_info(class_name, method, &info)) {
|
||||
method_args = info.arguments.size();
|
||||
if (base.get_type() == Variant::OBJECT) {
|
||||
Object *obj = base.operator Object *();
|
||||
if (obj) {
|
||||
List<String> options;
|
||||
obj->get_argument_options(p_method, p_argidx, &options);
|
||||
obj->get_argument_options(method, p_argidx, &options);
|
||||
for (String &opt : options) {
|
||||
// Handle user preference.
|
||||
if (opt.is_quoted()) {
|
||||
opt = opt.unquote().quote(quote_style);
|
||||
if (use_string_names && info.arguments[p_argidx].type == Variant::STRING_NAME) {
|
||||
opt = "&" + opt;
|
||||
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
|
||||
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
|
||||
if (literal->value.get_type() == Variant::STRING) {
|
||||
opt = "&" + opt;
|
||||
}
|
||||
} else {
|
||||
opt = "&" + opt;
|
||||
}
|
||||
} else if (use_node_paths && info.arguments[p_argidx].type == Variant::NODE_PATH) {
|
||||
opt = "^" + opt;
|
||||
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
|
||||
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
|
||||
if (literal->value.get_type() == Variant::STRING) {
|
||||
opt = "^" + opt;
|
||||
}
|
||||
} else {
|
||||
opt = "^" + opt;
|
||||
}
|
||||
}
|
||||
}
|
||||
ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
|
||||
|
@ -2952,13 +2967,13 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
r_arghint = _make_arguments_hint(info, p_argidx);
|
||||
}
|
||||
|
||||
if (p_argidx == 1 && p_context.node && p_context.node->type == GDScriptParser::Node::CALL && ClassDB::is_parent_class(class_name, SNAME("Tween")) && p_method == SNAME("tween_property")) {
|
||||
if (p_argidx == 1 && p_call && ClassDB::is_parent_class(class_name, SNAME("Tween")) && method == SNAME("tween_property")) {
|
||||
// Get tweened objects properties.
|
||||
if (static_cast<GDScriptParser::CallNode *>(p_context.node)->arguments.is_empty()) {
|
||||
if (p_call->arguments.is_empty()) {
|
||||
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
|
||||
break;
|
||||
}
|
||||
GDScriptParser::ExpressionNode *tweened_object = static_cast<GDScriptParser::CallNode *>(p_context.node)->arguments[0];
|
||||
GDScriptParser::ExpressionNode *tweened_object = p_call->arguments[0];
|
||||
if (!tweened_object) {
|
||||
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
|
||||
break;
|
||||
|
@ -2978,7 +2993,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
}
|
||||
String name = E.name.quote(quote_style);
|
||||
if (use_node_paths) {
|
||||
name = "^" + name;
|
||||
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
|
||||
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
|
||||
if (literal->value.get_type() == Variant::STRING) {
|
||||
name = "^" + name;
|
||||
}
|
||||
} else {
|
||||
name = "^" + name;
|
||||
}
|
||||
}
|
||||
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n);
|
||||
r_result.insert(option.display, option);
|
||||
|
@ -2996,7 +3018,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
|
||||
String name = member.get_name().quote(quote_style);
|
||||
if (use_node_paths) {
|
||||
name = "^" + name;
|
||||
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
|
||||
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
|
||||
if (literal->value.get_type() == Variant::STRING) {
|
||||
name = "^" + name;
|
||||
}
|
||||
} else {
|
||||
name = "^" + name;
|
||||
}
|
||||
}
|
||||
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n);
|
||||
r_result.insert(option.display, option);
|
||||
|
@ -3023,14 +3052,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
}
|
||||
String name = E.name.quote(quote_style);
|
||||
if (use_node_paths) {
|
||||
name = "^" + name;
|
||||
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
|
||||
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
|
||||
if (literal->value.get_type() == Variant::STRING) {
|
||||
name = "^" + name;
|
||||
}
|
||||
} else {
|
||||
name = "^" + name;
|
||||
}
|
||||
}
|
||||
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
|
||||
r_result.insert(option.display, option);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (p_method == SNAME("get_node") || p_method == SNAME("has_node"))) {
|
||||
if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (method == SNAME("get_node") || method == SNAME("has_node"))) {
|
||||
// Get autoloads
|
||||
List<PropertyInfo> props;
|
||||
ProjectSettings::get_singleton()->get_property_list(&props);
|
||||
|
@ -3043,14 +3079,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
String name = s.get_slicec('/', 1);
|
||||
String path = ("/root/" + name).quote(quote_style);
|
||||
if (use_node_paths) {
|
||||
path = "^" + path;
|
||||
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
|
||||
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
|
||||
if (literal->value.get_type() == Variant::STRING) {
|
||||
path = "^" + path;
|
||||
}
|
||||
} else {
|
||||
path = "^" + path;
|
||||
}
|
||||
}
|
||||
ScriptLanguage::CodeCompletionOption option(path, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
|
||||
r_result.insert(option.display, option);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && p_method.operator String().contains("action")) {
|
||||
if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && method.operator String().contains("action")) {
|
||||
// Get input actions
|
||||
List<PropertyInfo> props;
|
||||
ProjectSettings::get_singleton()->get_property_list(&props);
|
||||
|
@ -3061,14 +3104,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
}
|
||||
String name = s.get_slicec('/', 1).quote(quote_style);
|
||||
if (use_string_names) {
|
||||
name = "&" + name;
|
||||
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
|
||||
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
|
||||
if (literal->value.get_type() == Variant::STRING) {
|
||||
name = "&" + name;
|
||||
}
|
||||
} else {
|
||||
name = "&" + name;
|
||||
}
|
||||
}
|
||||
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
|
||||
r_result.insert(option.display, option);
|
||||
}
|
||||
}
|
||||
if (EDITOR_GET("text_editor/completion/complete_file_paths")) {
|
||||
if (p_argidx == 0 && p_method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) {
|
||||
if (p_argidx == 0 && method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) {
|
||||
HashMap<String, ScriptLanguage::CodeCompletionOption> list;
|
||||
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), list, SNAME("PackedScene"));
|
||||
for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &key_value_pair : list) {
|
||||
|
@ -3092,7 +3142,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
List<MethodInfo> methods;
|
||||
base.get_method_list(&methods);
|
||||
for (const MethodInfo &E : methods) {
|
||||
if (E.name == p_method) {
|
||||
if (E.name == method) {
|
||||
r_arghint = _make_arguments_hint(E, p_argidx);
|
||||
return;
|
||||
}
|
||||
|
@ -3290,7 +3340,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
|
|||
GDScriptCompletionIdentifier ci;
|
||||
ci.type = base_type;
|
||||
ci.value = base;
|
||||
_find_call_arguments(p_context, ci, call->function_name, p_argidx, _static, r_result, r_arghint);
|
||||
_list_call_arguments(p_context, ci, call, p_argidx, _static, r_result, r_arghint);
|
||||
|
||||
r_forced = r_result.size() > 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue