Merge pull request #45393 from Paulb23/code_edit_autocomplete

This commit is contained in:
Rémi Verschelde 2021-06-01 17:58:19 +02:00 committed by GitHub
commit c5f237eaf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 2059 additions and 888 deletions

View File

@ -474,10 +474,14 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_completion_query", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KEY_TAB));
inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER));
default_builtin_cache.insert("ui_text_completion_accept", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KEY_TAB));
default_builtin_cache.insert("ui_text_completion_replace", inputs);
// Newlines
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KEY_ENTER));

View File

@ -242,6 +242,8 @@ public:
};
struct ScriptCodeCompletionOption {
/* Keep enum in Sync with: */
/* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */
enum Kind {
KIND_CLASS,
KIND_FUNCTION,

View File

@ -8,6 +8,91 @@
<tutorials>
</tutorials>
<methods>
<method name="_confirm_code_completion" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="replace" type="bool">
</argument>
<description>
Override this method to define how the selected entry should be inserted. If [code]replace[/code] is true, any existing text should be replaced.
</description>
</method>
<method name="_filter_code_completion_candidates" qualifiers="virtual">
<return type="Array">
</return>
<argument index="0" name="candidates" type="Array">
</argument>
<description>
Override this method to define what items in [code]candidates[/code] should be displayed.
Both [code]candidates[/code] and the return is a [Array] of [Dictionary], see [method get_code_completion_option] for [Dictionary] content.
</description>
</method>
<method name="_request_code_completion" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="force" type="bool">
</argument>
<description>
Override this method to define what happens when the user requests code completion. If [code]force[/code] is true, any checks should be bypassed.
</description>
</method>
<method name="add_code_completion_option">
<return type="void">
</return>
<argument index="0" name="type" type="int" enum="CodeEdit.CodeCompletionKind">
</argument>
<argument index="1" name="display_text" type="String">
</argument>
<argument index="2" name="insert_text" type="String">
</argument>
<argument index="3" name="text_color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<argument index="4" name="icon" type="Resource" default="null">
</argument>
<argument index="5" name="value" type="Variant" default="0">
</argument>
<description>
Submits an item to the queue of potential candidates for the autocomplete menu. Call [method update_code_completion_options] to update the list.
[b]Note[/b]: This list will replace all current candidates.
</description>
</method>
<method name="add_comment_delimiter">
<return type="void">
</return>
<argument index="0" name="start_key" type="String">
</argument>
<argument index="1" name="end_key" type="String">
</argument>
<argument index="2" name="line_only" type="bool" default="false">
</argument>
<description>
Adds a comment delimiter.
Both the start and end keys must be symbols. Only the start key has to be unique.
Line only denotes if the region should continue until the end of the line or carry over on to the next line. If the end key is blank this is automatically set to [code]true[/code].
</description>
</method>
<method name="add_string_delimiter">
<return type="void">
</return>
<argument index="0" name="start_key" type="String">
</argument>
<argument index="1" name="end_key" type="String">
</argument>
<argument index="2" name="line_only" type="bool" default="false">
</argument>
<description>
Adds a string delimiter.
Both the start and end keys must be symbols. Only the start key has to be unique.
Line only denotes if the region should continue until the end of the line or carry over on to the next line. If the end key is blank this is automatically set to [code]true[/code].
</description>
</method>
<method name="cancel_code_completion">
<return type="void">
</return>
<description>
Cancels the autocomplete menu.
</description>
</method>
<method name="clear_bookmarked_lines">
<return type="void">
</return>
@ -20,12 +105,35 @@
<description>
</description>
</method>
<method name="clear_comment_delimiters">
<return type="void">
</return>
<description>
Removes all comment delimiters.
</description>
</method>
<method name="clear_executing_lines">
<return type="void">
</return>
<description>
</description>
</method>
<method name="clear_string_delimiters">
<return type="void">
</return>
<description>
Removes all string delimiters.
</description>
</method>
<method name="confirm_code_completion">
<return type="void">
</return>
<argument index="0" name="replace" type="bool" default="false">
</argument>
<description>
Inserts the selected entry into the text. If [code]replace[/code] is true, any existing text is replaced rather then merged.
</description>
</method>
<method name="get_bookmarked_lines" qualifiers="const">
<return type="Array">
</return>
@ -38,12 +146,128 @@
<description>
</description>
</method>
<method name="get_code_completion_option" qualifiers="const">
<return type="Dictionary">
</return>
<argument index="0" name="index" type="int">
</argument>
<description>
Gets the completion option at [code]index[/code]. The return [Dictionary] has the following key-values:
[code]kind[/code]: [enum CodeCompletionKind]
[code]display_text[/code]: Text that is shown on the autocomplete menu.
[code]insert_text[/code]: Text that is to be inserted when this item is selected.
[code]font_color[/code]: Color of the text on the autocomplete menu.
[code]icon[/code]: Icon to draw on the autocomplete menu.
[code]default_value[/code]: Value of the symbol.
</description>
</method>
<method name="get_code_completion_options" qualifiers="const">
<return type="Dictionary[]">
</return>
<description>
Gets all completion options, see [method get_code_completion_option] for return content.
</description>
</method>
<method name="get_code_completion_selected_index" qualifiers="const">
<return type="int">
</return>
<description>
Gets the index of the current selected completion option.
</description>
</method>
<method name="get_delimiter_end_key" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="delimiter_index" type="int">
</argument>
<description>
Gets the end key for a string or comment region index.
</description>
</method>
<method name="get_delimiter_end_postion" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="line" type="int">
</argument>
<argument index="1" name="column" type="int">
</argument>
<description>
If [code]line[/code] [code]column[/code] is in a string or comment, returns the end position of the region. If not or no end could be found, both [Vector2] values will be [code]-1[/code].
</description>
</method>
<method name="get_delimiter_start_key" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="delimiter_index" type="int">
</argument>
<description>
Gets the start key for a string or comment region index.
</description>
</method>
<method name="get_delimiter_start_postion" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="line" type="int">
</argument>
<argument index="1" name="column" type="int">
</argument>
<description>
If [code]line[/code] [code]column[/code] is in a string or comment, returns the start position of the region. If not or no start could be found, both [Vector2] values will be [code]-1[/code].
</description>
</method>
<method name="get_executing_lines" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
<method name="get_text_for_code_completion" qualifiers="const">
<return type="String">
</return>
<description>
Returns the full text with char [code]0xFFFF[/code] at the caret location.
</description>
</method>
<method name="has_comment_delimiter" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="start_key" type="String">
</argument>
<description>
Returns [code]true[/code] if comment [code]start_key[/code] exists.
</description>
</method>
<method name="has_string_delimiter" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="start_key" type="String">
</argument>
<description>
Returns [code]true[/code] if string [code]start_key[/code] exists.
</description>
</method>
<method name="is_in_comment" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="line" type="int">
</argument>
<argument index="1" name="column" type="int" default="-1">
</argument>
<description>
Return delimiter index if [code]line[/code] [code]column[/code] is in a comment. If [code]column[/code] is not provided, will return delimiter index if the entire [code]line[/code] is a comment. Otherwise [code]-1[/code].
</description>
</method>
<method name="is_in_string" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="line" type="int">
</argument>
<argument index="1" name="column" type="int" default="-1">
</argument>
<description>
Return the delimiter index if [code]line[/code] [code]column[/code] is in a string. If [code]column[/code] is not provided, will return the delimiter index if the entire [code]line[/code] is a string. Otherwise [code]-1[/code].
</description>
</method>
<method name="is_line_bookmarked" qualifiers="const">
<return type="bool">
</return>
@ -68,6 +292,60 @@
<description>
</description>
</method>
<method name="remove_comment_delimiter">
<return type="void">
</return>
<argument index="0" name="start_key" type="String">
</argument>
<description>
Removes the comment delimiter with [code]start_key[/code].
</description>
</method>
<method name="remove_string_delimiter">
<return type="void">
</return>
<argument index="0" name="start_key" type="String">
</argument>
<description>
Removes the string delimiter with [code]start_key[/code].
</description>
</method>
<method name="request_code_completion">
<return type="void">
</return>
<argument index="0" name="force" type="bool" default="false">
</argument>
<description>
Emits [signal request_code_completion], if [code]force[/code] is true will bypass all checks. Otherwise will check that the caret is in a word or in front of a prefix. Will ignore the request if all current options are of type file path, node path or signal.
</description>
</method>
<method name="set_code_completion_selected_index">
<return type="void">
</return>
<argument index="0" name="index" type="int">
</argument>
<description>
Sets the current selected completion option.
</description>
</method>
<method name="set_code_hint">
<return type="void">
</return>
<argument index="0" name="code_hint" type="String">
</argument>
<description>
Sets the code hint text. Pass an empty string to clear.
</description>
</method>
<method name="set_code_hint_draw_below">
<return type="void">
</return>
<argument index="0" name="draw_below" type="bool">
</argument>
<description>
Sets if the code hint should draw below the text.
</description>
</method>
<method name="set_line_as_bookmarked">
<return type="void">
</return>
@ -98,8 +376,30 @@
<description>
</description>
</method>
<method name="update_code_completion_options">
<return type="void">
</return>
<argument index="0" name="force" type="bool">
</argument>
<description>
Submits all completion options added with [method add_code_completion_option]. Will try to force the autoccomplete menu to popup, if [code]force[/code] is [code]true[/code].
[b]Note[/b]: This will replace all current candidates.
</description>
</method>
</methods>
<members>
<member name="code_completion_enabled" type="bool" setter="set_code_completion_enabled" getter="is_code_completion_enabled" default="false">
Sets whether code completion is allowed.
</member>
<member name="code_completion_prefixes" type="String[]" setter="set_code_completion_prefixes" getter="get_code_comletion_prefixes" default="[ ]">
Sets prefixes that will trigger code completion.
</member>
<member name="delimiter_comments" type="String[]" setter="set_comment_delimiters" getter="get_comment_delimiters" default="[ ]">
Sets the comment delimiters. All existing comment delimiters will be removed.
</member>
<member name="delimiter_strings" type="String[]" setter="set_string_delimiters" getter="get_string_delimiters" default="[ ]">
Sets the string delimiters. All existing string delimiters will be removed.
</member>
<member name="draw_bookmarks" type="bool" setter="set_draw_bookmarks_gutter" getter="is_drawing_bookmarks_gutter" default="false">
</member>
<member name="draw_breakpoints_gutter" type="bool" setter="set_draw_breakpoints_gutter" getter="is_drawing_breakpoints_gutter" default="false">
@ -123,8 +423,33 @@
<description>
</description>
</signal>
<signal name="request_code_completion">
<description>
Emitted when the user requests code completion.
</description>
</signal>
</signals>
<constants>
<constant name="KIND_CLASS" value="0" enum="CodeCompletionKind">
</constant>
<constant name="KIND_FUNCTION" value="1" enum="CodeCompletionKind">
</constant>
<constant name="KIND_SIGNAL" value="2" enum="CodeCompletionKind">
</constant>
<constant name="KIND_VARIABLE" value="3" enum="CodeCompletionKind">
</constant>
<constant name="KIND_MEMBER" value="4" enum="CodeCompletionKind">
</constant>
<constant name="KIND_ENUM" value="5" enum="CodeCompletionKind">
</constant>
<constant name="KIND_CONSTANT" value="6" enum="CodeCompletionKind">
</constant>
<constant name="KIND_NODE_PATH" value="7" enum="CodeCompletionKind">
</constant>
<constant name="KIND_FILE_PATH" value="8" enum="CodeCompletionKind">
</constant>
<constant name="KIND_PLAIN_TEXT" value="9" enum="CodeCompletionKind">
</constant>
</constants>
<theme_items>
<theme_item name="background_color" type="Color" default="Color( 0, 0, 0, 0 )">

View File

@ -703,6 +703,8 @@
</member>
<member name="input/ui_text_completion_query" type="Dictionary" setter="" getter="">
</member>
<member name="input/ui_text_completion_replace" type="Dictionary" setter="" getter="">
</member>
<member name="input/ui_text_dedent" type="Dictionary" setter="" getter="">
</member>
<member name="input/ui_text_delete" type="Dictionary" setter="" getter="">

View File

@ -128,6 +128,13 @@
Folds the given line, if possible (see [method can_fold]).
</description>
</method>
<method name="get_caret_draw_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
Gets the caret pixel draw poistion.
</description>
</method>
<method name="get_gutter_count" qualifiers="const">
<return type="int">
</return>
@ -315,6 +322,13 @@
Insert the specified text at the cursor position.
</description>
</method>
<method name="is_caret_visible" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the caret is visible on the screen.
</description>
</method>
<method name="is_folded" qualifiers="const">
<return type="bool">
</return>
@ -812,10 +826,6 @@
<description>
</description>
</signal>
<signal name="request_completion">
<description>
</description>
</signal>
<signal name="symbol_lookup">
<argument index="0" name="symbol" type="String">
</argument>
@ -964,24 +974,6 @@
</theme_item>
<theme_item name="code_folding_color" type="Color" default="Color( 0.8, 0.8, 0.8, 0.8 )">
</theme_item>
<theme_item name="completion" type="StyleBox">
</theme_item>
<theme_item name="completion_background_color" type="Color" default="Color( 0.17, 0.16, 0.2, 1 )">
</theme_item>
<theme_item name="completion_existing_color" type="Color" default="Color( 0.87, 0.87, 0.87, 0.13 )">
</theme_item>
<theme_item name="completion_font_color" type="Color" default="Color( 0.67, 0.67, 0.67, 1 )">
</theme_item>
<theme_item name="completion_lines" type="int" default="7">
</theme_item>
<theme_item name="completion_max_width" type="int" default="50">
</theme_item>
<theme_item name="completion_scroll_color" type="Color" default="Color( 1, 1, 1, 1 )">
</theme_item>
<theme_item name="completion_scroll_width" type="int" default="3">
</theme_item>
<theme_item name="completion_selected_color" type="Color" default="Color( 0.26, 0.26, 0.27, 1 )">
</theme_item>
<theme_item name="current_line_color" type="Color" default="Color( 0.25, 0.25, 0.26, 0.8 )">
Sets the [Color] of the breakpoints. [member breakpoint_gutter] has to be enabled.
</theme_item>

View File

@ -816,12 +816,12 @@ void CodeTextEditor::_code_complete_timer_timeout() {
if (!is_visible_in_tree()) {
return;
}
text_editor->query_code_comple();
text_editor->request_code_completion();
}
void CodeTextEditor::_complete_request() {
List<ScriptCodeCompletionOption> entries;
String ctext = text_editor->get_text_for_completion();
String ctext = text_editor->get_text_for_code_completion();
_code_complete_script(ctext, &entries);
bool forced = false;
if (code_complete_func) {
@ -832,16 +832,17 @@ void CodeTextEditor::_complete_request() {
}
for (List<ScriptCodeCompletionOption>::Element *E = entries.front(); E; E = E->next()) {
ScriptCodeCompletionOption *e = &E->get();
e->icon = _get_completion_icon(*e);
e->font_color = completion_font_color;
if (e->insert_text.begins_with("\"") || e->insert_text.begins_with("\'")) {
e->font_color = completion_string_color;
} else if (e->insert_text.begins_with("#") || e->insert_text.begins_with("//")) {
e->font_color = completion_comment_color;
ScriptCodeCompletionOption &e = E->get();
Color font_color = completion_font_color;
if (e.insert_text.begins_with("\"") || e.insert_text.begins_with("\'")) {
font_color = completion_string_color;
} else if (e.insert_text.begins_with("#") || e.insert_text.begins_with("//")) {
font_color = completion_comment_color;
}
text_editor->add_code_completion_option((CodeEdit::CodeCompletionKind)e.kind, e.display, e.insert_text, font_color, _get_completion_icon(e), e.default_value);
}
text_editor->code_complete(entries, forced);
text_editor->update_code_completion_options(forced);
}
Ref<Texture2D> CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOption &p_option) {
@ -1563,9 +1564,7 @@ void CodeTextEditor::_on_settings_change() {
EDITOR_GET("text_editor/completion/code_complete_delay"));
// Call hint settings.
text_editor->set_callhint_settings(
EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"),
EDITOR_GET("text_editor/completion/callhint_tooltip_offset"));
text_editor->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"));
idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay"));
}
@ -1847,15 +1846,17 @@ CodeTextEditor::CodeTextEditor() {
text_editor->connect("gui_input", callable_mp(this, &CodeTextEditor::_text_editor_gui_input));
text_editor->connect("cursor_changed", callable_mp(this, &CodeTextEditor::_line_col_changed));
text_editor->connect("text_changed", callable_mp(this, &CodeTextEditor::_text_changed));
text_editor->connect("request_completion", callable_mp(this, &CodeTextEditor::_complete_request));
Vector<String> cs;
text_editor->connect("request_code_completion", callable_mp(this, &CodeTextEditor::_complete_request));
TypedArray<String> cs;
cs.push_back(".");
cs.push_back(",");
cs.push_back("(");
cs.push_back("=");
cs.push_back("$");
cs.push_back("@");
text_editor->set_completion(true, cs);
cs.push_back("\"");
cs.push_back("\'");
text_editor->set_code_completion_prefixes(cs);
idle->connect("timeout", callable_mp(this, &CodeTextEditor::_text_changed_idle_timeout));
code_complete_timer->connect("timeout", callable_mp(this, &CodeTextEditor::_code_complete_timer_timeout));

View File

@ -571,7 +571,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/completion/code_complete_delay", 0.3);
hints["text_editor/completion/code_complete_delay"] = PropertyInfo(Variant::FLOAT, "text_editor/completion/code_complete_delay", PROPERTY_HINT_RANGE, "0.01, 5, 0.01");
_initial_set("text_editor/completion/put_callhint_tooltip_below_current_line", true);
_initial_set("text_editor/completion/callhint_tooltip_offset", Vector2());
_initial_set("text_editor/completion/complete_file_paths", true);
_initial_set("text_editor/completion/add_type_hints", false);
_initial_set("text_editor/completion/use_single_quotes", false);

View File

@ -203,6 +203,26 @@ void ScriptTextEditor::_set_theme_for_script() {
CodeEdit *text_edit = code_editor->get_text_editor();
text_edit->get_syntax_highlighter()->update_cache();
List<String> strings;
script->get_language()->get_string_delimiters(&strings);
text_edit->clear_string_delimiters();
for (List<String>::Element *E = strings.front(); E; E = E->next()) {
String string = E->get();
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
text_edit->add_string_delimiter(beg, end, end == "");
}
List<String> comments;
script->get_language()->get_comment_delimiters(&comments);
text_edit->clear_comment_delimiters();
for (List<String>::Element *E = comments.front(); E; E = E->next()) {
String comment = E->get();
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
text_edit->add_comment_delimiter(beg, end, end == "");
}
/* add keywords for auto completion */
// singleton autoloads (as types, just as engine singletons are)
Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
@ -1056,7 +1076,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
_edit_option_toggle_inline_comment();
} break;
case EDIT_COMPLETE: {
tx->query_code_comple();
tx->request_code_completion(true);
} break;
case EDIT_AUTO_INDENT: {
String text = tx->get_text();
@ -1804,9 +1824,7 @@ ScriptTextEditor::ScriptTextEditor() {
update_settings();
code_editor->get_text_editor()->set_callhint_settings(
EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"),
EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset"));
code_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
code_editor->get_text_editor()->set_select_identifiers_on_hover(true);
code_editor->get_text_editor()->set_context_menu_enabled(false);

View File

@ -154,6 +154,10 @@ void ShaderTextEditor::_load_theme_settings() {
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, true);
text_editor->clear_comment_delimiters();
text_editor->add_comment_delimiter("/*", "*/", false);
text_editor->add_comment_delimiter("//", "", true);
if (warnings_panel) {
// Warnings panel
warnings_panel->add_theme_font_override("normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts"));
@ -348,7 +352,7 @@ void ShaderEditor::_menu_option(int p_option) {
} break;
case EDIT_COMPLETE: {
shader_editor->get_text_editor()->query_code_comple();
shader_editor->get_text_editor()->request_code_completion();
} break;
case SEARCH_FIND: {
shader_editor->get_find_replace_bar()->popup_search();
@ -659,9 +663,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ShaderEditor::_editor_settings_changed));
ProjectSettingsEditor::get_singleton()->connect("confirmed", callable_mp(this, &ShaderEditor::_project_settings_changed));
shader_editor->get_text_editor()->set_callhint_settings(
EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"),
EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset"));
shader_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
shader_editor->get_text_editor()->set_select_identifiers_on_hover(true);
shader_editor->get_text_editor()->set_context_menu_enabled(false);

View File

@ -848,6 +848,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
expression_syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
expression_syntax_highlighter->add_color_region("//", "", comment_color, true);
expression_box->clear_comment_delimiters();
expression_box->add_comment_delimiter("/*", "*/", false);
expression_box->add_comment_delimiter("//", "", true);
expression_box->set_text(expression);
expression_box->set_context_menu_enabled(false);
expression_box->set_draw_line_numbers(true);
@ -2984,6 +2988,10 @@ void VisualShaderEditor::_notification(int p_what) {
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, true);
preview_text->clear_comment_delimiters();
preview_text->add_comment_delimiter("/*", "*/", false);
preview_text->add_comment_delimiter("//", "", true);
error_text->add_theme_font_override("font", get_theme_font("status_source", "EditorFonts"));
error_text->add_theme_font_size_override("font_size", get_theme_font_size("status_source_size", "EditorFonts"));
error_text->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,22 @@
class CodeEdit : public TextEdit {
GDCLASS(CodeEdit, TextEdit)
public:
/* Keep enum in sync with: */
/* /core/object/script_language.h - ScriptCodeCompletionOption::Kind */
enum CodeCompletionKind {
KIND_CLASS,
KIND_FUNCTION,
KIND_SIGNAL,
KIND_VARIABLE,
KIND_MEMBER,
KIND_ENUM,
KIND_CONSTANT,
KIND_NODE_PATH,
KIND_FILE_PATH,
KIND_PLAIN_TEXT,
};
private:
/* Main Gutter */
enum MainGutterType {
@ -80,16 +96,113 @@ private:
void _fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region);
void _gutter_clicked(int p_line, int p_gutter);
void _lines_edited_from(int p_from_line, int p_to_line);
void _update_gutter_indexes();
/* Delimiters */
enum DelimiterType {
TYPE_STRING,
TYPE_COMMENT,
};
struct Delimiter {
DelimiterType type;
String start_key = "";
String end_key = "";
bool line_only = true;
};
bool setting_delimiters = false;
Vector<Delimiter> delimiters;
/*
* Vector entry per line, contains a Map of column numbers to delimiter index, -1 marks the end of a region.
* e.g the following text will be stored as so:
*
* 0: nothing here
* 1:
* 2: # test
* 3: "test" text "multiline
* 4:
* 5: test
* 6: string"
*
* Vector [
* 0 = []
* 1 = []
* 2 = [
* 1 = 1
* 6 = -1
* ]
* 3 = [
* 1 = 0
* 6 = -1
* 13 = 0
* ]
* 4 = [
* 0 = 0
* ]
* 5 = [
* 5 = 0
* ]
* 6 = [
* 7 = -1
* ]
* ]
*/
Vector<Map<int, int>> delimiter_cache;
void _update_delimiter_cache(int p_from_line = 0, int p_to_line = -1);
int _is_in_delimiter(int p_line, int p_column, DelimiterType p_type) const;
void _add_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only, DelimiterType p_type);
void _remove_delimiter(const String &p_start_key, DelimiterType p_type);
bool _has_delimiter(const String &p_start_key, DelimiterType p_type) const;
void _set_delimiters(const TypedArray<String> &p_delimiters, DelimiterType p_type);
void _clear_delimiters(DelimiterType p_type);
TypedArray<String> _get_delimiters(DelimiterType p_type) const;
/* Code Hint */
String code_hint = "";
bool code_hint_draw_below = true;
int code_hint_xpos = -0xFFFF;
/* Code Completion */
bool code_completion_enabled = false;
bool code_completion_forced = false;
int code_completion_max_width = 0;
int code_completion_max_lines = 7;
int code_completion_scroll_width = 0;
Color code_completion_scroll_color = Color(0, 0, 0, 0);
Color code_completion_background_color = Color(0, 0, 0, 0);
Color code_completion_selected_color = Color(0, 0, 0, 0);
Color code_completion_existing_color = Color(0, 0, 0, 0);
bool code_completion_active = false;
Vector<ScriptCodeCompletionOption> code_completion_options;
int code_completion_line_ofs = 0;
int code_completion_current_selected = 0;
int code_completion_longest_line = 0;
Rect2i code_completion_rect;
Set<String> code_completion_prefixes;
List<ScriptCodeCompletionOption> code_completion_option_submitted;
List<ScriptCodeCompletionOption> code_completion_option_sources;
String code_completion_base;
void _filter_code_completion_candidates();
void _lines_edited_from(int p_from_line, int p_to_line);
protected:
void _gui_input(const Ref<InputEvent> &p_gui_input) override;
void _notification(int p_what);
static void _bind_methods();
public:
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
/* Main Gutter */
void set_draw_breakpoints_gutter(bool p_draw);
bool is_drawing_breakpoints_gutter() const;
@ -128,8 +241,64 @@ public:
void set_draw_fold_gutter(bool p_draw);
bool is_drawing_fold_gutter() const;
/* Delimiters */
void add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only = false);
void remove_string_delimiter(const String &p_start_key);
bool has_string_delimiter(const String &p_start_key) const;
void set_string_delimiters(const TypedArray<String> &p_string_delimiters);
void clear_string_delimiters();
TypedArray<String> get_string_delimiters() const;
int is_in_string(int p_line, int p_column = -1) const;
void add_comment_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only = false);
void remove_comment_delimiter(const String &p_start_key);
bool has_comment_delimiter(const String &p_start_key) const;
void set_comment_delimiters(const TypedArray<String> &p_comment_delimiters);
void clear_comment_delimiters();
TypedArray<String> get_comment_delimiters() const;
int is_in_comment(int p_line, int p_column = -1) const;
String get_delimiter_start_key(int p_delimiter_idx) const;
String get_delimiter_end_key(int p_delimiter_idx) const;
Point2 get_delimiter_start_position(int p_line, int p_column) const;
Point2 get_delimiter_end_position(int p_line, int p_column) const;
/* Code hint */
void set_code_hint(const String &p_hint);
void set_code_hint_draw_below(bool p_below);
/* Code Completion */
void set_code_completion_enabled(bool p_enable);
bool is_code_completion_enabled() const;
void set_code_completion_prefixes(const TypedArray<String> &p_prefixes);
TypedArray<String> get_code_completion_prefixes() const;
String get_text_for_code_completion() const;
void request_code_completion(bool p_force = false);
void add_code_completion_option(CodeCompletionKind p_type, const String &p_display_text, const String &p_insert_text, const Color &p_text_color = Color(1, 1, 1), const RES &p_icon = RES(), const Variant &p_value = Variant::NIL);
void update_code_completion_options(bool p_forced = false);
TypedArray<Dictionary> get_code_completion_options() const;
Dictionary get_code_completion_option(int p_index) const;
int get_code_completion_selected_index() const;
void set_code_completion_selected_index(int p_index);
void confirm_code_completion(bool p_replace = false);
void cancel_code_completion();
CodeEdit();
~CodeEdit();
};
VARIANT_ENUM_CAST(CodeEdit::CodeCompletionKind);
#endif // CODEEDIT_H

File diff suppressed because it is too large Load Diff

View File

@ -173,6 +173,8 @@ private:
};
struct Cursor {
Point2 draw_pos;
bool visible = false;
int last_fit_x = 0;
int line = 0;
int column = 0; ///< cursor
@ -239,20 +241,6 @@ private:
Dictionary _get_line_syntax_highlighting(int p_line);
Set<String> completion_prefixes;
bool completion_enabled = false;
List<ScriptCodeCompletionOption> completion_sources;
Vector<ScriptCodeCompletionOption> completion_options;
bool completion_active = false;
bool completion_forced = false;
ScriptCodeCompletionOption completion_current;
String completion_base;
int completion_index = 0;
Rect2i completion_rect;
int completion_line_ofs = 0;
String completion_hint;
int completion_hint_offset = 0;
bool setting_text = false;
// data
@ -306,10 +294,10 @@ private:
bool highlight_all_occurrences = false;
bool scroll_past_end_of_file_enabled = false;
bool auto_brace_completion_enabled = false;
bool brace_matching_enabled = false;
bool highlight_current_line = false;
bool auto_indent = false;
String cut_copy_line;
bool insert_mode = false;
bool select_identifiers_enabled = false;
@ -341,9 +329,6 @@ private:
bool next_operation_is_complex = false;
bool callhint_below = false;
Vector2 callhint_offset;
String search_text;
uint32_t search_flags = 0;
int search_result_line = 0;
@ -437,10 +422,6 @@ private:
PopupMenu *menu_ctl;
void _clear();
void _cancel_completion();
void _cancel_code_hint();
void _confirm_completion();
void _update_completion_candidates();
int _calculate_spaces_till_next_left_indent(int column);
int _calculate_spaces_till_next_right_indent(int column);
@ -463,9 +444,11 @@ private:
void _delete_selection();
void _move_cursor_document_start(bool p_select);
void _move_cursor_document_end(bool p_select);
void _handle_unicode_character(uint32_t unicode, bool p_had_selection, bool p_update_auto_complete);
void _handle_unicode_character(uint32_t unicode, bool p_had_selection);
protected:
bool auto_brace_completion_enabled = false;
struct Cache {
Ref<Texture2D> tab_icon;
Ref<Texture2D> space_icon;
@ -477,10 +460,6 @@ protected:
int font_size = 16;
int outline_size = 0;
Color outline_color;
Color completion_background_color;
Color completion_selected_color;
Color completion_existing_color;
Color completion_font_color;
Color caret_color;
Color caret_background_color;
Color font_color;
@ -505,7 +484,7 @@ protected:
void _insert_text(int p_line, int p_char, const String &p_text, int *r_end_line = nullptr, int *r_end_char = nullptr);
void _remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
void _insert_text_at_cursor(const String &p_text);
void _gui_input(const Ref<InputEvent> &p_gui_input);
virtual void _gui_input(const Ref<InputEvent> &p_gui_input);
void _notification(int p_what);
void _consume_pair_symbol(char32_t ch);
@ -681,10 +660,6 @@ public:
brace_matching_enabled = p_enabled;
update();
}
inline void set_callhint_settings(bool below, Vector2 offset) {
callhint_below = below;
callhint_offset = offset;
}
void set_auto_indent(bool p_auto_indent);
void center_viewport_to_cursor();
@ -695,6 +670,8 @@ public:
void cursor_set_column(int p_col, bool p_adjust_viewport = true);
void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0);
Point2 get_caret_draw_pos() const;
bool is_caret_visible() const;
int cursor_get_column() const;
int cursor_get_line() const;
Vector2i _get_cursor_pixel_pos(bool p_adjust_viewport = true);
@ -811,11 +788,6 @@ public:
void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata);
void set_completion(bool p_enabled, const Vector<String> &p_prefixes);
void code_complete(const List<ScriptCodeCompletionOption> &p_strings, bool p_forced = false);
void set_code_hint(const String &p_hint);
void query_code_comple();
void set_select_identifiers_on_hover(bool p_enable);
bool is_selecting_identifiers_on_hover_enabled() const;
@ -833,7 +805,6 @@ public:
PopupMenu *get_menu() const;
String get_text_for_completion();
String get_text_for_lookup_completion();
virtual bool is_text_field() const override;

View File

@ -432,7 +432,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("normal", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_stylebox("focus", "TextEdit", focus);
theme->set_stylebox("read_only", "TextEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0));
theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_icon("tab", "TextEdit", make_icon(tab_png));
theme->set_icon("space", "TextEdit", make_icon(space_png));
@ -441,11 +440,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font_size("font_size", "TextEdit", -1);
theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("completion_background_color", "TextEdit", Color(0.17, 0.16, 0.2));
theme->set_color("completion_selected_color", "TextEdit", Color(0.26, 0.26, 0.27));
theme->set_color("completion_existing_color", "TextEdit", Color(0.87, 0.87, 0.87, 0.13));
theme->set_color("completion_scroll_color", "TextEdit", control_font_pressed_color);
theme->set_color("completion_font_color", "TextEdit", Color(0.67, 0.67, 0.67));
theme->set_color("font_color", "TextEdit", control_font_color);
theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0));
theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
@ -458,9 +452,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2));
theme->set_color("word_highlighted_color", "TextEdit", Color(0.8, 0.9, 0.9, 0.15));
theme->set_constant("completion_lines", "TextEdit", 7);
theme->set_constant("completion_max_width", "TextEdit", 50);
theme->set_constant("completion_scroll_width", "TextEdit", 3);
theme->set_constant("line_spacing", "TextEdit", 4 * scale);
theme->set_constant("outline_size", "TextEdit", 0);