Przeglądaj źródła

Parse more informations for code completion

Geequlim 6 lat temu
rodzic
commit
ed7ed52151

+ 29 - 1
core/script_language.h

@@ -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 {

+ 8 - 7
editor/code_editor.cpp

@@ -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() {

+ 2 - 2
editor/code_editor.h

@@ -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();

+ 2 - 2
editor/plugins/script_text_editor.cpp

@@ -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();

+ 4 - 2
editor/plugins/script_text_editor.h

@@ -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);

+ 3 - 2
modules/gdnative/pluginscript/pluginscript_language.cpp

@@ -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;
 	}
 	}

+ 1 - 1
modules/gdnative/pluginscript/pluginscript_language.h

@@ -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);
 
 

+ 1 - 1
modules/gdscript/gdscript.h

@@ -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

+ 144 - 75
modules/gdscript/gdscript_editor.cpp

@@ -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()) {
-			r_result.insert(quote_style + E->get().replace("(", "").replace(")", "") + quote_style);
+		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;
 	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;
 }
 }