Parse more informations for code completion

This commit is contained in:
Geequlim 2019-06-13 17:17:20 +08:00
parent 2293c612e6
commit ed7ed52151
9 changed files with 194 additions and 93 deletions

View File

@ -200,6 +200,34 @@ public:
virtual ~ScriptInstance(); virtual ~ScriptInstance();
}; };
struct ScriptCodeCompletionOption {
enum Kind {
KIND_CLASS,
KIND_FUNCTION,
KIND_SIGNAL,
KIND_VARIABLE,
KIND_MEMBER,
KIND_ENUM,
KIND_CONSTANT,
KIND_NODE_PATH,
KIND_FILE_PATH,
KIND_PLAIN_TEXT,
};
Kind kind;
String display;
String insert_text;
ScriptCodeCompletionOption() {
kind = KIND_PLAIN_TEXT;
}
ScriptCodeCompletionOption(const String &p_text, Kind p_kind) {
display = p_text;
insert_text = p_text;
kind = p_kind;
}
};
class ScriptCodeCompletionCache { class ScriptCodeCompletionCache {
static ScriptCodeCompletionCache *singleton; static ScriptCodeCompletionCache *singleton;
@ -250,7 +278,7 @@ public:
virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; }
virtual bool overrides_external_editor() { return false; } virtual bool overrides_external_editor() { return false; }
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; } virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
struct LookupResult { struct LookupResult {
enum Type { enum Type {

View File

@ -724,7 +724,7 @@ void CodeTextEditor::_code_complete_timer_timeout() {
void CodeTextEditor::_complete_request() { void CodeTextEditor::_complete_request() {
List<String> entries; List<ScriptCodeCompletionOption> entries;
String ctext = text_editor->get_text_for_completion(); String ctext = text_editor->get_text_for_completion();
_code_complete_script(ctext, &entries); _code_complete_script(ctext, &entries);
bool forced = false; bool forced = false;
@ -733,15 +733,16 @@ void CodeTextEditor::_complete_request() {
} }
if (entries.size() == 0) if (entries.size() == 0)
return; return;
Vector<String> strs;
strs.resize(entries.size());
int i = 0;
for (List<String>::Element *E = entries.front(); E; E = E->next()) {
strs.write[i++] = E->get(); Vector<String> options;
options.resize(entries.size());
size_t i = 0;
for (List<ScriptCodeCompletionOption>::Element *E = entries.front(); E; E = E->next()) {
options.write[i] = E->get().insert_text;
i++;
} }
text_editor->code_complete(strs, forced); text_editor->code_complete(options, forced);
} }
void CodeTextEditor::_font_resize_timeout() { void CodeTextEditor::_font_resize_timeout() {

View File

@ -131,7 +131,7 @@ public:
FindReplaceBar(); FindReplaceBar();
}; };
typedef void (*CodeTextEditorCodeCompleteFunc)(void *p_ud, const String &p_code, List<String> *r_options, bool &r_forced); typedef void (*CodeTextEditorCodeCompleteFunc)(void *p_ud, const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_forced);
class CodeTextEditor : public VBoxContainer { class CodeTextEditor : public VBoxContainer {
@ -183,7 +183,7 @@ class CodeTextEditor : public VBoxContainer {
protected: protected:
virtual void _load_theme_settings() {} virtual void _load_theme_settings() {}
virtual void _validate_script() {} virtual void _validate_script() {}
virtual void _code_complete_script(const String &p_code, List<String> *r_options) {} virtual void _code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options) {}
void _text_changed_idle_timeout(); void _text_changed_idle_timeout();
void _code_complete_timer_timeout(); void _code_complete_timer_timeout();

View File

@ -773,13 +773,13 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo
} }
} }
void ScriptTextEditor::_code_complete_scripts(void *p_ud, const String &p_code, List<String> *r_options, bool &r_force) { void ScriptTextEditor::_code_complete_scripts(void *p_ud, const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force) {
ScriptTextEditor *ste = (ScriptTextEditor *)p_ud; ScriptTextEditor *ste = (ScriptTextEditor *)p_ud;
ste->_code_complete_script(p_code, r_options, r_force); ste->_code_complete_script(p_code, r_options, r_force);
} }
void ScriptTextEditor::_code_complete_script(const String &p_code, List<String> *r_options, bool &r_force) { void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force) {
if (color_panel->is_visible_in_tree()) return; if (color_panel->is_visible_in_tree()) return;
Node *base = get_tree()->get_edited_scene_root(); Node *base = get_tree()->get_edited_scene_root();

View File

@ -143,7 +143,6 @@ class ScriptTextEditor : public ScriptEditorBase {
}; };
protected: protected:
static void _code_complete_scripts(void *p_ud, const String &p_code, List<String> *r_options, bool &r_force);
void _update_breakpoint_list(); void _update_breakpoint_list();
void _breakpoint_item_pressed(int p_idx); void _breakpoint_item_pressed(int p_idx);
void _breakpoint_toggled(int p_row); void _breakpoint_toggled(int p_row);
@ -151,7 +150,10 @@ protected:
void _validate_script(); // No longer virtual. void _validate_script(); // No longer virtual.
void _update_bookmark_list(); void _update_bookmark_list();
void _bookmark_item_pressed(int p_idx); void _bookmark_item_pressed(int p_idx);
void _code_complete_script(const String &p_code, List<String> *r_options, bool &r_force);
static void _code_complete_scripts(void *p_ud, const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force);
void _code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force);
void _load_theme_settings(); void _load_theme_settings();
void _set_theme_for_script(); void _set_theme_for_script();
void _show_warnings_panel(bool p_show); void _show_warnings_panel(bool p_show);

View File

@ -159,7 +159,7 @@ String PluginScriptLanguage::make_function(const String &p_class, const String &
return String(); return String();
} }
Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint) { Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) {
if (_desc.complete_code) { if (_desc.complete_code) {
Array options; Array options;
godot_error tmp = _desc.complete_code( godot_error tmp = _desc.complete_code(
@ -171,7 +171,8 @@ Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_
&r_force, &r_force,
(godot_string *)&r_call_hint); (godot_string *)&r_call_hint);
for (int i = 0; i < options.size(); i++) { for (int i = 0; i < options.size(); i++) {
r_options->push_back(String(options[i])); ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
r_options->push_back(option);
} }
return (Error)tmp; return (Error)tmp;
} }

View File

@ -81,7 +81,7 @@ public:
virtual bool can_inherit_from_file() { return true; } virtual bool can_inherit_from_file() { return true; }
virtual int find_function(const String &p_function, const String &p_code) const; virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint); virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint);
virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); virtual void add_global_constant(const StringName &p_variable, const Variant &p_value);

