From 56885e5badb4381402c02e735aa98b3f1105c98d Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Mon, 27 May 2019 09:18:36 -0700 Subject: [PATCH] lineedit: add word movement commands --- termwiz/src/lineedit/actions.rs | 2 + termwiz/src/lineedit/mod.rs | 80 +++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/termwiz/src/lineedit/actions.rs b/termwiz/src/lineedit/actions.rs index 8734b9edb..0df78e79d 100644 --- a/termwiz/src/lineedit/actions.rs +++ b/termwiz/src/lineedit/actions.rs @@ -3,7 +3,9 @@ pub type RepeatCount = usize; #[derive(Debug, Clone, Copy)] pub enum Movement { BackwardChar(RepeatCount), + BackwardWord(RepeatCount), ForwardChar(RepeatCount), + ForwardWord(RepeatCount), StartOfLine, EndOfLine, } diff --git a/termwiz/src/lineedit/mod.rs b/termwiz/src/lineedit/mod.rs index b1e1db97e..7259019b7 100644 --- a/termwiz/src/lineedit/mod.rs +++ b/termwiz/src/lineedit/mod.rs @@ -29,6 +29,8 @@ //! Ctrl-J, Ctrl-M, Enter | Finish line editing and accept the current line //! Ctrl-K | Delete from cursor to end of line //! Ctrl-L | Move the cursor to the top left, clear screen and repaint +//! Alt-b, Alt-Left | Move the cursor backwards one word +//! Alt-f, Alt-Right | Move the cursor forwards one word use crate::caps::{Capabilities, ProbeHintsBuilder}; use crate::input::{InputEvent, KeyCode, KeyEvent, Modifiers}; use crate::surface::{Change, Position}; @@ -157,6 +159,25 @@ impl LineEditor { key: KeyCode::LeftArrow, modifiers: Modifiers::NONE, }) => Some(Action::Move(Movement::BackwardChar(1))), + + InputEvent::Key(KeyEvent { + key: KeyCode::Char('b'), + modifiers: Modifiers::ALT, + }) + | InputEvent::Key(KeyEvent { + key: KeyCode::LeftArrow, + modifiers: Modifiers::ALT, + }) => Some(Action::Move(Movement::BackwardWord(1))), + + InputEvent::Key(KeyEvent { + key: KeyCode::Char('f'), + modifiers: Modifiers::ALT, + }) + | InputEvent::Key(KeyEvent { + key: KeyCode::RightArrow, + modifiers: Modifiers::ALT, + }) => Some(Action::Move(Movement::ForwardWord(1))), + InputEvent::Key(KeyEvent { key: KeyCode::Char('A'), modifiers: Modifiers::CTRL, @@ -213,6 +234,65 @@ impl LineEditor { } position } + Movement::BackwardWord(rep) => { + let char_indices: Vec<(usize, char)> = self.line.char_indices().collect(); + if char_indices.is_empty() { + return self.cursor; + } + let mut char_position = char_indices + .iter() + .position(|(idx, _)| *idx == self.cursor) + .unwrap_or(char_indices.len() - 1); + + for _ in 0..rep { + if char_position == 0 { + break; + } + + let mut found = None; + for prev in (0..char_position - 1).rev() { + if char_indices[prev].1.is_whitespace() { + found = Some(prev + 1); + break; + } + } + + char_position = found.unwrap_or(0); + } + char_indices[char_position].0 + } + Movement::ForwardWord(rep) => { + let char_indices: Vec<(usize, char)> = self.line.char_indices().collect(); + if char_indices.is_empty() { + return self.cursor; + } + let mut char_position = char_indices + .iter() + .position(|(idx, _)| *idx == self.cursor) + .unwrap_or(char_indices.len()); + + for _ in 0..rep { + // Skip any non-whitespace characters + while char_position < char_indices.len() + && !char_indices[char_position].1.is_whitespace() + { + char_position += 1; + } + + // Skip any whitespace characters + while char_position < char_indices.len() + && char_indices[char_position].1.is_whitespace() + { + char_position += 1; + } + + // We are now on the start of the next word + } + char_indices + .get(char_position) + .map(|(i, _)| *i) + .unwrap_or(self.line.len()) + } Movement::ForwardChar(rep) => { let mut position = self.cursor; for _ in 0..rep {