diff options
Diffstat (limited to 'editor/code_editor.cpp')
-rw-r--r-- | editor/code_editor.cpp | 485 |
1 files changed, 397 insertions, 88 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 0b06839ecf..db44edcfcb 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -30,6 +30,7 @@ #include "code_editor.h" +#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/string_builder.h" #include "editor/editor_scale.h" @@ -107,6 +108,8 @@ void FindReplaceBar::_notification(int p_what) { hide_button->set_hover_texture(get_icon("Close", "EditorIcons")); hide_button->set_pressed_texture(get_icon("Close", "EditorIcons")); hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size()); + } else if (p_what == NOTIFICATION_THEME_CHANGED) { + matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor")); } } @@ -151,6 +154,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) text_edit->cursor_set_line(line, false); text_edit->cursor_set_column(col + text.length(), false); text_edit->center_viewport_to_cursor(); + text_edit->select(line, col, line, col + text.length()); } text_edit->set_search_text(text); @@ -160,14 +164,18 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) result_line = line; result_col = col; - set_error(""); + _update_results_count(); } else { + results_count = 0; result_line = -1; result_col = -1; text_edit->set_search_text(""); - set_error(text.empty() ? "" : TTR("No Matches")); + text_edit->set_search_flags(p_flags); + text_edit->set_current_search_result(line, col); } + _update_matches_label(); + return found; } @@ -181,15 +189,19 @@ void FindReplaceBar::_replace() { text_edit->insert_text_at_cursor(get_replace_text()); text_edit->end_complex_operation(); + + results_count = -1; } - search_current(); + if (!search_current()) { + search_next(); + } } void FindReplaceBar::_replace_all() { text_edit->disconnect("text_changed", this, "_editor_text_changed"); - // line as x so it gets priority in comparison, column as y + // Line as x so it gets priority in comparison, column as y. Point2i orig_cursor(text_edit->cursor_get_line(), text_edit->cursor_get_column()); Point2i prev_match = Point2(-1, -1); @@ -221,7 +233,7 @@ void FindReplaceBar::_replace_all() { Point2i match_to(result_line, result_col + search_text_len); if (match_from < prev_match) { - break; // done + break; // Done. } prev_match = Point2i(result_line, result_col + replace_text.length()); @@ -234,14 +246,14 @@ void FindReplaceBar::_replace_all() { continue; } - // replace but adjust selection bounds + // Replace but adjust selection bounds. text_edit->insert_text_at_cursor(replace_text); if (match_to.x == selection_end.x) { selection_end.y += replace_text.length() - search_text_len; } } else { - // just replace + // Just replace. text_edit->insert_text_at_cursor(replace_text); } @@ -253,12 +265,12 @@ void FindReplaceBar::_replace_all() { replace_all_mode = false; - // restore editor state (selection, cursor, scroll) + // Restore editor state (selection, cursor, scroll). text_edit->cursor_set_line(orig_cursor.x); text_edit->cursor_set_column(orig_cursor.y); if (selection_enabled && is_selection_only()) { - // reselect + // Reselect. text_edit->select(selection_begin.x, selection_begin.y, selection_end.x, selection_end.y); } else { text_edit->deselect(); @@ -268,6 +280,7 @@ void FindReplaceBar::_replace_all() { set_error(vformat(TTR("Replaced %d occurrence(s)."), rc)); text_edit->call_deferred("connect", "text_changed", this, "_editor_text_changed"); + results_count = -1; } void FindReplaceBar::_get_search_from(int &r_line, int &r_col) { @@ -275,22 +288,50 @@ void FindReplaceBar::_get_search_from(int &r_line, int &r_col) { r_line = text_edit->cursor_get_line(); r_col = text_edit->cursor_get_column(); - if (text_edit->is_selection_active() && !replace_all_mode) { + if (r_line == result_line && r_col >= result_col && r_col <= result_col + get_search_text().length()) { + r_col = result_col; + } +} - int selection_line = text_edit->get_selection_from_line(); +void FindReplaceBar::_update_results_count() { + if (results_count != -1) + return; - if (text_edit->get_selection_text() == get_search_text() && r_line == selection_line) { + results_count = 0; - int selection_from_col = text_edit->get_selection_from_column(); + String searched = get_search_text(); + if (searched.empty()) return; - if (r_col >= selection_from_col && r_col <= text_edit->get_selection_to_column()) { - r_col = selection_from_col; - } + String full_text = text_edit->get_text(); + + int from_pos = 0; + + while (true) { + int pos = is_case_sensitive() ? full_text.find(searched, from_pos) : full_text.findn(searched, from_pos); + if (pos == -1) break; + + if (is_whole_words()) { + from_pos++; // Making sure we won't hit the same match next time, if we get out via a continue. + if (pos > 0 && !is_symbol(full_text[pos - 1])) + continue; + if (pos + searched.length() < full_text.length() && !is_symbol(full_text[pos + searched.length()])) + continue; } + + results_count++; + from_pos = pos + searched.length(); } +} - if (r_line == result_line && r_col >= result_col && r_col <= result_col + get_search_text().length()) { - r_col = result_col; +void FindReplaceBar::_update_matches_label() { + + if (search_text->get_text().empty() || results_count == -1) { + matches_label->hide(); + } else { + matches_label->show(); + + matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor")); + matches_label->set_text(vformat(results_count == 1 ? TTR("%d match.") : TTR("%d matches."), results_count)); } } @@ -311,6 +352,9 @@ bool FindReplaceBar::search_current() { bool FindReplaceBar::search_prev() { + if (!is_visible()) + popup_search(true); + uint32_t flags = 0; String text = get_search_text(); @@ -323,6 +367,8 @@ bool FindReplaceBar::search_prev() { int line, col; _get_search_from(line, col); + if (text_edit->is_selection_active()) + col--; // Skip currently selected word. col -= text.length(); if (col < 0) { @@ -337,8 +383,15 @@ bool FindReplaceBar::search_prev() { bool FindReplaceBar::search_next() { + if (!is_visible()) + popup_search(true); + uint32_t flags = 0; - String text = get_search_text(); + String text; + if (replace_all_mode) + text = get_replace_text(); + else + text = get_search_text(); if (is_whole_words()) flags |= TextEdit::SEARCH_WHOLE_WORDS; @@ -369,38 +422,54 @@ void FindReplaceBar::_hide_bar() { text_edit->set_search_text(""); result_line = -1; result_col = -1; - set_error(""); hide(); } -void FindReplaceBar::_show_search() { +void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) { show(); - search_text->call_deferred("grab_focus"); + if (p_show_only) + return; + + if (p_focus_replace) { + search_text->deselect(); + replace_text->call_deferred("grab_focus"); + } else { + replace_text->deselect(); + search_text->call_deferred("grab_focus"); + } if (text_edit->is_selection_active() && !selection_only->is_pressed()) { search_text->set_text(text_edit->get_selection_text()); } if (!get_search_text().empty()) { - search_text->select_all(); - search_text->set_cursor_position(search_text->get_text().length()); - search_current(); + if (p_focus_replace) { + replace_text->select_all(); + replace_text->set_cursor_position(replace_text->get_text().length()); + } else { + search_text->select_all(); + search_text->set_cursor_position(search_text->get_text().length()); + } + + results_count = -1; + _update_results_count(); + _update_matches_label(); } } -void FindReplaceBar::popup_search() { +void FindReplaceBar::popup_search(bool p_show_only) { replace_text->hide(); hbc_button_replace->hide(); hbc_option_replace->hide(); - _show_search(); + + _show_search(false, p_show_only); } void FindReplaceBar::popup_replace() { if (!replace_text->is_visible_in_tree()) { - replace_text->clear(); replace_text->show(); hbc_button_replace->show(); hbc_option_replace->show(); @@ -408,16 +477,18 @@ void FindReplaceBar::popup_replace() { selection_only->set_pressed((text_edit->is_selection_active() && text_edit->get_selection_from_line() < text_edit->get_selection_to_line())); - _show_search(); + _show_search(is_visible() || text_edit->is_selection_active()); } void FindReplaceBar::_search_options_changed(bool p_pressed) { + results_count = -1; search_current(); } void FindReplaceBar::_editor_text_changed() { + results_count = -1; if (is_visible_in_tree()) { preserve_cursor = true; search_current(); @@ -427,12 +498,17 @@ void FindReplaceBar::_editor_text_changed() { void FindReplaceBar::_search_text_changed(const String &p_text) { + results_count = -1; search_current(); } void FindReplaceBar::_search_text_entered(const String &p_text) { - search_next(); + if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + search_prev(); + } else { + search_next(); + } } void FindReplaceBar::_replace_text_entered(const String &p_text) { @@ -475,6 +551,7 @@ void FindReplaceBar::set_error(const String &p_label) { void FindReplaceBar::set_text_edit(TextEdit *p_text_edit) { + results_count = -1; text_edit = p_text_edit; text_edit->connect("text_changed", this, "_editor_text_changed"); } @@ -501,11 +578,13 @@ void FindReplaceBar::_bind_methods() { FindReplaceBar::FindReplaceBar() { + results_count = -1; replace_all_mode = false; preserve_cursor = false; vbc_lineedit = memnew(VBoxContainer); add_child(vbc_lineedit); + vbc_lineedit->set_alignment(ALIGN_CENTER); vbc_lineedit->set_h_size_flags(SIZE_EXPAND_FILL); VBoxContainer *vbc_button = memnew(VBoxContainer); add_child(vbc_button); @@ -514,8 +593,10 @@ FindReplaceBar::FindReplaceBar() { HBoxContainer *hbc_button_search = memnew(HBoxContainer); vbc_button->add_child(hbc_button_search); + hbc_button_search->set_alignment(ALIGN_END); hbc_button_replace = memnew(HBoxContainer); vbc_button->add_child(hbc_button_replace); + hbc_button_replace->set_alignment(ALIGN_END); HBoxContainer *hbc_option_search = memnew(HBoxContainer); vbc_option->add_child(hbc_option_search); @@ -529,6 +610,10 @@ FindReplaceBar::FindReplaceBar() { search_text->connect("text_changed", this, "_search_text_changed"); search_text->connect("text_entered", this, "_search_text_entered"); + matches_label = memnew(Label); + hbc_button_search->add_child(matches_label); + matches_label->hide(); + find_prev = memnew(ToolButton); hbc_button_search->add_child(find_prev); find_prev->set_focus_mode(FOCUS_NONE); @@ -582,6 +667,26 @@ FindReplaceBar::FindReplaceBar() { /*** CODE EDITOR ****/ +// This function should be used to handle shortcuts that could otherwise +// be handled too late if they weren't handled here. +void CodeTextEditor::_input(const Ref<InputEvent> &event) { + + const Ref<InputEventKey> key_event = event; + if (!key_event.is_valid() || !key_event->is_pressed()) + return; + + if (ED_IS_SHORTCUT("script_text_editor/move_up", key_event)) { + move_lines_up(); + accept_event(); + return; + } + if (ED_IS_SHORTCUT("script_text_editor/move_down", key_event)) { + move_lines_down(); + accept_event(); + return; + } +} + void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; @@ -649,7 +754,7 @@ void CodeTextEditor::_zoom_changed() { } void CodeTextEditor::_reset_zoom() { - Ref<DynamicFont> font = text_editor->get_font("font"); // reset source font size to default + Ref<DynamicFont> font = text_editor->get_font("font"); // Reset source font size to default. if (font.is_valid()) { EditorSettings::get_singleton()->set("interface/editor/code_font_size", 14); @@ -670,14 +775,14 @@ void CodeTextEditor::_line_col_changed() { } } - StringBuilder *sb = memnew(StringBuilder); - sb->append("("); - sb->append(itos(text_editor->cursor_get_line() + 1).lpad(3)); - sb->append(","); - sb->append(itos(positional_column + 1).lpad(3)); - sb->append(")"); + StringBuilder sb; + sb.append("("); + sb.append(itos(text_editor->cursor_get_line() + 1).lpad(3)); + sb.append(","); + sb.append(itos(positional_column + 1).lpad(3)); + sb.append(")"); - line_and_col_txt->set_text(sb->as_string()); + line_and_col_txt->set_text(sb.as_string()); } void CodeTextEditor::_text_changed() { @@ -697,7 +802,7 @@ void CodeTextEditor::_code_complete_timer_timeout() { void CodeTextEditor::_complete_request() { - List<String> entries; + List<ScriptCodeCompletionOption> entries; String ctext = text_editor->get_text_for_completion(); _code_complete_script(ctext, &entries); bool forced = false; @@ -706,15 +811,55 @@ void CodeTextEditor::_complete_request() { } if (entries.size() == 0) 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(); + for (List<ScriptCodeCompletionOption>::Element *E = entries.front(); E; E = E->next()) { + E->get().icon = _get_completion_icon(E->get()); } + text_editor->code_complete(entries, forced); +} - text_editor->code_complete(strs, forced); +Ref<Texture> CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOption &p_option) { + Ref<Texture> tex; + switch (p_option.kind) { + case ScriptCodeCompletionOption::KIND_CLASS: { + if (has_icon(p_option.display, "EditorIcons")) { + tex = get_icon(p_option.display, "EditorIcons"); + } else { + tex = get_icon("Object", "EditorIcons"); + } + } break; + case ScriptCodeCompletionOption::KIND_ENUM: + tex = get_icon("Enum", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_FILE_PATH: + tex = get_icon("File", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_NODE_PATH: + tex = get_icon("NodePath", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_VARIABLE: + tex = get_icon("Variant", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_CONSTANT: + tex = get_icon("MemberConstant", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_MEMBER: + tex = get_icon("MemberProperty", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_SIGNAL: + tex = get_icon("MemberSignal", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_FUNCTION: + tex = get_icon("MemberMethod", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_PLAIN_TEXT: + tex = get_icon("CubeMesh", "EditorIcons"); + break; + default: + tex = get_icon("String", "EditorIcons"); + break; + } + return tex; } void CodeTextEditor::_font_resize_timeout() { @@ -744,28 +889,33 @@ bool CodeTextEditor::_add_font_size(int p_delta) { void CodeTextEditor::update_editor_settings() { - text_editor->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete")); - text_editor->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file")); + text_editor->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/highlighting/syntax_highlighting")); + text_editor->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_all_occurrences")); + text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line")); text_editor->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/indent/type")); text_editor->set_indent_size(EditorSettings::get_singleton()->get("text_editor/indent/size")); text_editor->set_auto_indent(EditorSettings::get_singleton()->get("text_editor/indent/auto_indent")); text_editor->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/indent/draw_tabs")); - text_editor->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_line_numbers")); - text_editor->set_line_numbers_zero_padded(EditorSettings::get_singleton()->get("text_editor/line_numbers/line_numbers_zero_padded")); - text_editor->set_show_line_length_guideline(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_line_length_guideline")); - text_editor->set_line_length_guideline_column(EditorSettings::get_singleton()->get("text_editor/line_numbers/line_length_guideline_column")); - text_editor->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/highlighting/syntax_highlighting")); - text_editor->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_all_occurrences")); - text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line")); + text_editor->set_draw_spaces(EditorSettings::get_singleton()->get("text_editor/indent/draw_spaces")); + text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/navigation/smooth_scrolling")); + text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/navigation/v_scroll_speed")); + text_editor->set_draw_minimap(EditorSettings::get_singleton()->get("text_editor/navigation/show_minimap")); + text_editor->set_minimap_width(EditorSettings::get_singleton()->get("text_editor/navigation/minimap_width")); + text_editor->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_numbers")); + text_editor->set_line_numbers_zero_padded(EditorSettings::get_singleton()->get("text_editor/appearance/line_numbers_zero_padded")); + text_editor->set_bookmark_gutter_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/show_bookmark_gutter")); + text_editor->set_breakpoint_gutter_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/show_breakpoint_gutter")); + text_editor->set_draw_info_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/show_info_gutter")); + text_editor->set_hiding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding")); + text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding")); + text_editor->set_wrap_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/word_wrap")); + text_editor->set_show_line_length_guideline(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_length_guideline")); + text_editor->set_line_length_guideline_column(EditorSettings::get_singleton()->get("text_editor/appearance/line_length_guideline_column")); + text_editor->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file")); + text_editor->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret")); text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink")); text_editor->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed")); - text_editor->set_breakpoint_gutter_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_breakpoint_gutter")); - text_editor->set_hiding_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding")); - text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding")); - text_editor->set_wrap_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/word_wrap")); - text_editor->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret")); - text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/open_scripts/smooth_scrolling")); - text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/open_scripts/v_scroll_speed")); + text_editor->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete")); } void CodeTextEditor::trim_trailing_whitespace() { @@ -796,6 +946,24 @@ void CodeTextEditor::trim_trailing_whitespace() { } } +void CodeTextEditor::insert_final_newline() { + int final_line = text_editor->get_line_count() - 1; + + String line = text_editor->get_line(final_line); + + //length 0 means it's already an empty line, + //no need to add a newline + if (line.length() > 0 && !line.ends_with("\n")) { + text_editor->begin_complex_operation(); + + line += "\n"; + text_editor->set_line(final_line, line); + + text_editor->end_complex_operation(); + text_editor->update(); + } +} + void CodeTextEditor::convert_indent_to_spaces() { int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); String indent = ""; @@ -904,7 +1072,7 @@ void CodeTextEditor::convert_case(CaseStyle p_case) { for (int i = begin; i <= end; i++) { int len = text_editor->get_line(i).length(); if (i == end) - len -= len - end_col; + len = end_col; if (i == begin) len -= begin_col; String new_line = text_editor->get_line(i).substr(i == begin ? begin_col : 0, len); @@ -1014,6 +1182,19 @@ void CodeTextEditor::move_lines_down() { text_editor->update(); } +void CodeTextEditor::_delete_line(int p_line) { + // this is currently intended to be called within delete_lines() + // so `begin_complex_operation` is ommitted here + text_editor->set_line(p_line, ""); + if (p_line == 0 && text_editor->get_line_count() > 1) { + text_editor->cursor_set_line(1); + text_editor->cursor_set_column(0); + } + text_editor->backspace_at_cursor(); + text_editor->unfold_line(p_line); + text_editor->cursor_set_line(p_line); +} + void CodeTextEditor::delete_lines() { text_editor->begin_complex_operation(); if (text_editor->is_selection_active()) { @@ -1021,22 +1202,13 @@ void CodeTextEditor::delete_lines() { int from_line = text_editor->get_selection_from_line(); int count = Math::abs(to_line - from_line) + 1; - text_editor->cursor_set_line(to_line, false); - while (count) { - text_editor->set_line(text_editor->cursor_get_line(), ""); - text_editor->backspace_at_cursor(); - count--; - if (count) - text_editor->unfold_line(from_line); + text_editor->cursor_set_line(from_line, false); + for (int i = 0; i < count; i++) { + _delete_line(from_line); } - text_editor->cursor_set_line(from_line - 1); text_editor->deselect(); } else { - int line = text_editor->cursor_get_line(); - text_editor->set_line(text_editor->cursor_get_line(), ""); - text_editor->backspace_at_cursor(); - text_editor->unfold_line(line); - text_editor->cursor_set_line(line); + _delete_line(text_editor->cursor_get_line()); } text_editor->end_complex_operation(); } @@ -1098,7 +1270,7 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) { int col_to = text_editor->get_selection_to_column(); int cursor_pos = text_editor->cursor_get_column(); - // Check if all lines in the selected block are commented + // Check if all lines in the selected block are commented. bool is_commented = true; for (int i = begin; i <= end; i++) { if (!text_editor->get_line(i).begins_with(delimiter)) { @@ -1171,21 +1343,82 @@ void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { text_editor->select(p_line, p_begin, p_line, p_end); } +void CodeTextEditor::goto_line_centered(int p_line) { + goto_line(p_line); + text_editor->call_deferred("center_viewport_to_cursor"); +} + +void CodeTextEditor::set_executing_line(int p_line) { + text_editor->set_executing_line(p_line); +} + +void CodeTextEditor::clear_executing_line() { + text_editor->clear_executing_line(); +} + Variant CodeTextEditor::get_edit_state() { Dictionary state; state["scroll_position"] = text_editor->get_v_scroll(); + state["h_scroll_position"] = text_editor->get_h_scroll(); state["column"] = text_editor->cursor_get_column(); state["row"] = text_editor->cursor_get_line(); + state["selection"] = get_text_edit()->is_selection_active(); + if (get_text_edit()->is_selection_active()) { + state["selection_from_line"] = text_editor->get_selection_from_line(); + state["selection_from_column"] = text_editor->get_selection_from_column(); + state["selection_to_line"] = text_editor->get_selection_to_line(); + state["selection_to_column"] = text_editor->get_selection_to_column(); + } + + state["folded_lines"] = text_editor->get_folded_lines(); + state["breakpoints"] = text_editor->get_breakpoints_array(); + state["bookmarks"] = text_editor->get_bookmarks_array(); + + state["syntax_highlighter"] = TTR("Standard"); + SyntaxHighlighter *syntax_highlighter = text_editor->_get_syntax_highlighting(); + if (syntax_highlighter) { + state["syntax_highlighter"] = syntax_highlighter->get_name(); + } + return state; } void CodeTextEditor::set_edit_state(const Variant &p_state) { Dictionary state = p_state; - text_editor->cursor_set_column(state["column"]); + + /* update the row first as it sets the column to 0 */ text_editor->cursor_set_line(state["row"]); + text_editor->cursor_set_column(state["column"]); text_editor->set_v_scroll(state["scroll_position"]); + text_editor->set_h_scroll(state["h_scroll_position"]); + + if (state.has("selection")) { + text_editor->select(state["selection_from_line"], state["selection_from_column"], state["selection_to_line"], state["selection_to_column"]); + } + + if (state.has("folded_lines")) { + Vector<int> folded_lines = state["folded_lines"]; + for (int i = 0; i < folded_lines.size(); i++) { + text_editor->fold_line(folded_lines[i]); + } + } + + if (state.has("breakpoints")) { + Array breakpoints = state["breakpoints"]; + for (int i = 0; i < breakpoints.size(); i++) { + text_editor->set_line_as_breakpoint(breakpoints[i], true); + } + } + + if (state.has("bookmarks")) { + Array bookmarks = state["bookmarks"]; + for (int i = 0; i < bookmarks.size(); i++) { + text_editor->set_line_as_bookmark(bookmarks[i], true); + } + } + text_editor->grab_focus(); } @@ -1216,6 +1449,9 @@ void CodeTextEditor::_update_font() { text_editor->add_font_override("font", get_font("source", "EditorFonts")); + error->add_font_override("font", get_font("status_source", "EditorFonts")); + error->add_color_override("font_color", get_color("error_color", "Editor")); + Ref<Font> status_bar_font = get_font("status_source", "EditorFonts"); error->add_font_override("font", status_bar_font); int count = status_bar->get_child_count(); @@ -1232,25 +1468,30 @@ void CodeTextEditor::_on_settings_change() { font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size"); - // AUTO BRACE COMPLETION + // Auto brace completion. text_editor->set_auto_brace_completion( - EDITOR_DEF("text_editor/completion/auto_brace_complete", true)); + EDITOR_GET("text_editor/completion/auto_brace_complete")); code_complete_timer->set_wait_time( - EDITOR_DEF("text_editor/completion/code_complete_delay", .3f)); + EDITOR_GET("text_editor/completion/code_complete_delay")); - // call hint settings + // Call hint settings. text_editor->set_callhint_settings( - EDITOR_DEF("text_editor/completion/put_callhint_tooltip_below_current_line", true), - EDITOR_DEF("text_editor/completion/callhint_tooltip_offset", Vector2())); + EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"), + EDITOR_GET("text_editor/completion/callhint_tooltip_offset")); + + idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay")); } void CodeTextEditor::_text_changed_idle_timeout() { - _validate_script(); emit_signal("validate_script"); } +void CodeTextEditor::validate_script() { + idle->start(); +} + void CodeTextEditor::_warning_label_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { @@ -1288,6 +1529,9 @@ void CodeTextEditor::_notification(int p_what) { warning_button->set_icon(get_icon("NodeWarning", "EditorIcons")); add_constant_override("separation", 4 * EDSCALE); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + set_process_input(is_visible_in_tree()); + } break; default: break; } @@ -1301,8 +1545,75 @@ void CodeTextEditor::set_warning_nb(int p_warning_nb) { _set_show_warnings_panel(false); } +void CodeTextEditor::toggle_bookmark() { + + int line = text_editor->cursor_get_line(); + text_editor->set_line_as_bookmark(line, !text_editor->is_line_set_as_bookmark(line)); +} + +void CodeTextEditor::goto_next_bookmark() { + + List<int> bmarks; + text_editor->get_bookmarks(&bmarks); + if (bmarks.size() <= 0) { + return; + } + + int line = text_editor->cursor_get_line(); + if (line >= bmarks[bmarks.size() - 1]) { + text_editor->unfold_line(bmarks[0]); + text_editor->cursor_set_line(bmarks[0]); + } else { + for (List<int>::Element *E = bmarks.front(); E; E = E->next()) { + int bline = E->get(); + if (bline > line) { + text_editor->unfold_line(bline); + text_editor->cursor_set_line(bline); + text_editor->center_viewport_to_cursor(); + return; + } + } + } +} + +void CodeTextEditor::goto_prev_bookmark() { + + List<int> bmarks; + text_editor->get_bookmarks(&bmarks); + if (bmarks.size() <= 0) { + return; + } + + int line = text_editor->cursor_get_line(); + if (line <= bmarks[0]) { + text_editor->unfold_line(bmarks[bmarks.size() - 1]); + text_editor->cursor_set_line(bmarks[bmarks.size() - 1]); + } else { + for (List<int>::Element *E = bmarks.back(); E; E = E->prev()) { + int bline = E->get(); + if (bline < line) { + text_editor->unfold_line(bline); + text_editor->cursor_set_line(bline); + text_editor->center_viewport_to_cursor(); + return; + } + } + } +} + +void CodeTextEditor::remove_all_bookmarks() { + + List<int> bmarks; + text_editor->get_bookmarks(&bmarks); + + for (List<int>::Element *E = bmarks.front(); E; E = E->next()) { + text_editor->set_line_as_bookmark(E->get(), false); + } +} + void CodeTextEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_input"), &CodeTextEditor::_input); ClassDB::bind_method("_text_editor_gui_input", &CodeTextEditor::_text_editor_gui_input); ClassDB::bind_method("_line_col_changed", &CodeTextEditor::_line_col_changed); ClassDB::bind_method("_text_changed", &CodeTextEditor::_text_changed); @@ -1357,12 +1668,12 @@ CodeTextEditor::CodeTextEditor() { idle = memnew(Timer); add_child(idle); idle->set_one_shot(true); - idle->set_wait_time(EDITOR_DEF("text_editor/completion/idle_parse_delay", 2)); + idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay")); code_complete_timer = memnew(Timer); add_child(code_complete_timer); code_complete_timer->set_one_shot(true); - code_complete_timer->set_wait_time(EDITOR_DEF("text_editor/completion/code_complete_delay", .3f)); + code_complete_timer->set_wait_time(EDITOR_GET("text_editor/completion/code_complete_delay")); error_line = 0; error_column = 0; @@ -1377,8 +1688,6 @@ CodeTextEditor::CodeTextEditor() { error = memnew(Label); scroll->add_child(error); error->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); - error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); - error->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); error->set_mouse_filter(MOUSE_FILTER_STOP); error->connect("gui_input", this, "_error_pressed"); find_replace_bar->connect("error", error, "set_text"); |