Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TextEdit] Update syntax highlighting when IME composition string is updated. #102472

Merged
merged 1 commit into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/classes/TextEdit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,13 @@
Returns the width in pixels of the [param wrap_index] on [param line].
</description>
</method>
<method name="get_line_with_ime" qualifiers="const">
<return type="String" />
<param index="0" name="line" type="int" />
<description>
Returns line text as it is currently displayed, including IME composition string.
</description>
</method>
<method name="get_line_wrap_count" qualifiers="const">
<return type="int" />
<param index="0" name="line" type="int" />
Expand Down
2 changes: 1 addition & 1 deletion modules/gdscript/editor/gdscript_highlighter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
76 changes: 50 additions & 26 deletions scene/gui/text_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -405,7 +416,7 @@ void TextEdit::Text::insert(int p_at, const Vector<String> &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);
}
}

Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 7 additions & 1 deletion scene/gui/text_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ class TextEdit : public Control {
Array bidi_override;
Ref<TextParagraph> data_buf;

String ime_data;
Array ime_bidi_override;

Color background_color = Color(0, 0, 0, 0);
bool hidden = false;
int line_count = 0;
Expand Down Expand Up @@ -228,19 +231,21 @@ class TextEdit : public Control {
const Ref<TextParagraph> 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<String> &p_text, const Vector<Array> &p_bidi_override);
void remove_range(int p_from_line, int p_to_line);
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);
Expand Down Expand Up @@ -794,6 +799,7 @@ class TextEdit : public Control {

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;
Expand Down
2 changes: 1 addition & 1 deletion scene/resources/syntax_highlighter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading