diff options
Diffstat (limited to 'modules/gdscript/gdscript_editor.cpp')
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 501 |
1 files changed, 314 insertions, 187 deletions
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index a9b641de50..9b3bf8ad5b 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,12 +33,9 @@ #include "core/engine.h" #include "core/global_constants.h" #include "core/os/file_access.h" -#include "editor/editor_settings.h" #include "gdscript_compiler.h" #ifdef TOOLS_ENABLED -#include "core/engine.h" -#include "core/reference.h" #include "editor/editor_file_system.h" #include "editor/editor_settings.h" #endif @@ -47,19 +44,44 @@ void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const p_delimiters->push_back("#"); } + void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("\" \""); p_delimiters->push_back("' '"); p_delimiters->push_back("\"\"\" \"\"\""); } -Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { + +String GDScriptLanguage::_get_processed_template(const String &p_template, const String &p_base_class_name) const { + + String processed_template = p_template; + #ifdef TOOLS_ENABLED - bool th = EDITOR_DEF("text_editor/completion/add_type_hints", false); + if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) { + processed_template = processed_template.replace("%INT_TYPE%", ": int"); + processed_template = processed_template.replace("%STRING_TYPE%", ": String"); + processed_template = processed_template.replace("%FLOAT_TYPE%", ": float"); + processed_template = processed_template.replace("%VOID_RETURN%", " -> void"); + } else { + processed_template = processed_template.replace("%INT_TYPE%", ""); + processed_template = processed_template.replace("%STRING_TYPE%", ""); + processed_template = processed_template.replace("%FLOAT_TYPE%", ""); + processed_template = processed_template.replace("%VOID_RETURN%", ""); + } #else - bool th = false; + processed_template = processed_template.replace("%INT_TYPE%", ""); + processed_template = processed_template.replace("%STRING_TYPE%", ""); + processed_template = processed_template.replace("%FLOAT_TYPE%", ""); + processed_template = processed_template.replace("%VOID_RETURN%", ""); #endif + processed_template = processed_template.replace("%BASE%", p_base_class_name); + processed_template = processed_template.replace("%TS%", _get_indentation()); + + return processed_template; +} + +Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { String _template = "extends %BASE%\n" "\n" "# Declare member variables here. Examples:\n" @@ -74,27 +96,7 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str "#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n" "#%TS%pass\n"; -#ifdef TOOLS_ENABLED - if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) { - _template = _template.replace("%INT_TYPE%", ": int"); - _template = _template.replace("%STRING_TYPE%", ": String"); - _template = _template.replace("%FLOAT_TYPE%", ": float"); - _template = _template.replace("%VOID_RETURN%", " -> void"); - } else { - _template = _template.replace("%INT_TYPE%", ""); - _template = _template.replace("%STRING_TYPE%", ""); - _template = _template.replace("%FLOAT_TYPE%", ""); - _template = _template.replace("%VOID_RETURN%", ""); - } -#else - _template = _template.replace("%INT_TYPE%", ""); - _template = _template.replace("%STRING_TYPE%", ""); - _template = _template.replace("%FLOAT_TYPE%", ""); - _template = _template.replace("%VOID_RETURN%", ""); -#endif - - _template = _template.replace("%BASE%", p_base_class_name); - _template = _template.replace("%TS%", _get_indentation()); + _template = _get_processed_template(_template, p_base_class_name); Ref<GDScript> script; script.instance(); @@ -110,10 +112,8 @@ bool GDScriptLanguage::is_using_templates() { void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { - String src = p_script->get_source_code(); - src = src.replace("%BASE%", p_base_class_name); - src = src.replace("%TS%", _get_indentation()); - p_script->set_source_code(src); + String _template = _get_processed_template(p_script->get_source_code(), p_base_class_name); + p_script->set_source_code(_template); } bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { @@ -159,7 +159,11 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & for (int i = 0; i < cl->subclasses.size(); i++) { for (int j = 0; j < cl->subclasses[i]->functions.size(); j++) { - funcs[cl->subclasses[i]->functions[j]->line] = String(cl->subclasses[i]->name) + "." + String(cl->subclasses[i]->functions[j]->name); + funcs[cl->subclasses[i]->functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->functions[j]->name; + } + for (int j = 0; j < cl->subclasses[i]->static_functions.size(); j++) { + + funcs[cl->subclasses[i]->static_functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->static_functions[j]->name; } } @@ -219,7 +223,7 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const _debug_parse_err_line = p_line; _debug_parse_err_file = p_file; _debug_error = p_error; - ScriptDebugger::get_singleton()->debug(this, false); + ScriptDebugger::get_singleton()->debug(this, false, true); return true; } else { return false; @@ -233,7 +237,8 @@ bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) _debug_parse_err_line = -1; _debug_parse_err_file = ""; _debug_error = p_error; - ScriptDebugger::get_singleton()->debug(this, p_allow_continue); + bool is_error_breakpoint = p_error != "Breakpoint"; + ScriptDebugger::get_singleton()->debug(this, p_allow_continue, is_error_breakpoint); return true; } else { return false; @@ -382,8 +387,6 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - if (_debug_parse_err_line >= 0) - return ""; return ""; } @@ -488,12 +491,15 @@ struct GDScriptCompletionContext { Object *base; String base_path; int line; + uint32_t depth; GDScriptCompletionContext() : _class(NULL), function(NULL), block(NULL), - base(NULL) {} + base(NULL), + line(0), + depth(0) {} }; struct GDScriptCompletionIdentifier { @@ -506,10 +512,14 @@ struct GDScriptCompletionIdentifier { assigned_expression(NULL) {} }; -static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) { +static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) { + + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; for (int i = 0; i < p_dir->get_file_count(); i++) { - r_list.insert("\"" + p_dir->get_file_path(i) + "\""); + ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH); + option.insert_text = quote_style + option.display + quote_style; + r_list.insert(option.display, option); } for (int i = 0; i < p_dir->get_subdir_count(); i++) { @@ -624,6 +634,9 @@ static GDScriptCompletionIdentifier _type_from_gdtype(const GDScriptDataType &p_ ci.type.script_type = p_gdtype.script_type; switch (p_gdtype.kind) { + case GDScriptDataType::UNINITIALIZED: { + ERR_PRINT("Uninitialized completion. Please report a bug."); + } break; case GDScriptDataType::BUILTIN: { ci.type.kind = GDScriptParser::DataType::BUILTIN; } break; @@ -640,12 +653,18 @@ static GDScriptCompletionIdentifier _type_from_gdtype(const GDScriptDataType &p_ return ci; } -static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); -static bool _guess_identifier_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); -static bool _guess_method_return_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); +static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); +static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); +static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); -static bool _guess_expression_type(const GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_expression, GDScriptCompletionIdentifier &r_type) { +static bool _guess_expression_type(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_expression, GDScriptCompletionIdentifier &r_type) { bool found = false; + + if (++p_context.depth > 100) { + print_error("Maximum _guess_expression_type depth limit reached. Please file a bugreport."); + return false; + } + switch (p_expression->type) { case GDScriptParser::Node::TYPE_CONSTANT: { const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(p_expression); @@ -782,12 +801,12 @@ static bool _guess_expression_type(const GDScriptCompletionContext &p_context, c if (mb && mb->is_const()) { bool all_is_const = true; Vector<Variant> args; - GDScriptCompletionContext c = p_context; - c.line = op->line; + GDScriptCompletionContext c2 = p_context; + c2.line = op->line; for (int i = 2; all_is_const && i < op->arguments.size(); i++) { GDScriptCompletionIdentifier arg; - if (_guess_expression_type(c, op->arguments[i], arg)) { + if (_guess_expression_type(c2, op->arguments[i], arg)) { if (arg.type.has_type && arg.type.is_constant && arg.value.get_type() != Variant::OBJECT) { args.push_back(arg.value); } else { @@ -1058,7 +1077,8 @@ static bool _guess_expression_type(const GDScriptCompletionContext &p_context, c case GDScriptParser::OperatorNode::OP_BIT_AND: vop = Variant::OP_BIT_AND; break; case GDScriptParser::OperatorNode::OP_BIT_OR: vop = Variant::OP_BIT_OR; break; case GDScriptParser::OperatorNode::OP_BIT_XOR: vop = Variant::OP_BIT_XOR; break; - default: {} + default: { + } } if (vop == Variant::OP_MAX) { @@ -1113,6 +1133,8 @@ static bool _guess_expression_type(const GDScriptCompletionContext &p_context, c } break; } } break; + default: { + } } // It may have found a null, but that's never useful @@ -1133,7 +1155,7 @@ static bool _guess_expression_type(const GDScriptCompletionContext &p_context, c return found; } -static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { +static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { // Look in blocks first const GDScriptParser::BlockNode *blk = p_context.block; @@ -1189,7 +1211,11 @@ static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, c c.line = op->line; c.block = blk; if (_guess_expression_type(p_context, op->arguments[1], r_type)) { - r_type.type.is_meta_type = false; + r_type.type.is_meta_type = false; // Right-hand of `is` will be a meta type, but the left-hand value is not + // Not an assignment, it shouldn't carry any value + r_type.value = Variant(); + r_type.assigned_expression = NULL; + return true; } } @@ -1274,9 +1300,9 @@ static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, c for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { if (E->get().name == p_context.function->name) { MethodInfo &mi = E->get(); - for (List<PropertyInfo>::Element *E = mi.arguments.front(); E; E = E->next()) { - if (E->get().name == p_identifier) { - r_type = _type_from_property(E->get()); + for (List<PropertyInfo>::Element *F = mi.arguments.front(); F; F = F->next()) { + if (F->get().name == p_identifier) { + r_type = _type_from_property(F->get()); return true; } } @@ -1316,37 +1342,38 @@ static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, c return false; } - // Check ClassDB - if (ClassDB::class_exists(p_identifier)) { - r_type.type.has_type = true; - r_type.type.kind = GDScriptParser::DataType::NATIVE; - r_type.type.native_type = p_identifier; - if (Engine::get_singleton()->has_singleton(p_identifier)) { - r_type.type.is_meta_type = false; - r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier); - } else { - r_type.type.is_meta_type = true; - int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier]; - r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx]; + for (int i = 0; i < 2; i++) { + StringName target_id; + switch (i) { + case 0: + // Check ClassDB + target_id = p_identifier; + break; + case 1: + // ClassDB again for underscore-prefixed classes + target_id = String("_") + p_identifier; + break; } - return true; - } - // ClassDB again for underscore-prefixed classes - StringName under_id = String("_") + p_identifier; - if (ClassDB::class_exists(under_id)) { - r_type.type.has_type = true; - r_type.type.kind = GDScriptParser::DataType::NATIVE; - r_type.type.native_type = p_identifier; - if (Engine::get_singleton()->has_singleton(p_identifier)) { - r_type.type.is_meta_type = false; - r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier); - } else { - r_type.type.is_meta_type = true; - int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier]; - r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx]; + if (ClassDB::class_exists(target_id)) { + r_type.type.has_type = true; + r_type.type.kind = GDScriptParser::DataType::NATIVE; + r_type.type.native_type = target_id; + if (Engine::get_singleton()->has_singleton(target_id)) { + r_type.type.is_meta_type = false; + r_type.value = Engine::get_singleton()->get_singleton_object(target_id); + } else { + r_type.type.is_meta_type = true; + const Map<StringName, int>::Element *target_elem = GDScriptLanguage::get_singleton()->get_global_map().find(target_id); + // Check because classes like EditorNode are in ClassDB by now, but unknown to GDScript + if (!target_elem) { + return false; + } + int idx = target_elem->get(); + r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx]; + } + return true; } - return true; } // Check autoload singletons @@ -1358,7 +1385,7 @@ static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, c return false; } -static bool _guess_identifier_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { +static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; while (base_type.has_type) { @@ -1547,7 +1574,7 @@ static bool _find_last_return_in_block(const GDScriptCompletionContext &p_contex return false; } -static bool _guess_method_return_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) { +static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) { GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; @@ -1785,14 +1812,15 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio return arghint; } -static void _find_enumeration_candidates(const String p_enum_hint, Set<String> &r_result) { +static void _find_enumeration_candidates(const String p_enum_hint, Map<String, ScriptCodeCompletionOption> &r_result) { if (p_enum_hint.find(".") == -1) { // Global constant StringName current_enum = p_enum_hint; for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { if (GlobalConstants::get_global_constant_enum(i) == current_enum) { - r_result.insert(GlobalConstants::get_global_constant_name(i)); + ScriptCodeCompletionOption option(GlobalConstants::get_global_constant_name(i), ScriptCodeCompletionOption::KIND_ENUM); + r_result.insert(option.display, option); } } } else { @@ -1807,15 +1835,17 @@ static void _find_enumeration_candidates(const String p_enum_hint, Set<String> & ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { String candidate = class_name + "." + E->get(); - r_result.insert(candidate); + ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM); + r_result.insert(option.display, option); } } } -static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Set<String> &r_result) { +static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) { for (Map<StringName, GDScriptParser::LocalVarNode *>::Element *E = p_context.block->variables.front(); E; E = E->next()) { if (E->get()->line < p_context.line) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_VARIABLE); + r_result.insert(option.display, option); } } if (p_context.block->parent_block) { @@ -1825,40 +1855,47 @@ static void _find_identifiers_in_block(const GDScriptCompletionContext &p_contex } } -static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result); +static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result); -static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Set<String> &r_result) { +static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result) { if (!p_parent_only) { if (!p_static && !p_only_functions) { for (int i = 0; i < p_context._class->variables.size(); i++) { - r_result.insert(p_context._class->variables[i].identifier); + ScriptCodeCompletionOption option(p_context._class->variables[i].identifier, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } if (!p_only_functions) { for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_context._class->constant_expressions.front(); E; E = E->next()) { - r_result.insert(E->key()); + ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } for (int i = 0; i < p_context._class->subclasses.size(); i++) { - r_result.insert(p_context._class->subclasses[i]->name); + ScriptCodeCompletionOption option(p_context._class->subclasses[i]->name, ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } } for (int i = 0; i < p_context._class->static_functions.size(); i++) { + ScriptCodeCompletionOption option(p_context._class->static_functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION); if (p_context._class->static_functions[i]->arguments.size()) { - r_result.insert(p_context._class->static_functions[i]->name.operator String() + "("); + option.insert_text += "("; } else { - r_result.insert(p_context._class->static_functions[i]->name.operator String() + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } if (!p_static) { for (int i = 0; i < p_context._class->functions.size(); i++) { + ScriptCodeCompletionOption option(p_context._class->functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION); if (p_context._class->functions[i]->arguments.size()) { - r_result.insert(p_context._class->functions[i]->name.operator String() + "("); + option.insert_text += "("; } else { - r_result.insert(p_context._class->functions[i]->name.operator String() + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } } } @@ -1876,12 +1913,14 @@ static void _find_identifiers_in_class(const GDScriptCompletionContext &p_contex _find_identifiers_in_base(c, base_type, p_only_functions, r_result); } -static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result) { +static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) { GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) { - r_result.insert("new("); + ScriptCodeCompletionOption option("new", ScriptCodeCompletionOption::KIND_FUNCTION); + option.insert_text += "("; + r_result.insert(option.display, option); } while (base_type.has_type) { @@ -1898,27 +1937,41 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context Ref<GDScript> script = base_type.script_type; if (script.is_valid()) { if (!_static && !p_only_functions) { - for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) { - r_result.insert(E->get().operator String()); + if (p_context.base && p_context.base->get_script_instance()) { + List<PropertyInfo> members; + p_context.base->get_script_instance()->get_property_list(&members); + for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); + } + } else { + for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) { + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); + } } } if (!p_only_functions) { for (const Map<StringName, Variant>::Element *E = script->get_constants().front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } } for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) { if (!_static || E->get()->is_static()) { + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get()->get_argument_count()) { - r_result.insert(E->key().operator String() + "("); + option.insert_text += "("; } else { - r_result.insert(E->key().operator String() + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } } if (!p_only_functions) { for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } } base_type = GDScriptParser::DataType(); @@ -1929,7 +1982,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context } else { base_type.has_type = script->get_instance_base_type() != StringName(); base_type.kind = GDScriptParser::DataType::NATIVE; - base_type.script_type = script->get_instance_base_type(); + base_type.native_type = script->get_instance_base_type(); } } else { return; @@ -1942,25 +1995,29 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context List<PropertyInfo> members; scr->get_script_property_list(&members); for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - r_result.insert(E->get().name); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } if (!p_only_functions) { Map<StringName, Variant> constants; scr->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } } List<MethodInfo> methods; scr->get_script_method_list(&methods); for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get().arguments.size()) { - r_result.insert(E->get().name + "("); + option.insert_text += "("; } else { - r_result.insert(E->get().name + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } Ref<Script> base_script = scr->get_base_script(); @@ -1987,7 +2044,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context List<String> constants; ClassDB::get_integer_constant_list(type, &constants); for (List<String>::Element *E = constants.front(); E; E = E->next()) { - r_result.insert(E->get()); + ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } if (!_static) { @@ -2000,23 +2058,27 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context if (E->get().name.find("/") != -1) { continue; } - r_result.insert(E->get().name); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } } if (!_static) { List<MethodInfo> methods; - ClassDB::get_method_list(type, &methods, false, true); + bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize(); + ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters); for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { if (E->get().name.begins_with("_")) { continue; } + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get().arguments.size()) { - r_result.insert(E->get().name + "("); + option.insert_text += "("; } else { - r_result.insert(E->get().name + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } } @@ -2031,11 +2093,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context if (!p_only_functions) { List<PropertyInfo> members; - tmp.get_property_list(&members); + p_base.value.get_property_list(&members); for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { if (String(E->get().name).find("/") == -1) { - r_result.insert(E->get().name); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } } @@ -2043,11 +2106,13 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context List<MethodInfo> methods; tmp.get_method_list(&methods); for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get().arguments.size()) { - r_result.insert(E->get().name + "("); + option.insert_text += "("; } else { - r_result.insert(E->get().name + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } return; @@ -2059,7 +2124,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context } } -static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Set<String> &r_result) { +static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) { const GDScriptParser::BlockNode *block = p_context.block; @@ -2068,7 +2133,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p const GDScriptParser::FunctionNode *f = p_context.function; for (int i = 0; i < f->arguments.size(); i++) { - r_result.insert(f->arguments[i].operator String()); + ScriptCodeCompletionOption option(f->arguments[i].operator String(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_result.insert(option.display, option); } } @@ -2093,11 +2159,13 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { MethodInfo mi = GDScriptFunctions::get_info(GDScriptFunctions::Function(i)); + ScriptCodeCompletionOption option(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))), ScriptCodeCompletionOption::KIND_FUNCTION); if (mi.arguments.size() || (mi.flags & METHOD_FLAG_VARARG)) { - r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "("); + option.insert_text += "("; } else { - r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } static const char *_type_names[Variant::VARIANT_MAX] = { @@ -2107,7 +2175,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p }; for (int i = 0; i < Variant::VARIANT_MAX; i++) { - r_result.insert(_type_names[i]); + ScriptCodeCompletionOption option(_type_names[i], ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } static const char *_keywords[] = { @@ -2121,7 +2190,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p const char **kw = _keywords; while (*kw) { - r_result.insert(*kw); + ScriptCodeCompletionOption option(*kw, ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_result.insert(option.display, option); kw++; } @@ -2135,7 +2205,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p } String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { - r_result.insert(s.get_slice("/", 1)); + ScriptCodeCompletionOption option(s.get_slice("/", 1), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } } @@ -2143,19 +2214,22 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p List<StringName> named_scripts; ScriptServer::get_global_class_list(&named_scripts); for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { - r_result.insert(E->get().operator String()); + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } // Native classes for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } } -static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Set<String> &r_result, String &r_arghint) { +static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptCodeCompletionOption> &r_result, String &r_arghint) { Variant base = p_base.value; GDScriptParser::DataType base_type = p_base.type; - bool _static = false; + + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; while (base_type.has_type) { switch (base_type.kind) { @@ -2166,18 +2240,18 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con return; } } - if (!_static) { - for (int i = 0; i < base_type.class_type->functions.size(); i++) { - if (base_type.class_type->functions[i]->name == p_method) { - r_arghint = _make_arguments_hint(base_type.class_type->functions[i], p_argidx); - return; - } + for (int i = 0; i < base_type.class_type->functions.size(); i++) { + if (base_type.class_type->functions[i]->name == p_method) { + r_arghint = _make_arguments_hint(base_type.class_type->functions[i], p_argidx); + return; } } if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { for (int i = 0; i < base_type.class_type->_signals.size(); i++) { - r_result.insert("\"" + base_type.class_type->_signals[i].name.operator String() + "\""); + ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2190,7 +2264,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con List<MethodInfo> signals; gds->get_script_signal_list(&signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - r_result.insert("\"" + E->get().name + "\""); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } Ref<GDScript> base_script = gds->get_base_script(); @@ -2227,8 +2303,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con if (obj) { List<String> options; obj->get_argument_options(p_method, p_argidx, &options); - for (List<String>::Element *E = options.front(); E; E = E->next()) { - r_result.insert(E->get()); + for (List<String>::Element *F = options.front(); F; F = F->next()) { + ScriptCodeCompletionOption option(F->get(), ScriptCodeCompletionOption::KIND_FUNCTION); + r_result.insert(option.display, option); } } } @@ -2249,7 +2326,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con List<MethodInfo> signals; ClassDB::get_signal_list(class_name, &signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - r_result.insert("\"" + E->get().name + "\""); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2264,7 +2343,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con continue; } String name = s.get_slice("/", 1); - r_result.insert("\"/root/" + name + "\""); + ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2278,7 +2359,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con continue; } String name = s.get_slice("/", 1); - r_result.insert("\"" + name + "\""); + ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2311,7 +2394,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con } } -static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Set<String> &r_result, bool &r_forced, String &r_arghint) { +static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) { + + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; if (!p_node || p_node->type != GDScriptParser::Node::TYPE_OPERATOR) { return; @@ -2427,30 +2512,38 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con _find_call_arguments(p_context, ci, function, p_argidx, _static, r_result, r_arghint); if (function == "connect" && p_argidx == 2) { - Set<String> methods; + Map<String, ScriptCodeCompletionOption> methods; _find_identifiers_in_base(p_context, connect_base, true, methods); - for (Set<String>::Element *E = methods.front(); E; E = E->next()) { - r_result.insert("\"" + E->get().replace("(", "").replace(")", "") + "\""); + for (Map<String, ScriptCodeCompletionOption>::Element *E = methods.front(); E; E = E->next()) { + ScriptCodeCompletionOption &option = E->value(); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } r_forced = r_result.size() > 0; } -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) { +Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { + + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; GDScriptParser parser; - parser.parse(p_code, p_base_path, false, "", true); + parser.parse(p_code, p_path.get_base_dir(), false, p_path, true); r_forced = false; - Set<String> options; + Map<String, ScriptCodeCompletionOption> options; GDScriptCompletionContext context; context._class = parser.get_completion_class(); context.block = parser.get_completion_block(); context.function = parser.get_completion_function(); - context.base = p_owner; - context.base_path = p_base_path; context.line = parser.get_completion_line(); + + if (!context._class || context._class->owner == NULL) { + context.base = p_owner; + context.base_path = p_path.get_base_dir(); + } + bool is_function = false; switch (parser.get_completion_type()) { @@ -2460,7 +2553,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base List<StringName> constants; Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants); for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { - options.insert(E->get().operator String()); + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + options.insert(option.display, option); } } break; case GDScriptParser::COMPLETION_PARENT_FUNCTION: { @@ -2468,7 +2562,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } break; case GDScriptParser::COMPLETION_FUNCTION: { is_function = true; - } // fallthrough + FALLTHROUGH; + } case GDScriptParser::COMPLETION_IDENTIFIER: { _find_identifiers(context, is_function, options); } break; @@ -2484,9 +2579,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base r_forced = true; String idopt = opt.unquote(); if (idopt.replace("/", "_").is_valid_identifier()) { - options.insert(idopt); + ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } else { - options.insert(opt); + ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } } } @@ -2501,13 +2598,15 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base continue; } String name = s.get_slice("/", 1); - options.insert("\"/root/" + name + "\""); + ScriptCodeCompletionOption option(quote_style + "/root/" + name + quote_style, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } } } break; case GDScriptParser::COMPLETION_METHOD: { is_function = true; - } // fallthrough + FALLTHROUGH; + } case GDScriptParser::COMPLETION_INDEX: { const GDScriptParser::Node *node = parser.get_completion_node(); if (node->type != GDScriptParser::Node::TYPE_OPERATOR) { @@ -2623,7 +2722,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } method_hint += ":"; - options.insert(method_hint); + ScriptCodeCompletionOption option(method_hint, ScriptCodeCompletionOption::KIND_FUNCTION); + options.insert(option.display, option); } } break; case GDScriptParser::COMPLETION_YIELD: { @@ -2641,7 +2741,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base switch (base_type.kind) { case GDScriptParser::DataType::CLASS: { for (int i = 0; i < base_type.class_type->_signals.size(); i++) { - options.insert("\"" + base_type.class_type->_signals[i].name.operator String() + "\""); + ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + options.insert(option.display, option); } base_type = base_type.class_type->base_type; } break; @@ -2652,7 +2754,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base List<MethodInfo> signals; scr->get_script_signal_list(&signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - options.insert("\"" + E->get().name + "\""); + ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL); + options.insert(option.display, option); } Ref<Script> base_script = scr->get_base_script(); if (base_script.is_valid()) { @@ -2679,7 +2782,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base List<MethodInfo> signals; ClassDB::get_signal_list(class_name, &signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - options.insert("\"" + E->get().name + "\""); + ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL); + options.insert(option.display, option); } } break; default: { @@ -2716,18 +2820,31 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base c.line = E->value().expression->line; if (_guess_expression_type(c, E->value().expression, constant)) { if (constant.type.has_type && constant.type.is_meta_type) { - options.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } } for (int i = 0; i < clss->subclasses.size(); i++) { if (clss->subclasses[i]->name != StringName()) { - options.insert(clss->subclasses[i]->name.operator String()); + ScriptCodeCompletionOption option(clss->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } clss = clss->owner; for (int i = 0; i < Variant::VARIANT_MAX; i++) { - options.insert(Variant::get_type_name((Variant::Type)i)); + ScriptCodeCompletionOption option(Variant::get_type_name((Variant::Type)i), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); + } + List<PropertyInfo> props; + ProjectSettings::get_singleton()->get_property_list(&props); + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + String s = E->get().name; + if (!s.begins_with("autoload/")) { + continue; + } + ScriptCodeCompletionOption option(s.get_slice("/", 1), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } @@ -2741,18 +2858,21 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base if (Engine::get_singleton()->has_singleton(class_name)) { continue; } - options.insert(class_name); + ScriptCodeCompletionOption option(class_name, ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } // Named scripts List<StringName> named_scripts; ScriptServer::get_global_class_list(&named_scripts); for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { - options.insert(E->get().operator String()); + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } if (parser.get_completion_identifier_is_function()) { - options.insert("void"); + ScriptCodeCompletionOption option("void", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + options.insert(option.display, option); } r_forced = true; } break; @@ -2792,20 +2912,22 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base if (base_type.class_type) { for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = base_type.class_type->constant_expressions.front(); E; E = E->next()) { GDScriptCompletionIdentifier constant; - GDScriptCompletionContext c = context; - c._class = base_type.class_type; - c.function = NULL; - c.block = NULL; - c.line = E->value().expression->line; - if (_guess_expression_type(c, E->value().expression, constant)) { + GDScriptCompletionContext c2 = context; + c2._class = base_type.class_type; + c2.function = NULL; + c2.block = NULL; + c2.line = E->value().expression->line; + if (_guess_expression_type(c2, E->value().expression, constant)) { if (constant.type.has_type && constant.type.is_meta_type) { - options.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } } for (int i = 0; i < base_type.class_type->subclasses.size(); i++) { if (base_type.class_type->subclasses[i]->name != StringName()) { - options.insert(base_type.class_type->subclasses[i]->name.operator String()); + ScriptCodeCompletionOption option(base_type.class_type->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } @@ -2823,7 +2945,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { Ref<Script> const_scr = E->value(); if (const_scr.is_valid()) { - options.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } Ref<Script> base_script = scr->get_base_script(); @@ -2845,7 +2968,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } break; } - for (Set<String>::Element *E = options.front(); E; E = E->next()) { + for (Map<String, ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) { r_options->push_back(E->get()); } @@ -2854,7 +2977,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base #else -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) { +Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { return OK; } @@ -2865,7 +2988,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base String GDScriptLanguage::_get_indentation() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0); + bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", false); if (use_space_indentation) { int indent_size = EDITOR_DEF("text_editor/indent/size", 4); @@ -2983,8 +3106,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } } } + base_type = base_type.class_type->base_type; } - base_type = base_type.class_type->base_type; } break; case GDScriptParser::DataType::SCRIPT: case GDScriptParser::DataType::GDSCRIPT: { @@ -3125,7 +3248,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co return ERR_CANT_RESOLVE; } -Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result) { +Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { //before parsing, try the usual stuff if (ClassDB::class_exists(p_symbol)) { @@ -3167,7 +3290,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol } GDScriptParser parser; - parser.parse(p_code, p_base_path, false, "", true); + parser.parse(p_code, p_path.get_base_dir(), false, p_path, true); if (parser.get_completion_type() == GDScriptParser::COMPLETION_NONE) { return ERR_CANT_RESOLVE; @@ -3179,7 +3302,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol context.block = parser.get_completion_block(); context.line = parser.get_completion_line(); context.base = p_owner; - context.base_path = p_base_path; + context.base_path = p_path.get_base_dir(); if (context._class && context._class->extends_class.size() > 0) { bool success = false; @@ -3204,7 +3327,8 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol case GDScriptParser::COMPLETION_PARENT_FUNCTION: case GDScriptParser::COMPLETION_FUNCTION: { is_function = true; - } // fallthrough + FALLTHROUGH; + } case GDScriptParser::COMPLETION_IDENTIFIER: { if (!is_function) { @@ -3335,7 +3459,8 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol } break; case GDScriptParser::COMPLETION_METHOD: { is_function = true; - } // fallthrough + FALLTHROUGH; + } case GDScriptParser::COMPLETION_INDEX: { const GDScriptParser::Node *node = parser.get_completion_node(); if (node->type != GDScriptParser::Node::TYPE_OPERATOR) { @@ -3357,6 +3482,8 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol return OK; } } break; + default: { + } } return ERR_CANT_RESOLVE; |