From 73c92f3a6bf47c44785fd482c2b2b6ce0d394f33 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 21 Jan 2025 11:49:36 +0800 Subject: [PATCH] input: Fix crash cause by incorrect selected range. (#560) The `selected_range` should be UTF-8. --- crates/ui/src/input/input.rs | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/crates/ui/src/input/input.rs b/crates/ui/src/input/input.rs index 8ccc62b3..ddeec59b 100644 --- a/crates/ui/src/input/input.rs +++ b/crates/ui/src/input/input.rs @@ -169,6 +169,10 @@ pub struct TextInput { pub(super) suffix: Option) -> AnyElement + 'static>>, pub(super) loading: bool, pub(super) placeholder: SharedString, + /// Range in UTF-8 length for the selected text. + /// + /// - "Hello δΈ–η•ŒπŸ’" = 16 + /// - "πŸ’" = 4 pub(super) selected_range: Range, /// Range for save the selected word, use to keep word range when drag move. pub(super) selected_word_range: Option>, @@ -609,7 +613,7 @@ impl TextInput { return; } let offset = (self.end_of_line(cx) + 1).min(self.text.len()); - self.select_to(offset, cx); + self.select_to(self.next_boundary(offset), cx); } fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext) { @@ -649,12 +653,12 @@ impl TextInput { fn select_to_start_of_line(&mut self, _: &SelectToStartOfLine, cx: &mut ViewContext) { let offset = self.start_of_line(cx); - self.select_to(offset, cx); + self.select_to(self.previous_boundary(offset), cx); } fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext) { let offset = self.end_of_line(cx); - self.select_to(offset, cx); + self.select_to(self.next_boundary(offset), cx); } /// Get start of line @@ -772,9 +776,9 @@ impl TextInput { } if event.modifiers.shift { - self.select_to(offset, cx); + self.select_to(self.next_boundary(offset), cx); } else { - self.move_to(offset, cx) + self.move_to(self.next_boundary(offset), cx) } } @@ -815,8 +819,7 @@ impl TextInput { return; } - let range = self.range_from_utf16(&self.selected_range); - let selected_text = self.text[range].to_string(); + let selected_text = self.text[self.selected_range.clone()].to_string(); cx.write_to_clipboard(ClipboardItem::new_string(selected_text)); self.replace_text_in_range(None, "", cx); } @@ -873,6 +876,11 @@ impl TextInput { self.history.ignore = false; } + /// Move the cursor to the given offset. + /// + /// The offset is the UTF-8 offset. + /// + /// Ensure the offset use self.next_boundary or self.previous_boundary to get the correct offset. fn move_to(&mut self, offset: usize, cx: &mut ViewContext) { self.selected_range = offset..offset; self.pause_blink_cursor(cx); @@ -980,6 +988,11 @@ impl TextInput { } } + /// Select the text from the current cursor position to the given offset. + /// + /// The offset is the UTF-8 offset. + /// + /// Ensure the offset use self.next_boundary or self.previous_boundary to get the correct offset. fn select_to(&mut self, offset: usize, cx: &mut ViewContext) { if self.selection_reversed { self.selected_range.start = offset @@ -1008,6 +1021,8 @@ impl TextInput { } /// Select the word at the given offset. + /// + /// The offset is the UTF-8 offset. fn select_word(&mut self, offset: usize, cx: &mut ViewContext) { fn is_word(c: char) -> bool { c.is_alphanumeric() || matches!(c, '_') @@ -1047,7 +1062,8 @@ impl TextInput { } fn unselect(&mut self, cx: &mut ViewContext) { - self.selected_range = self.cursor_offset()..self.cursor_offset(); + let offset = self.next_boundary(self.cursor_offset()); + self.selected_range = offset..offset; cx.notify() } @@ -1152,7 +1168,7 @@ impl TextInput { } let offset = self.index_for_mouse_position(event.position, cx); - self.select_to(offset, cx); + self.select_to(self.next_boundary(offset), cx); } fn is_valid_input(&self, new_text: &str) -> bool {