Skip to content

Commit c977b59

Browse files
committed
Merge pull request #107872 from Thought-Weaver/users/loganapple/editor-caret-fix
[Autocomplete] Avoid prepending literals when the character has already been typed
2 parents c83ccae + 216c462 commit c977b59

File tree

5 files changed

+104
-23
lines changed

5 files changed

+104
-23
lines changed

modules/gdscript/gdscript_editor.cpp

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2909,9 +2909,10 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co
29092909
}
29102910
}
29112911

2912-
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) {
2912+
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) {
29132913
Variant base = p_base.value;
29142914
GDScriptParser::DataType base_type = p_base.type;
2915+
const StringName &method = p_call->function_name;
29152916

29162917
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
29172918
const bool use_string_names = EDITOR_GET("text_editor/completion/add_string_name_literals");
@@ -2920,7 +2921,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
29202921
while (base_type.is_set() && !base_type.is_variant()) {
29212922
switch (base_type.kind) {
29222923
case GDScriptParser::DataType::CLASS: {
2923-
if (base_type.is_meta_type && p_method == SNAME("new")) {
2924+
if (base_type.is_meta_type && method == SNAME("new")) {
29242925
const GDScriptParser::ClassNode *current = base_type.class_type;
29252926

29262927
do {
@@ -2939,8 +2940,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
29392940
return;
29402941
}
29412942

2942-
if (base_type.class_type->has_member(p_method)) {
2943-
const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(p_method);
2943+
if (base_type.class_type->has_member(method)) {
2944+
const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(method);
29442945

29452946
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
29462947
r_arghint = _make_arguments_hint(member.function, p_argidx);
@@ -2951,8 +2952,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
29512952
base_type = base_type.class_type->base_type;
29522953
} break;
29532954
case GDScriptParser::DataType::SCRIPT: {
2954-
if (base_type.script_type->is_valid() && base_type.script_type->has_method(p_method)) {
2955-
r_arghint = _make_arguments_hint(base_type.script_type->get_method_info(p_method), p_argidx);
2955+
if (base_type.script_type->is_valid() && base_type.script_type->has_method(method)) {
2956+
r_arghint = _make_arguments_hint(base_type.script_type->get_method_info(method), p_argidx);
29562957
return;
29572958
}
29582959
Ref<Script> base_script = base_type.script_type->get_base_script();
@@ -2974,21 +2975,35 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
29742975
MethodInfo info;
29752976
int method_args = 0;
29762977

2977-
if (ClassDB::get_method_info(class_name, p_method, &info)) {
2978+
if (ClassDB::get_method_info(class_name, method, &info)) {
29782979
method_args = info.arguments.size();
29792980
if (base.get_type() == Variant::OBJECT) {
29802981
Object *obj = base.operator Object *();
29812982
if (obj) {
29822983
List<String> options;
2983-
obj->get_argument_options(p_method, p_argidx, &options);
2984+
obj->get_argument_options(method, p_argidx, &options);
29842985
for (String &opt : options) {
29852986
// Handle user preference.
29862987
if (opt.is_quoted()) {
29872988
opt = opt.unquote().quote(quote_style);
29882989
if (use_string_names && info.arguments[p_argidx].type == Variant::STRING_NAME) {
2989-
opt = "&" + opt;
2990+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
2991+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
2992+
if (literal->value.get_type() == Variant::STRING) {
2993+
opt = "&" + opt;
2994+
}
2995+
} else {
2996+
opt = "&" + opt;
2997+
}
29902998
} else if (use_node_paths && info.arguments[p_argidx].type == Variant::NODE_PATH) {
2991-
opt = "^" + opt;
2999+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3000+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3001+
if (literal->value.get_type() == Variant::STRING) {
3002+
opt = "^" + opt;
3003+
}
3004+
} else {
3005+
opt = "^" + opt;
3006+
}
29923007
}
29933008
}
29943009
ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
@@ -3007,13 +3022,13 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30073022
r_arghint = _make_arguments_hint(info, p_argidx);
30083023
}
30093024

3010-
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")) {
3025+
if (p_argidx == 1 && p_call && ClassDB::is_parent_class(class_name, SNAME("Tween")) && method == SNAME("tween_property")) {
30113026
// Get tweened objects properties.
3012-
if (static_cast<GDScriptParser::CallNode *>(p_context.node)->arguments.is_empty()) {
3027+
if (p_call->arguments.is_empty()) {
30133028
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
30143029
break;
30153030
}
3016-
GDScriptParser::ExpressionNode *tweened_object = static_cast<GDScriptParser::CallNode *>(p_context.node)->arguments[0];
3031+
GDScriptParser::ExpressionNode *tweened_object = p_call->arguments[0];
30173032
if (!tweened_object) {
30183033
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
30193034
break;
@@ -3033,7 +3048,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30333048
}
30343049
String name = E.name.quote(quote_style);
30353050
if (use_node_paths) {
3036-
name = "^" + name;
3051+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3052+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3053+
if (literal->value.get_type() == Variant::STRING) {
3054+
name = "^" + name;
3055+
}
3056+
} else {
3057+
name = "^" + name;
3058+
}
30373059
}
30383060
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n);
30393061
r_result.insert(option.display, option);
@@ -3051,7 +3073,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30513073
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
30523074
String name = member.get_name().quote(quote_style);
30533075
if (use_node_paths) {
3054-
name = "^" + name;
3076+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3077+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3078+
if (literal->value.get_type() == Variant::STRING) {
3079+
name = "^" + name;
3080+
}
3081+
} else {
3082+
name = "^" + name;
3083+
}
30553084
}
30563085
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n);
30573086
r_result.insert(option.display, option);
@@ -3078,14 +3107,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30783107
}
30793108
String name = E.name.quote(quote_style);
30803109
if (use_node_paths) {
3081-
name = "^" + name;
3110+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3111+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3112+
if (literal->value.get_type() == Variant::STRING) {
3113+
name = "^" + name;
3114+
}
3115+
} else {
3116+
name = "^" + name;
3117+
}
30823118
}
30833119
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
30843120
r_result.insert(option.display, option);
30853121
}
30863122
}
30873123

3088-
if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (p_method == SNAME("get_node") || p_method == SNAME("has_node"))) {
3124+
if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (method == SNAME("get_node") || method == SNAME("has_node"))) {
30893125
// Get autoloads
30903126
List<PropertyInfo> props;
30913127
ProjectSettings::get_singleton()->get_property_list(&props);
@@ -3098,14 +3134,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30983134
String name = s.get_slicec('/', 1);
30993135
String path = ("/root/" + name).quote(quote_style);
31003136
if (use_node_paths) {
3101-
path = "^" + path;
3137+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3138+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3139+
if (literal->value.get_type() == Variant::STRING) {
3140+
path = "^" + path;
3141+
}
3142+
} else {
3143+
path = "^" + path;
3144+
}
31023145
}
31033146
ScriptLanguage::CodeCompletionOption option(path, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
31043147
r_result.insert(option.display, option);
31053148
}
31063149
}
31073150

3108-
if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && p_method.operator String().contains("action")) {
3151+
if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && method.operator String().contains("action")) {
31093152
// Get input actions
31103153
List<PropertyInfo> props;
31113154
ProjectSettings::get_singleton()->get_property_list(&props);
@@ -3116,14 +3159,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
31163159
}
31173160
String name = s.get_slicec('/', 1).quote(quote_style);
31183161
if (use_string_names) {
3119-
name = "&" + name;
3162+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3163+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3164+
if (literal->value.get_type() == Variant::STRING) {
3165+
name = "&" + name;
3166+
}
3167+
} else {
3168+
name = "&" + name;
3169+
}
31203170
}
31213171
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
31223172
r_result.insert(option.display, option);
31233173
}
31243174
}
31253175
if (EDITOR_GET("text_editor/completion/complete_file_paths")) {
3126-
if (p_argidx == 0 && p_method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) {
3176+
if (p_argidx == 0 && method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) {
31273177
HashMap<String, ScriptLanguage::CodeCompletionOption> list;
31283178
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), list, SNAME("PackedScene"));
31293179
for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &key_value_pair : list) {
@@ -3147,7 +3197,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
31473197
List<MethodInfo> methods;
31483198
base.get_method_list(&methods);
31493199
for (const MethodInfo &E : methods) {
3150-
if (E.name == p_method) {
3200+
if (E.name == method) {
31513201
r_arghint = _make_arguments_hint(E, p_argidx);
31523202
return;
31533203
}
@@ -3358,7 +3408,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
33583408
GDScriptCompletionIdentifier ci;
33593409
ci.type = base_type;
33603410
ci.value = base;
3361-
_find_call_arguments(p_context, ci, call->function_name, p_argidx, _static, r_result, r_arghint);
3411+
_list_call_arguments(p_context, ci, call, p_argidx, _static, r_result, r_arghint);
33623412

33633413
r_forced = r_result.size() > 0;
33643414
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[input]
2+
add_node_path_literals=true
3+
[output]
4+
include=[
5+
{"insert_text": "\"property_of_a\""},
6+
{"insert_text": "\"name\""},
7+
]
8+
exclude=[
9+
{"insert_text": "^\"property_of_a\""},
10+
{"insert_text": "^\"name\""},
11+
]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
extends Node
2+
3+
const A = preload("res://completion/class_a.notest.gd")
4+
5+
func _ready() -> void:
6+
var a := A.new()
7+
var tween := get_tree().create_tween()
8+
tween.tween_property(a, ^"➡")
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[input]
2+
add_string_name_literals=true
3+
[output]
4+
include=[
5+
{"insert_text": "\"test_input_action\""},
6+
]
7+
exclude=[
8+
{"insert_text": "&\"test_input_action\""},
9+
]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func _input(event: InputEvent) -> void:
2+
event.is_action_pressed(&"➡")
3+
pass

0 commit comments

Comments
 (0)