Skip to content

Commit 216c462

Browse files
loganappleThought-Weaver
authored andcommitted
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
1 parent 48f361a commit 216c462

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
@@ -2854,9 +2854,10 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co
28542854
}
28552855
}
28562856

2857-
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) {
2857+
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) {
28582858
Variant base = p_base.value;
28592859
GDScriptParser::DataType base_type = p_base.type;
2860+
const StringName &method = p_call->function_name;
28602861

28612862
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
28622863
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
28652866
while (base_type.is_set() && !base_type.is_variant()) {
28662867
switch (base_type.kind) {
28672868
case GDScriptParser::DataType::CLASS: {
2868-
if (base_type.is_meta_type && p_method == SNAME("new")) {
2869+
if (base_type.is_meta_type && method == SNAME("new")) {
28692870
const GDScriptParser::ClassNode *current = base_type.class_type;
28702871

28712872
do {
@@ -2884,8 +2885,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
28842885
return;
28852886
}
28862887

2887-
if (base_type.class_type->has_member(p_method)) {
2888-
const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(p_method);
2888+
if (base_type.class_type->has_member(method)) {
2889+
const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(method);
28892890

28902891
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
28912892
r_arghint = _make_arguments_hint(member.function, p_argidx);
@@ -2896,8 +2897,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
28962897
base_type = base_type.class_type->base_type;
28972898
} break;
28982899
case GDScriptParser::DataType::SCRIPT: {
2899-
if (base_type.script_type->is_valid() && base_type.script_type->has_method(p_method)) {
2900-
r_arghint = _make_arguments_hint(base_type.script_type->get_method_info(p_method), p_argidx);
2900+
if (base_type.script_type->is_valid() && base_type.script_type->has_method(method)) {
2901+
r_arghint = _make_arguments_hint(base_type.script_type->get_method_info(method), p_argidx);
29012902
return;
29022903
}
29032904
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
29192920
MethodInfo info;
29202921
int method_args = 0;
29212922

2922-
if (ClassDB::get_method_info(class_name, p_method, &info)) {
2923+
if (ClassDB::get_method_info(class_name, method, &info)) {
29232924
method_args = info.arguments.size();
29242925
if (base.get_type() == Variant::OBJECT) {
29252926
Object *obj = base.operator Object *();
29262927
if (obj) {
29272928
List<String> options;
2928-
obj->get_argument_options(p_method, p_argidx, &options);
2929+
obj->get_argument_options(method, p_argidx, &options);
29292930
for (String &opt : options) {
29302931
// Handle user preference.
29312932
if (opt.is_quoted()) {
29322933
opt = opt.unquote().quote(quote_style);
29332934
if (use_string_names && info.arguments[p_argidx].type == Variant::STRING_NAME) {
2934-
opt = "&" + opt;
2935+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
2936+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
2937+
if (literal->value.get_type() == Variant::STRING) {
2938+
opt = "&" + opt;
2939+
}
2940+
} else {
2941+
opt = "&" + opt;
2942+
}
29352943
} else if (use_node_paths && info.arguments[p_argidx].type == Variant::NODE_PATH) {
2936-
opt = "^" + opt;
2944+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
2945+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
2946+
if (literal->value.get_type() == Variant::STRING) {
2947+
opt = "^" + opt;
2948+
}
2949+
} else {
2950+
opt = "^" + opt;
2951+
}
29372952
}
29382953
}
29392954
ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
@@ -2952,13 +2967,13 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
29522967
r_arghint = _make_arguments_hint(info, p_argidx);
29532968
}
29542969

2955-
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")) {
2970+
if (p_argidx == 1 && p_call && ClassDB::is_parent_class(class_name, SNAME("Tween")) && method == SNAME("tween_property")) {
29562971
// Get tweened objects properties.
2957-
if (static_cast<GDScriptParser::CallNode *>(p_context.node)->arguments.is_empty()) {
2972+
if (p_call->arguments.is_empty()) {
29582973
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
29592974
break;
29602975
}
2961-
GDScriptParser::ExpressionNode *tweened_object = static_cast<GDScriptParser::CallNode *>(p_context.node)->arguments[0];
2976+
GDScriptParser::ExpressionNode *tweened_object = p_call->arguments[0];
29622977
if (!tweened_object) {
29632978
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
29642979
break;
@@ -2978,7 +2993,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
29782993
}
29792994
String name = E.name.quote(quote_style);
29802995
if (use_node_paths) {
2981-
name = "^" + name;
2996+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
2997+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
2998+
if (literal->value.get_type() == Variant::STRING) {
2999+
name = "^" + name;
3000+
}
3001+
} else {
3002+
name = "^" + name;
3003+
}
29823004
}
29833005
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n);
29843006
r_result.insert(option.display, option);
@@ -2996,7 +3018,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
29963018
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
29973019
String name = member.get_name().quote(quote_style);
29983020
if (use_node_paths) {
2999-
name = "^" + name;
3021+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3022+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3023+
if (literal->value.get_type() == Variant::STRING) {
3024+
name = "^" + name;
3025+
}
3026+
} else {
3027+
name = "^" + name;
3028+
}
30003029
}
30013030
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, ScriptLanguage::CodeCompletionLocation::LOCATION_LOCAL + n);
30023031
r_result.insert(option.display, option);
@@ -3023,14 +3052,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30233052
}
30243053
String name = E.name.quote(quote_style);
30253054
if (use_node_paths) {
3026-
name = "^" + name;
3055+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3056+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3057+
if (literal->value.get_type() == Variant::STRING) {
3058+
name = "^" + name;
3059+
}
3060+
} else {
3061+
name = "^" + name;
3062+
}
30273063
}
30283064
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
30293065
r_result.insert(option.display, option);
30303066
}
30313067
}
30323068

3033-
if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (p_method == SNAME("get_node") || p_method == SNAME("has_node"))) {
3069+
if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (method == SNAME("get_node") || method == SNAME("has_node"))) {
30343070
// Get autoloads
30353071
List<PropertyInfo> props;
30363072
ProjectSettings::get_singleton()->get_property_list(&props);
@@ -3043,14 +3079,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30433079
String name = s.get_slicec('/', 1);
30443080
String path = ("/root/" + name).quote(quote_style);
30453081
if (use_node_paths) {
3046-
path = "^" + path;
3082+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3083+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3084+
if (literal->value.get_type() == Variant::STRING) {
3085+
path = "^" + path;
3086+
}
3087+
} else {
3088+
path = "^" + path;
3089+
}
30473090
}
30483091
ScriptLanguage::CodeCompletionOption option(path, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
30493092
r_result.insert(option.display, option);
30503093
}
30513094
}
30523095

3053-
if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && p_method.operator String().contains("action")) {
3096+
if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && method.operator String().contains("action")) {
30543097
// Get input actions
30553098
List<PropertyInfo> props;
30563099
ProjectSettings::get_singleton()->get_property_list(&props);
@@ -3061,14 +3104,21 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30613104
}
30623105
String name = s.get_slicec('/', 1).quote(quote_style);
30633106
if (use_string_names) {
3064-
name = "&" + name;
3107+
if (p_call->arguments.size() > p_argidx && p_call->arguments[p_argidx] && p_call->arguments[p_argidx]->type == GDScriptParser::Node::LITERAL) {
3108+
GDScriptParser::LiteralNode *literal = static_cast<GDScriptParser::LiteralNode *>(p_call->arguments[p_argidx]);
3109+
if (literal->value.get_type() == Variant::STRING) {
3110+
name = "&" + name;
3111+
}
3112+
} else {
3113+
name = "&" + name;
3114+
}
30653115
}
30663116
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
30673117
r_result.insert(option.display, option);
30683118
}
30693119
}
30703120
if (EDITOR_GET("text_editor/completion/complete_file_paths")) {
3071-
if (p_argidx == 0 && p_method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) {
3121+
if (p_argidx == 0 && method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) {
30723122
HashMap<String, ScriptLanguage::CodeCompletionOption> list;
30733123
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), list, SNAME("PackedScene"));
30743124
for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &key_value_pair : list) {
@@ -3092,7 +3142,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
30923142
List<MethodInfo> methods;
30933143
base.get_method_list(&methods);
30943144
for (const MethodInfo &E : methods) {
3095-
if (E.name == p_method) {
3145+
if (E.name == method) {
30963146
r_arghint = _make_arguments_hint(E, p_argidx);
30973147
return;
30983148
}
@@ -3290,7 +3340,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
32903340
GDScriptCompletionIdentifier ci;
32913341
ci.type = base_type;
32923342
ci.value = base;
3293-
_find_call_arguments(p_context, ci, call->function_name, p_argidx, _static, r_result, r_arghint);
3343+
_list_call_arguments(p_context, ci, call, p_argidx, _static, r_result, r_arghint);
32943344

32953345
r_forced = r_result.size() > 0;
32963346
}
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)