From 94e6cdefda1bd4481b63602645b3aee451f2ae2f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 12 Dec 2023 10:29:14 -0700 Subject: [PATCH] Add select by word and double/triple click actions --- src/edit/editor.rs | 40 ++++++++++++++++++++++++++++------ src/edit/mod.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++ src/edit/vi.rs | 2 +- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/edit/editor.rs b/src/edit/editor.rs index fd468c301e..621790e2ce 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -704,12 +704,9 @@ impl Edit for Editor { // Adjust selection match self.selection { Selection::None => {} - Selection::Normal(ref mut select) => { - if select.line == line_i && select.index >= after_whitespace { - select.index += required_indent; - } - } - Selection::Line(ref mut select) => { + Selection::Normal(ref mut select) + | Selection::Line(ref mut select) + | Selection::Word(ref mut select) => { if select.line == line_i && select.index >= after_whitespace { select.index += required_indent; } @@ -768,7 +765,9 @@ impl Edit for Editor { // Adjust selection match self.selection { Selection::None => {} - Selection::Normal(ref mut select) | Selection::Line(ref mut select) => { + Selection::Normal(ref mut select) + | Selection::Line(ref mut select) + | Selection::Word(ref mut select) => { if select.line == line_i && select.index > last_indent { select.index -= after_whitespace - last_indent; } @@ -791,6 +790,33 @@ impl Edit for Editor { } } } + Action::DoubleClick { x, y } => { + self.set_selection(Selection::None); + + if let Some(new_cursor) = self.buffer.hit(x as f32, y as f32) { + if new_cursor != self.cursor { + let color = self.cursor.color; + self.cursor = new_cursor; + self.cursor.color = color; + self.buffer.set_redraw(true); + } + self.selection = Selection::Word(self.cursor); + self.buffer.set_redraw(true); + } + } + Action::TripleClick { x, y } => { + self.set_selection(Selection::None); + + if let Some(new_cursor) = self.buffer.hit(x as f32, y as f32) { + if new_cursor != self.cursor { + let color = self.cursor.color; + self.cursor = new_cursor; + self.cursor.color = color; + } + self.selection = Selection::Line(self.cursor); + self.buffer.set_redraw(true); + } + } Action::Drag { x, y } => { if self.selection == Selection::None { self.selection = Selection::Normal(self.cursor); diff --git a/src/edit/mod.rs b/src/edit/mod.rs index 89353cde04..4975bfebad 100644 --- a/src/edit/mod.rs +++ b/src/edit/mod.rs @@ -1,6 +1,7 @@ #[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec}; use core::cmp; +use unicode_segmentation::UnicodeSegmentation; #[cfg(feature = "swash")] use crate::Color; @@ -69,6 +70,16 @@ pub enum Action { x: i32, y: i32, }, + /// Mouse double click at specified position + DoubleClick { + x: i32, + y: i32, + }, + /// Mouse triple click at specified position + TripleClick { + x: i32, + y: i32, + }, /// Mouse drag to specified position Drag { x: i32, @@ -140,6 +151,8 @@ pub enum Selection { Normal(Cursor), /// Select by lines Line(Cursor), + /// Select by words + Word(Cursor), //TODO: Select block } @@ -202,6 +215,46 @@ pub trait Edit { let end_index = self.buffer().lines[end_line].text().len(); Some((Cursor::new(start_line, 0), Cursor::new(end_line, end_index))) } + Selection::Word(select) => { + let (mut start, mut end) = match select.line.cmp(&cursor.line) { + cmp::Ordering::Greater => (cursor, select), + cmp::Ordering::Less => (select, cursor), + cmp::Ordering::Equal => { + /* select.line == cursor.line */ + if select.index < cursor.index { + (select, cursor) + } else { + /* select.index >= cursor.index */ + (cursor, select) + } + } + }; + + // Move start to beginning of word + { + let line = &self.buffer().lines[start.line]; + start.index = line + .text() + .unicode_word_indices() + .rev() + .map(|(i, _)| i) + .find(|&i| i < start.index) + .unwrap_or(0); + } + + // Move end to end of word + { + let line = &self.buffer().lines[end.line]; + end.index = line + .text() + .unicode_word_indices() + .map(|(i, word)| i + word.len()) + .find(|&i| i > end.index) + .unwrap_or(line.text().len()); + } + + Some((start, end)) + } } } diff --git a/src/edit/vi.rs b/src/edit/vi.rs index b4ffd858e6..abaaf679fa 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -413,7 +413,7 @@ impl<'a> Edit for ViEditor<'a> { editor.insert_string(data, None); } else { match selection { - Selection::Normal(_) | Selection::None => { + Selection::None | Selection::Normal(_) | Selection::Word(_) => { let mut cursor = editor.cursor(); if after { let buffer = editor.buffer();