diff --git a/src/cursor.rs b/src/cursor.rs index d257f82..8219f6b 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -6,6 +6,8 @@ pub enum CursorMove { Down, Head, End, + Top, + Bottom, } impl CursorMove { @@ -14,6 +16,15 @@ impl CursorMove { (row, col): (usize, usize), lines: &[String], ) -> Option<(usize, usize)> { + fn fit_col(col: usize, line: &str) -> usize { + let end = line.chars().count(); + if end <= col { + end - 1 + } else { + col + } + } + match self { CursorMove::Forward if col + 1 >= lines[row].chars().count() => { if row + 1 < lines.len() { @@ -32,25 +43,16 @@ impl CursorMove { } CursorMove::Back => Some((row, col - 1)), CursorMove::Up if row == 0 => None, - CursorMove::Up => { - let mut col = col; - let end = lines[row - 1].chars().count(); - if end <= col { - col = end - 1; - } - Some((row - 1, col)) - } + CursorMove::Up => Some((row - 1, fit_col(col, &lines[row - 1]))), CursorMove::Down if row + 1 >= lines.len() => None, - CursorMove::Down => { - let mut col = col; - let end = lines[row + 1].chars().count(); - if end <= col { - col = end - 1; - } - Some((row + 1, col)) - } + CursorMove::Down => (Some((row + 1, fit_col(col, &lines[row + 1])))), CursorMove::Head => Some((row, 0)), CursorMove::End => Some((row, lines[row].chars().count() - 1)), + CursorMove::Top => Some((0, fit_col(col, &lines[0]))), + CursorMove::Bottom => { + let row = lines.len() - 1; + Some((row, fit_col(col, &lines[row]))) + } } } } diff --git a/src/input.rs b/src/input.rs index 029cfb3..a708706 100644 --- a/src/input.rs +++ b/src/input.rs @@ -20,6 +20,7 @@ pub enum Key { pub struct Input { pub key: Key, pub ctrl: bool, + pub alt: bool, } impl Default for Input { @@ -27,6 +28,7 @@ impl Default for Input { Input { key: Key::Null, ctrl: false, + alt: false, } } } @@ -44,6 +46,7 @@ impl From for Input { impl From for Input { fn from(key: KeyEvent) -> Self { let ctrl = key.modifiers.contains(KeyModifiers::CONTROL); + let alt = key.modifiers.contains(KeyModifiers::ALT); let key = match key.code { KeyCode::Char(c) => Key::Char(c), KeyCode::Backspace => Key::Backspace, @@ -58,6 +61,6 @@ impl From for Input { KeyCode::End => Key::End, _ => Key::Null, }; - Self { key, ctrl } + Self { key, ctrl, alt } } } diff --git a/src/textarea.rs b/src/textarea.rs index 9113d9f..eedfc75 100644 --- a/src/textarea.rs +++ b/src/textarea.rs @@ -38,34 +38,127 @@ impl<'a> Default for TextArea<'a> { impl<'a> TextArea<'a> { pub fn input(&mut self, input: impl Into) { let input = input.into(); - if input.ctrl { - match input.key { - Key::Char('h') => self.delete_char(), - Key::Char('m') => self.insert_newline(), - Key::Char('p') => self.move_cursor(CursorMove::Up), - Key::Char('f') => self.move_cursor(CursorMove::Forward), - Key::Char('n') => self.move_cursor(CursorMove::Down), - Key::Char('b') => self.move_cursor(CursorMove::Back), - Key::Char('a') => self.move_cursor(CursorMove::Head), - Key::Char('e') => self.move_cursor(CursorMove::End), - Key::Char('u') => self.undo(), - Key::Char('r') => self.redo(), - _ => {} + match input { + Input { + key: Key::Char(c), + ctrl: false, + alt: false, + } => self.insert_char(c), + Input { + key: Key::Tab, + ctrl: false, + alt: false, + } => self.insert_tab(), + Input { + key: Key::Char('h'), + ctrl: true, + alt: false, } - } else { - match input.key { - Key::Char(c) => self.insert_char(c), - Key::Backspace => self.delete_char(), - Key::Tab => self.insert_tab(), - Key::Enter => self.insert_newline(), - Key::Up => self.move_cursor(CursorMove::Up), - Key::Right => self.move_cursor(CursorMove::Forward), - Key::Down => self.move_cursor(CursorMove::Down), - Key::Left => self.move_cursor(CursorMove::Back), - Key::Home => self.move_cursor(CursorMove::Head), - Key::End => self.move_cursor(CursorMove::End), - _ => {} + | Input { + key: Key::Backspace, + .. + } => self.delete_char(), + Input { + key: Key::Char('m'), + ctrl: true, + alt: false, } + | Input { + key: Key::Enter, .. + } => self.insert_newline(), + Input { + key: Key::Char('n'), + ctrl: true, + alt: false, + } + | Input { + key: Key::Down, + ctrl: false, + alt: false, + } => self.move_cursor(CursorMove::Down), + Input { + key: Key::Char('p'), + ctrl: true, + alt: false, + } + | Input { + key: Key::Up, + ctrl: false, + alt: false, + } => self.move_cursor(CursorMove::Up), + Input { + key: Key::Char('f'), + ctrl: true, + alt: false, + } + | Input { + key: Key::Right, + ctrl: false, + alt: false, + } => self.move_cursor(CursorMove::Forward), + Input { + key: Key::Char('b'), + ctrl: true, + alt: false, + } + | Input { + key: Key::Left, + ctrl: false, + alt: false, + } => self.move_cursor(CursorMove::Back), + Input { + key: Key::Char('a'), + ctrl: true, + alt: false, + } + | Input { key: Key::Home, .. } + | Input { + key: Key::Left | Key::Char('b'), + ctrl: true, + alt: true, + } => self.move_cursor(CursorMove::Head), + Input { + key: Key::Char('e'), + ctrl: true, + alt: false, + } + | Input { key: Key::End, .. } + | Input { + key: Key::Right | Key::Char('f'), + ctrl: true, + alt: true, + } => self.move_cursor(CursorMove::End), + Input { + key: Key::Char('<'), + ctrl: false, + alt: true, + } + | Input { + key: Key::Up | Key::Char('p'), + ctrl: true, + alt: true, + } => self.move_cursor(CursorMove::Top), + Input { + key: Key::Char('>'), + ctrl: false, + alt: true, + } + | Input { + key: Key::Down | Key::Char('n'), + ctrl: true, + alt: true, + } => self.move_cursor(CursorMove::Bottom), + Input { + key: Key::Char('u'), + ctrl: true, + alt: false, + } => self.undo(), + Input { + key: Key::Char('r'), + ctrl: true, + alt: false, + } => self.redo(), + _ => {} } // Check invariants