View File

@ -458,7 +458,7 @@ public:
virtual bool can_inherit_from_file() { return true; } virtual bool can_inherit_from_file() { return true; }
virtual int find_function(const String &p_function, const String &p_code) const; virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint); virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint);
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result); virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result);
#endif #endif

View File

@ -509,12 +509,14 @@ struct GDScriptCompletionIdentifier {
assigned_expression(NULL) {} 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) ? "'" : "\""; const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
for (int i = 0; i < p_dir->get_file_count(); i++) { for (int i = 0; i < p_dir->get_file_count(); i++) {
r_list.insert(quote_style + p_dir->get_file_path(i) + quote_style); 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++) { for (int i = 0; i < p_dir->get_subdir_count(); i++) {
@ -1807,14 +1809,15 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
return arghint; 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) { if (p_enum_hint.find(".") == -1) {
// Global constant // Global constant
StringName current_enum = p_enum_hint; StringName current_enum = p_enum_hint;
for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
if (GlobalConstants::get_global_constant_enum(i) == current_enum) { 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 { } else {
@ -1829,15 +1832,17 @@ static void _find_enumeration_candidates(const String p_enum_hint, Set<String> &
ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); ClassDB::get_enum_constants(class_name, enum_name, &enum_constants);
for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) {
String candidate = class_name + "." + E->get(); 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()) { for (Map<StringName, GDScriptParser::LocalVarNode *>::Element *E = p_context.block->variables.front(); E; E = E->next()) {
if (E->get()->line < p_context.line) { 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) { if (p_context.block->parent_block) {
@ -1847,40 +1852,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_parent_only) {
if (!p_static && !p_only_functions) { if (!p_static && !p_only_functions) {
for (int i = 0; i < p_context._class->variables.size(); i++) { 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) { if (!p_only_functions) {
for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_context._class->constant_expressions.front(); E; E = E->next()) { 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++) { 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++) { 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()) { 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 { } 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) { if (!p_static) {
for (int i = 0; i < p_context._class->functions.size(); i++) { 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()) { if (p_context._class->functions[i]->arguments.size()) {
r_result.insert(p_context._class->functions[i]->name.operator String() + "("); option.insert_text += "(";
} else { } else {
r_result.insert(p_context._class->functions[i]->name.operator String() + "()"); option.insert_text += "()";
} }
r_result.insert(option.display, option);
} }
} }
} }
@ -1898,12 +1910,14 @@ static void _find_identifiers_in_class(const GDScriptCompletionContext &p_contex
_find_identifiers_in_base(c, base_type, p_only_functions, r_result); _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; GDScriptParser::DataType base_type = p_base.type;
bool _static = base_type.is_meta_type; bool _static = base_type.is_meta_type;
if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) { 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) { while (base_type.has_type) {
@ -1921,26 +1935,31 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (script.is_valid()) { if (script.is_valid()) {
if (!_static && !p_only_functions) { if (!_static && !p_only_functions) {
for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) { for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) {
r_result.insert(E->get().operator String()); ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_MEMBER);
r_result.insert(option.display, option);
} }
} }
if (!p_only_functions) { if (!p_only_functions) {
for (const Map<StringName, Variant>::Element *E = script->get_constants().front(); E; E = E->next()) { 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()) { for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) {
if (!_static || E->get()->is_static()) { if (!_static || E->get()->is_static()) {
ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get()->get_argument_count()) { if (E->get()->get_argument_count()) {
r_result.insert(E->key().operator String() + "("); option.insert_text += "(";
} else { } else {
r_result.insert(E->key().operator String() + "()"); option.insert_text += "()";
} }
r_result.insert(option.display, option);
} }
} }
if (!p_only_functions) { if (!p_only_functions) {
for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) { 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(); base_type = GDScriptParser::DataType();
@ -1964,25 +1983,29 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
List<PropertyInfo> members; List<PropertyInfo> members;
scr->get_script_property_list(&members); scr->get_script_property_list(&members);
for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { 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) { if (!p_only_functions) {
Map<StringName, Variant> constants; Map<StringName, Variant> constants;
scr->get_constants(&constants); scr->get_constants(&constants);
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { 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; List<MethodInfo> methods;
scr->get_script_method_list(&methods); scr->get_script_method_list(&methods);
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get().arguments.size()) { if (E->get().arguments.size()) {
r_result.insert(E->get().name + "("); option.insert_text += "(";
} else { } else {
r_result.insert(E->get().name + "()"); option.insert_text += "()";
} }
r_result.insert(option.display, option);
} }
Ref<Script> base_script = scr->get_base_script(); Ref<Script> base_script = scr->get_base_script();
@ -2009,7 +2032,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
List<String> constants; List<String> constants;
ClassDB::get_integer_constant_list(type, &constants); ClassDB::get_integer_constant_list(type, &constants);
for (List<String>::Element *E = constants.front(); E; E = E->next()) { 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) { if (!_static) {
@ -2022,7 +2046,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (E->get().name.find("/") != -1) { if (E->get().name.find("/") != -1) {
continue; continue;
} }
r_result.insert(E->get().name); ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
r_result.insert(option.display, option);
} }
} }
} }
@ -2035,11 +2060,13 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (E->get().name.begins_with("_")) { if (E->get().name.begins_with("_")) {
continue; continue;
} }
ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get().arguments.size()) { if (E->get().arguments.size()) {
r_result.insert(E->get().name + "("); option.insert_text += "(";
} else { } else {
r_result.insert(E->get().name + "()"); option.insert_text += "()";
} }
r_result.insert(option.display, option);
} }
} }
@ -2058,7 +2085,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
if (String(E->get().name).find("/") == -1) { 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);
} }
} }
} }
@ -2066,11 +2094,13 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
List<MethodInfo> methods; List<MethodInfo> methods;
tmp.get_method_list(&methods); tmp.get_method_list(&methods);
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
if (E->get().arguments.size()) { if (E->get().arguments.size()) {
r_result.insert(E->get().name + "("); option.insert_text += "(";
} else { } else {
r_result.insert(E->get().name + "()"); option.insert_text += "()";
} }
r_result.insert(option.display, option);
} }
return; return;
@ -2082,7 +2112,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; const GDScriptParser::BlockNode *block = p_context.block;
@ -2091,7 +2121,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
const GDScriptParser::FunctionNode *f = p_context.function; const GDScriptParser::FunctionNode *f = p_context.function;
for (int i = 0; i < f->arguments.size(); i++) { 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);
} }
} }
@ -2116,11 +2147,13 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
MethodInfo mi = GDScriptFunctions::get_info(GDScriptFunctions::Function(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)) { if (mi.arguments.size() || (mi.flags & METHOD_FLAG_VARARG)) {
r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "("); option.insert_text += "(";
} else { } 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] = { static const char *_type_names[Variant::VARIANT_MAX] = {
@ -2130,7 +2163,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
}; };
for (int i = 0; i < Variant::VARIANT_MAX; i++) { 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[] = { static const char *_keywords[] = {
@ -2144,7 +2178,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
const char **kw = _keywords; const char **kw = _keywords;
while (*kw) { while (*kw) {
r_result.insert(*kw); ScriptCodeCompletionOption option(*kw, ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
r_result.insert(option.display, option);
kw++; kw++;
} }
@ -2158,7 +2193,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
} }
String path = ProjectSettings::get_singleton()->get(s); String path = ProjectSettings::get_singleton()->get(s);
if (path.begins_with("*")) { 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);
} }
} }
@ -2166,16 +2202,18 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
List<StringName> named_scripts; List<StringName> named_scripts;
ScriptServer::get_global_class_list(&named_scripts); ScriptServer::get_global_class_list(&named_scripts);
for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { 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 // Native classes
for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) { 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; Variant base = p_base.value;
GDScriptParser::DataType base_type = p_base.type; GDScriptParser::DataType base_type = p_base.type;
@ -2199,7 +2237,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) { for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
r_result.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style); 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);
} }
} }
@ -2212,7 +2252,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<MethodInfo> signals; List<MethodInfo> signals;
gds->get_script_signal_list(&signals); gds->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
r_result.insert(quote_style + E->get().name + quote_style); 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(); Ref<GDScript> base_script = gds->get_base_script();
@ -2250,7 +2292,8 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<String> options; List<String> options;
obj->get_argument_options(p_method, p_argidx, &options); obj->get_argument_options(p_method, p_argidx, &options);
for (List<String>::Element *F = options.front(); F; F = F->next()) { for (List<String>::Element *F = options.front(); F; F = F->next()) {
r_result.insert(F->get()); ScriptCodeCompletionOption option(F->get(), ScriptCodeCompletionOption::KIND_FUNCTION);
r_result.insert(option.display, option);
} }
} }
} }
@ -2271,7 +2314,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
List<MethodInfo> signals; List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals); ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
r_result.insert(quote_style + E->get().name + quote_style); ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL);
option.insert_text = quote_style + option.display + quote_style;
r_result.insert(option.display, option);
} }
} }
@ -2286,7 +2331,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
continue; continue;
} }
String name = s.get_slice("/", 1); String name = s.get_slice("/", 1);
r_result.insert(quote_style + "/root/" + name + quote_style); ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH);
option.insert_text = quote_style + option.display + quote_style;
r_result.insert(option.display, option);
} }
} }
@ -2300,7 +2347,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
continue; continue;
} }
String name = s.get_slice("/", 1); String name = s.get_slice("/", 1);
r_result.insert(quote_style + name + quote_style); ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT);
option.insert_text = quote_style + option.display + quote_style;
r_result.insert(option.display, option);
} }
} }
@ -2333,7 +2382,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
} }
} }
static void _find_call_arguments(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) ? "'" : "\""; const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
@ -2451,17 +2500,19 @@ static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDS
_find_call_arguments(p_context, ci, function, p_argidx, _static, r_result, r_arghint); _find_call_arguments(p_context, ci, function, p_argidx, _static, r_result, r_arghint);
if (function == "connect" && p_argidx == 2) { if (function == "connect" && p_argidx == 2) {
Set<String> methods; Map<String, ScriptCodeCompletionOption> methods;
_find_identifiers_in_base(p_context, connect_base, true, methods); _find_identifiers_in_base(p_context, connect_base, true, methods);
for (Set<String>::Element *E = methods.front(); E; E = E->next()) { for (Map<String, ScriptCodeCompletionOption>::Element *E = methods.front(); E; E = E->next()) {
r_result.insert(quote_style + E->get().replace("(", "").replace(")", "") + quote_style); 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; r_forced = r_result.size() > 0;
} }
Error GDScriptLanguage::complete_code(const String &p_code, const String &p_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) ? "'" : "\""; const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
@ -2469,7 +2520,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
parser.parse(p_code, p_path.get_base_dir(), false, p_path, true); parser.parse(p_code, p_path.get_base_dir(), false, p_path, true);
r_forced = false; r_forced = false;
Set<String> options; Map<String, ScriptCodeCompletionOption> options;
GDScriptCompletionContext context; GDScriptCompletionContext context;
context._class = parser.get_completion_class(); context._class = parser.get_completion_class();
context.block = parser.get_completion_block(); context.block = parser.get_completion_block();
@ -2490,7 +2541,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
List<StringName> constants; List<StringName> constants;
Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants); Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants);
for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { 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; } break;
case GDScriptParser::COMPLETION_PARENT_FUNCTION: { case GDScriptParser::COMPLETION_PARENT_FUNCTION: {
@ -2515,9 +2567,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
r_forced = true; r_forced = true;
String idopt = opt.unquote(); String idopt = opt.unquote();
if (idopt.replace("/", "_").is_valid_identifier()) { if (idopt.replace("/", "_").is_valid_identifier()) {
options.insert(idopt); ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH);
options.insert(option.display, option);
} else { } else {
options.insert(opt); ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
options.insert(option.display, option);
} }
} }
} }
@ -2532,7 +2586,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
continue; continue;
} }
String name = s.get_slice("/", 1); String name = s.get_slice("/", 1);
options.insert(quote_style + "/root/" + name + quote_style); ScriptCodeCompletionOption option(quote_style + "/root/" + name + quote_style, ScriptCodeCompletionOption::KIND_NODE_PATH);
options.insert(option.display, option);
} }
} }
} break; } break;
@ -2655,7 +2710,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
} }
method_hint += ":"; method_hint += ":";
options.insert(method_hint); ScriptCodeCompletionOption option(method_hint, ScriptCodeCompletionOption::KIND_FUNCTION);
options.insert(option.display, option);
} }
} break; } break;
case GDScriptParser::COMPLETION_YIELD: { case GDScriptParser::COMPLETION_YIELD: {
@ -2673,7 +2729,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
switch (base_type.kind) { switch (base_type.kind) {
case GDScriptParser::DataType::CLASS: { case GDScriptParser::DataType::CLASS: {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) { for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
options.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style); 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; base_type = base_type.class_type->base_type;
} break; } break;
@ -2684,7 +2742,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
List<MethodInfo> signals; List<MethodInfo> signals;
scr->get_script_signal_list(&signals); scr->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
options.insert(quote_style + E->get().name + quote_style); 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(); Ref<Script> base_script = scr->get_base_script();
if (base_script.is_valid()) { if (base_script.is_valid()) {
@ -2711,7 +2770,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
List<MethodInfo> signals; List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals); ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
options.insert(quote_style + E->get().name + quote_style); ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL);
options.insert(option.display, option);
} }
} break; } break;
default: { default: {
@ -2748,18 +2808,21 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
c.line = E->value().expression->line; c.line = E->value().expression->line;
if (_guess_expression_type(c, E->value().expression, constant)) { if (_guess_expression_type(c, E->value().expression, constant)) {
if (constant.type.has_type && constant.type.is_meta_type) { 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++) { for (int i = 0; i < clss->subclasses.size(); i++) {
if (clss->subclasses[i]->name != StringName()) { 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; clss = clss->owner;
for (int i = 0; i < Variant::VARIANT_MAX; i++) { 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);
} }
} }
@ -2773,18 +2836,21 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
if (Engine::get_singleton()->has_singleton(class_name)) { if (Engine::get_singleton()->has_singleton(class_name)) {
continue; continue;
} }
options.insert(class_name); ScriptCodeCompletionOption option(class_name, ScriptCodeCompletionOption::KIND_CLASS);
options.insert(option.display, option);
} }
// Named scripts // Named scripts
List<StringName> named_scripts; List<StringName> named_scripts;
ScriptServer::get_global_class_list(&named_scripts); ScriptServer::get_global_class_list(&named_scripts);
for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { 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()) { 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; r_forced = true;
} break; } break;
@ -2831,13 +2897,15 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
c2.line = E->value().expression->line; c2.line = E->value().expression->line;
if (_guess_expression_type(c2, E->value().expression, constant)) { if (_guess_expression_type(c2, E->value().expression, constant)) {
if (constant.type.has_type && constant.type.is_meta_type) { 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++) { for (int i = 0; i < base_type.class_type->subclasses.size(); i++) {
if (base_type.class_type->subclasses[i]->name != StringName()) { 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);
} }
} }
@ -2855,7 +2923,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
Ref<Script> const_scr = E->value(); Ref<Script> const_scr = E->value();
if (const_scr.is_valid()) { 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(); Ref<Script> base_script = scr->get_base_script();
@ -2877,7 +2946,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
} break; } 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()); r_options->push_back(E->get());
} }
@ -2886,7 +2955,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
#else #else
Error GDScriptLanguage::complete_code(const String &p_code, const String &p_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; return OK;
} }