diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 3b52ae567a..8cfff6b35f 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -59,34 +59,6 @@ static _FORCE_INLINE_ char32_t lower_case(char32_t c) { return (is_ascii_upper_case(c) ? (c + ('a' - 'A')) : c); } -bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) { - const String &s = p_s; - int beg = CLAMP(p_col, 0, s.length()); - int end = beg; - - if (s[beg] > 32 || beg == s.length()) { - bool symbol = beg < s.length() && is_symbol(s[beg]); - - while (beg > 0 && s[beg - 1] > 32 && (symbol == is_symbol(s[beg - 1]))) { - beg--; - } - while (end < s.length() && s[end + 1] > 32 && (symbol == is_symbol(s[end + 1]))) { - end++; - } - - if (end < s.length()) { - end += 1; - } - - r_beg = beg; - r_end = end; - - return true; - } else { - return false; - } -} - Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path, String &r_fragment) const { // Splits the URL into scheme, host, port, path, fragment. Strip credentials when present. String base = *this; diff --git a/core/string/ustring.h b/core/string/ustring.h index 505f94a112..9bcc68064f 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -787,8 +787,6 @@ _FORCE_INLINE_ String ETRN(const String &p_text, const String &p_text_plural, in return p_text_plural; } -bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end); - template _FORCE_INLINE_ Vector sarray(P... p_args) { return Vector({ String(p_args)... }); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 7aec88f1e8..d8dfd40add 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -2410,7 +2410,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref &ev) { } } - String word_at_pos = tx->get_word_at_pos(local_pos); + String word_at_pos = tx->get_lookup_word(mouse_line, mouse_column); if (word_at_pos.is_empty()) { word_at_pos = tx->get_word_under_caret(selection_clicked); } diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index fa650b559f..2b42ce8888 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -443,7 +443,7 @@ void CodeEdit::gui_input(const Ref &p_gui_input) { if (symbol_lookup_on_click_enabled) { if (mm->is_command_or_control_pressed() && mm->get_button_mask().is_empty()) { symbol_lookup_pos = get_line_column_at_pos(mpos, false, false); - symbol_lookup_new_word = get_word_at_pos(mpos); + symbol_lookup_new_word = get_lookup_word(symbol_lookup_pos.y, symbol_lookup_pos.x); if (symbol_lookup_new_word != symbol_lookup_word) { emit_signal(SNAME("symbol_validate"), symbol_lookup_new_word); } @@ -454,7 +454,7 @@ void CodeEdit::gui_input(const Ref &p_gui_input) { if (symbol_tooltip_on_hover_enabled) { symbol_tooltip_pos = get_line_column_at_pos(mpos, false, false); - symbol_tooltip_word = get_word_at_pos(mpos); + symbol_tooltip_word = get_lookup_word(symbol_tooltip_pos.y, symbol_tooltip_pos.x); symbol_tooltip_timer->start(); } @@ -499,7 +499,8 @@ void CodeEdit::gui_input(const Ref &p_gui_input) { if ((mac_keys && k->get_keycode() == Key::META) || (!mac_keys && k->get_keycode() == Key::CTRL)) { if (symbol_lookup_on_click_enabled) { if (k->is_pressed() && !is_dragging_cursor()) { - symbol_lookup_new_word = get_word_at_pos(get_local_mouse_pos()); + Point2i lookup_pos = get_line_column_at_pos(get_local_mouse_pos(), false, false); + symbol_lookup_new_word = get_lookup_word(lookup_pos.y, lookup_pos.x); if (symbol_lookup_new_word != symbol_lookup_word) { emit_signal(SNAME("symbol_validate"), symbol_lookup_new_word); } @@ -2483,6 +2484,25 @@ String CodeEdit::get_text_with_cursor_char(int p_line, int p_column) const { return result.as_string(); } +String CodeEdit::get_lookup_word(int p_line, int p_column) const { + if (p_line < 0 || p_column < 0) { + return String(); + } + if (is_in_string(p_line, p_column) != -1) { + // Return the string in case it is a path. + Point2 start_pos = get_delimiter_start_position(p_line, p_column); + Point2 end_pos = get_delimiter_end_position(p_line, p_column); + int start_line = start_pos.y; + int start_column = start_pos.x; + int end_line = end_pos.y; + int end_column = end_pos.x; + if (start_line == end_line && start_column >= 0 && end_column >= 0) { + return get_line(start_line).substr(start_column, end_column - start_column - 1); + } + } + return get_word(p_line, p_column); +} + void CodeEdit::set_symbol_lookup_word_as_valid(bool p_valid) { symbol_lookup_word = p_valid ? symbol_lookup_new_word : ""; symbol_lookup_new_word = ""; @@ -2506,7 +2526,7 @@ bool CodeEdit::is_symbol_tooltip_on_hover_enabled() const { void CodeEdit::_on_symbol_tooltip_timer_timeout() { const int line = symbol_tooltip_pos.y; const int column = symbol_tooltip_pos.x; - if (line >= 0 && column >= 0 && !symbol_tooltip_word.is_empty() && !has_selection() && !Input::get_singleton()->is_anything_pressed()) { + if (line >= 0 && column >= 0 && !symbol_tooltip_word.is_empty() && !Input::get_singleton()->is_anything_pressed()) { emit_signal(SNAME("symbol_hovered"), symbol_tooltip_word, line, column); } } diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h index af9e82150c..744fbf7f03 100644 --- a/scene/gui/code_edit.h +++ b/scene/gui/code_edit.h @@ -504,6 +504,7 @@ public: String get_text_for_symbol_lookup() const; String get_text_with_cursor_char(int p_line, int p_column) const; + String get_lookup_word(int p_line, int p_column) const; void set_symbol_lookup_word_as_valid(bool p_valid); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 23c7452243..e3645492d9 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3633,22 +3633,24 @@ String TextEdit::get_tooltip(const Point2 &p_pos) const { return Control::get_tooltip(p_pos); } Point2i pos = get_line_column_at_pos(p_pos); - int row = pos.y; + int line = pos.y; int col = pos.x; - String s = text[row]; - if (s.length() == 0) { + const String &text_line = text[line]; + if (text_line.is_empty()) { return Control::get_tooltip(p_pos); } - int beg, end; - if (select_word(s, col, beg, end)) { - Variant args[1] = { s.substr(beg, end - beg) }; - const Variant *argp[] = { &args[0] }; - Callable::CallError ce; - Variant ret; - tooltip_callback.callp(argp, 1, ret, ce); - ERR_FAIL_COND_V_MSG(ce.error != Callable::CallError::CALL_OK, "", "Failed to call custom tooltip."); - return ret; + const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); + for (int i = 0; i < words.size(); i = i + 2) { + if (words[i] <= col && words[i + 1] >= col) { + Variant args[1] = { text_line.substr(words[i], words[i + 1] - words[i]) }; + const Variant *argp[] = { &args[0] }; + Callable::CallError ce; + Variant ret; + tooltip_callback.callp(argp, 1, ret, ce); + ERR_FAIL_COND_V_MSG(ce.error != Callable::CallError::CALL_OK, "", "Failed to call custom tooltip."); + return ret; + } } return Control::get_tooltip(p_pos); @@ -4924,43 +4926,29 @@ Point2 TextEdit::get_local_mouse_pos() const { String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { Point2i pos = get_line_column_at_pos(p_pos, false, false); - int row = pos.y; + int line = pos.y; int col = pos.x; - if (row < 0 || col < 0) { - return ""; - } + return get_word(line, col); +} - String s = text[row]; - if (s.length() == 0) { - return ""; +String TextEdit::get_word(int p_line, int p_column) const { + if (p_line < 0 || p_column < 0) { + return String(); } - int beg, end; - if (select_word(s, col, beg, end)) { - bool inside_quotes = false; - char32_t selected_quote = '\0'; - int qbegin = 0, qend = 0; - for (int i = 0; i < s.length(); i++) { - if (s[i] == '"' || s[i] == '\'') { - if (i == 0 || s[i - 1] != '\\') { - if (inside_quotes && selected_quote == s[i]) { - qend = i; - inside_quotes = false; - selected_quote = '\0'; - if (col >= qbegin && col <= qend) { - return s.substr(qbegin, qend - qbegin); - } - } else if (!inside_quotes) { - qbegin = i + 1; - inside_quotes = true; - selected_quote = s[i]; - } - } - } + ERR_FAIL_INDEX_V(p_line, text.size(), String()); + + const String &text_line = text[p_line]; + if (text_line.is_empty()) { + return String(); + } + ERR_FAIL_INDEX_V(p_column, text_line.size() + 1, String()); + + const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(p_line)->get_rid()); + for (int i = 0; i < words.size(); i = i + 2) { + if (words[i] <= p_column && words[i + 1] >= p_column) { + return text_line.substr(words[i], words[i + 1] - words[i]); } - - return s.substr(beg, end - beg); } - return String(); } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index e7a926698a..b0a5f1b291 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -919,6 +919,7 @@ public: Point2 get_local_mouse_pos() const; String get_word_at_pos(const Vector2 &p_pos) const; + String get_word(int p_line, int p_column) const; Point2i get_line_column_at_pos(const Point2i &p_pos, bool p_clamp_line = true, bool p_clamp_column = true) const; Point2i get_pos_at_line_column(int p_line, int p_column) const;