From 7da0767f357540871ace6439e6e371ce3fdb0d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:37:53 +0200 Subject: [PATCH] [TextEdit] Update syntax highlighting when IME composition string is updated. --- doc/classes/TextEdit.xml | 7 ++ .../gdscript/editor/gdscript_highlighter.cpp | 2 +- scene/gui/text_edit.cpp | 76 ++++++++++++------- scene/gui/text_edit.h | 8 +- scene/resources/syntax_highlighter.cpp | 2 +- 5 files changed, 66 insertions(+), 29 deletions(-) diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 7331b5a6812..330ea49292f 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -419,6 +419,13 @@ Returns the width in pixels of the [param wrap_index] on [param line]. + + + + + Returns line text as it is currently displayed, including IME composition string. + + diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index acb74c1a6dc..88e634f425c 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -94,7 +94,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_region = color_region_cache[p_line - 1]; } - const String &str = text_edit->get_line(p_line); + const String &str = text_edit->get_line_with_ime(p_line); const int line_length = str.length(); Color prev_color; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index aa85b3d9cc8..a153e025c4e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -186,7 +186,15 @@ _FORCE_INLINE_ String TextEdit::Text::operator[](int p_line) const { return text[p_line].data; } -void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_changed, const String &p_ime_text, const Array &p_bidi_override) { +_FORCE_INLINE_ const String &TextEdit::Text::get_text_with_ime(int p_line) const { + if (!text[p_line].ime_data.is_empty()) { + return text[p_line].ime_data; + } else { + return text[p_line].data; + } +} + +void TextEdit::Text::invalidate_cache(int p_line, bool p_text_changed) { ERR_FAIL_INDEX(p_line, text.size()); if (font.is_null()) { @@ -209,20 +217,14 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan text_line.data_buf->set_preserve_control(draw_control_chars); text_line.data_buf->set_custom_punctuation(get_enabled_word_separators()); - if (p_ime_text.length() > 0) { - if (p_text_changed) { - text_line.data_buf->add_string(p_ime_text, font, font_size, language); - } - if (!p_bidi_override.is_empty()) { - TS->shaped_text_set_bidi_override(text_line.data_buf->get_rid(), p_bidi_override); - } - } else { - if (p_text_changed) { - text_line.data_buf->add_string(text_line.data, font, font_size, language); - } - if (!text_line.bidi_override.is_empty()) { - TS->shaped_text_set_bidi_override(text_line.data_buf->get_rid(), text_line.bidi_override); - } + const String &text_with_ime = (!text_line.ime_data.is_empty()) ? text_line.ime_data : text_line.data; + const Array &bidi_override_with_ime = (!text_line.ime_data.is_empty()) ? text_line.ime_bidi_override : text_line.bidi_override; + + if (p_text_changed) { + text_line.data_buf->add_string(text_with_ime, font, font_size, language); + } + if (bidi_override_with_ime.is_empty()) { + TS->shaped_text_set_bidi_override(text_line.data_buf->get_rid(), bidi_override_with_ime); } if (!p_text_changed) { @@ -286,7 +288,7 @@ void TextEdit::Text::invalidate_all_lines() { text[i].data_buf->tab_align(tabs); } } - invalidate_cache(i, -1, false); + invalidate_cache(i, false); } tab_size_dirty = false; } @@ -304,7 +306,7 @@ void TextEdit::Text::invalidate_font() { } for (int i = 0; i < text.size(); i++) { - invalidate_cache(i, -1, false); + invalidate_cache(i, false); } is_dirty = false; } @@ -322,7 +324,7 @@ void TextEdit::Text::invalidate_all() { } for (int i = 0; i < text.size(); i++) { - invalidate_cache(i, -1, true); + invalidate_cache(i, true); } is_dirty = false; } @@ -336,9 +338,8 @@ void TextEdit::Text::clear() { Line line; line.gutters.resize(gutter_count); - line.data = ""; text.insert(0, line); - invalidate_cache(0, -1, true); + invalidate_cache(0, true); } int TextEdit::Text::get_total_visible_line_count() const { @@ -349,8 +350,18 @@ void TextEdit::Text::set(int p_line, const String &p_text, const Array &p_bidi_o ERR_FAIL_INDEX(p_line, text.size()); text.write[p_line].data = p_text; + text.write[p_line].ime_data = String(); text.write[p_line].bidi_override = p_bidi_override; - invalidate_cache(p_line, -1, true); + text.write[p_line].ime_bidi_override.clear(); + invalidate_cache(p_line, true); +} + +void TextEdit::Text::set_ime(int p_line, const String &p_text, const Array &p_bidi_override) { + ERR_FAIL_INDEX(p_line, text.size()); + + text.write[p_line].ime_data = p_text; + text.write[p_line].ime_bidi_override = p_bidi_override; + invalidate_cache(p_line, true); } void TextEdit::Text::set_hidden(int p_line, bool p_hidden) { @@ -405,7 +416,7 @@ void TextEdit::Text::insert(int p_at, const Vector &p_text, const Vector line.data = p_text[i]; line.bidi_override = p_bidi_override[i]; text.write[p_at + i] = line; - invalidate_cache(p_at + i, -1, true); + invalidate_cache(p_at + i, true); } } @@ -2967,15 +2978,20 @@ void TextEdit::_update_ime_text() { if (has_ime_text()) { // Update text to visually include IME text. for (int i = 0; i < get_caret_count(); i++) { - String text_with_ime = text[get_caret_line(i)].substr(0, get_caret_column(i)) + ime_text + text[get_caret_line(i)].substr(get_caret_column(i), text[get_caret_line(i)].length()); - text.invalidate_cache(get_caret_line(i), get_caret_column(i), true, text_with_ime, structured_text_parser(st_parser, st_args, text_with_ime)); + int l = get_caret_line(i); + String text_with_ime = text[l].substr(0, get_caret_column(i)) + ime_text + text[l].substr(get_caret_column(i)); + text.set_ime(l, text_with_ime, structured_text_parser(st_parser, st_args, text_with_ime)); + emit_signal(SNAME("lines_edited_from"), l, l); } } else { // Reset text. for (int i = 0; i < get_caret_count(); i++) { - text.invalidate_cache(get_caret_line(i), get_caret_column(i), true); + int l = get_caret_line(i); + text.set_ime(l, String(), Array()); + emit_signal(SNAME("lines_edited_from"), l, l); } } + _clear_syntax_highlighting_cache(); queue_redraw(); } @@ -3513,11 +3529,18 @@ void TextEdit::set_line(int p_line, const String &p_new_text) { String TextEdit::get_line(int p_line) const { if (p_line < 0 || p_line >= text.size()) { - return ""; + return String(); } return text[p_line]; } +String TextEdit::get_line_with_ime(int p_line) const { + if (p_line < 0 || p_line >= text.size()) { + return String(); + } + return text.get_text_with_ime(p_line); +} + int TextEdit::get_line_width(int p_line, int p_wrap_index) const { ERR_FAIL_INDEX_V(p_line, text.size(), 0); ERR_FAIL_COND_V(p_wrap_index > get_line_wrap_count(p_line), 0); @@ -6540,6 +6563,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_line", "line", "new_text"), &TextEdit::set_line); ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line); + ClassDB::bind_method(D_METHOD("get_line_with_ime", "line"), &TextEdit::get_line_with_ime); ClassDB::bind_method(D_METHOD("get_line_width", "line", "wrap_index"), &TextEdit::get_line_width, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_line_height"), &TextEdit::get_line_height); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 44168a8a268..21c8781e264 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -152,6 +152,9 @@ private: Array bidi_override; Ref data_buf; + String ime_data; + Array ime_bidi_override; + Color background_color = Color(0, 0, 0, 0); bool hidden = false; int line_count = 0; @@ -228,6 +231,7 @@ private: const Ref get_line_data(int p_line) const; void set(int p_line, const String &p_text, const Array &p_bidi_override); + void set_ime(int p_line, const String &p_text, const Array &p_bidi_override); void set_hidden(int p_line, bool p_hidden); bool is_hidden(int p_line) const; void insert(int p_at, const Vector &p_text, const Vector &p_bidi_override); @@ -235,12 +239,13 @@ private: int size() const { return text.size(); } void clear(); - void invalidate_cache(int p_line, int p_column = -1, bool p_text_changed = false, const String &p_ime_text = String(), const Array &p_bidi_override = Array()); + void invalidate_cache(int p_line, bool p_text_changed = false); void invalidate_font(); void invalidate_all(); void invalidate_all_lines(); _FORCE_INLINE_ String operator[](int p_line) const; + _FORCE_INLINE_ const String &get_text_with_ime(int p_line) const; /* Gutters. */ void add_gutter(int p_at); @@ -794,6 +799,7 @@ public: void set_line(int p_line, const String &p_new_text); String get_line(int p_line) const; + String get_line_with_ime(int p_line) const; int get_line_width(int p_line, int p_wrap_index = -1) const; int get_line_height() const; diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp index 662bb3d60c9..5a835b64b3c 100644 --- a/scene/resources/syntax_highlighter.cpp +++ b/scene/resources/syntax_highlighter.cpp @@ -144,7 +144,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) { in_region = color_region_cache[p_line - 1]; } - const String &str = text_edit->get_line(p_line); + const String &str = text_edit->get_line_with_ime(p_line); const int line_length = str.length(); Color prev_color;