diff --git a/src/ui/util.rs b/src/ui/util.rs index 67e258f..402372f 100644 --- a/src/ui/util.rs +++ b/src/ui/util.rs @@ -54,6 +54,8 @@ pub fn list_editor_key_bindings( // Cursor movement bindings.binding("ctrl+b, ←", "move cursor left"); bindings.binding("ctrl+f, →", "move cursor right"); + bindings.binding("alt+b, ctrl+←", "move cursor left a word"); + bindings.binding("alt+f, ctrl+→", "move cursor right a word"); bindings.binding("ctrl+a, home", "move cursor to start of line"); bindings.binding("ctrl+e, end", "move cursor to end of line"); bindings.binding("↑/↓", "move cursor up/down"); @@ -86,6 +88,8 @@ pub fn handle_editor_key_event( // Cursor movement key!(Ctrl + 'b') | key!(Left) => editor.move_cursor_left(terminal.frame()), key!(Ctrl + 'f') | key!(Right) => editor.move_cursor_right(terminal.frame()), + key!(Alt + 'b') | key!(Ctrl + Left) => editor.move_cursor_left_a_word(terminal.frame()), + key!(Alt + 'f') | key!(Ctrl + Right) => editor.move_cursor_right_a_word(terminal.frame()), key!(Ctrl + 'a') | key!(Home) => editor.move_cursor_to_start_of_line(terminal.frame()), key!(Ctrl + 'e') | key!(End) => editor.move_cursor_to_end_of_line(terminal.frame()), key!(Up) => editor.move_cursor_up(terminal.frame()), diff --git a/src/ui/widgets/editor.rs b/src/ui/widgets/editor.rs index 20f4a38..cae62ca 100644 --- a/src/ui/widgets/editor.rs +++ b/src/ui/widgets/editor.rs @@ -237,6 +237,42 @@ impl InnerEditorState { } } + fn move_cursor_left_a_word(&mut self, frame: &mut Frame) { + let boundaries = self.grapheme_boundaries(); + let mut encountered_word = false; + for (start, end) in boundaries.iter().zip(boundaries.iter().skip(1)).rev() { + if *end == self.idx { + let g = &self.text[*start..*end]; + let whitespace = g.chars().all(|c| c.is_whitespace()); + if encountered_word && whitespace { + break; + } else if !whitespace { + encountered_word = true; + } + self.idx = *start; + } + } + self.record_cursor_col(frame); + } + + fn move_cursor_right_a_word(&mut self, frame: &mut Frame) { + let boundaries = self.grapheme_boundaries(); + let mut encountered_word = false; + for (start, end) in boundaries.iter().zip(boundaries.iter().skip(1)) { + if *start == self.idx { + let g = &self.text[*start..*end]; + let whitespace = g.chars().all(|c| c.is_whitespace()); + if encountered_word && whitespace { + break; + } else if !whitespace { + encountered_word = true; + } + self.idx = *end; + } + } + self.record_cursor_col(frame); + } + fn move_cursor_to_start_of_line(&mut self, frame: &mut Frame) { let boundaries = self.line_boundaries(); let (line, _, _) = self.cursor_line(&boundaries); @@ -329,6 +365,14 @@ impl EditorState { self.0.lock().move_cursor_right(frame); } + pub fn move_cursor_left_a_word(&self, frame: &mut Frame) { + self.0.lock().move_cursor_left_a_word(frame); + } + + pub fn move_cursor_right_a_word(&self, frame: &mut Frame) { + self.0.lock().move_cursor_right_a_word(frame); + } + pub fn move_cursor_to_start_of_line(&self, frame: &mut Frame) { self.0.lock().move_cursor_to_start_of_line(frame); }