diff --git a/src/cursor.rs b/src/cursor.rs new file mode 100644 index 0000000..d257f82 --- /dev/null +++ b/src/cursor.rs @@ -0,0 +1,56 @@ +#[derive(Clone, Copy, Debug)] +pub enum CursorMove { + Forward, + Back, + Up, + Down, + Head, + End, +} + +impl CursorMove { + pub fn next_cursor( + &self, + (row, col): (usize, usize), + lines: &[String], + ) -> Option<(usize, usize)> { + match self { + CursorMove::Forward if col + 1 >= lines[row].chars().count() => { + if row + 1 < lines.len() { + Some((row + 1, 0)) + } else { + None + } + } + CursorMove::Forward => Some((row, col + 1)), + CursorMove::Back if col == 0 => { + if row > 0 { + Some((row - 1, lines[row - 1].chars().count() - 1)) + } else { + None + } + } + 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::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::Head => Some((row, 0)), + CursorMove::End => Some((row, lines[row].chars().count() - 1)), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 6990d0c..a1d3bd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ +mod cursor; mod edit; mod history; mod input; mod textarea; +pub use cursor::CursorMove; pub use input::{Input, Key}; pub use textarea::TextArea; diff --git a/src/textarea.rs b/src/textarea.rs index adedb44..5fa0b06 100644 --- a/src/textarea.rs +++ b/src/textarea.rs @@ -1,3 +1,4 @@ +use crate::cursor::CursorMove; use crate::edit::{Edit, EditKind}; use crate::history::EditHistory; use crate::input::{Input, Key}; @@ -34,12 +35,12 @@ impl<'a> TextArea<'a> { match input.key { Key::Char('h') => self.delete_char(), Key::Char('m') => self.insert_newline(), - Key::Char('p') => self.cursor_up(), - Key::Char('f') => self.cursor_forward(), - Key::Char('n') => self.cursor_down(), - Key::Char('b') => self.cursor_back(), - Key::Char('a') => self.cursor_start(), - Key::Char('e') => self.cursor_end(), + 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(), _ => {} @@ -50,12 +51,12 @@ impl<'a> TextArea<'a> { Key::Backspace => self.delete_char(), Key::Tab => self.insert_tab(), Key::Enter => self.insert_newline(), - Key::Up => self.cursor_up(), - Key::Right => self.cursor_forward(), - Key::Down => self.cursor_down(), - Key::Left => self.cursor_back(), - Key::Home => self.cursor_start(), - Key::End => self.cursor_end(), + 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), _ => {} } } @@ -165,60 +166,12 @@ impl<'a> TextArea<'a> { } } - pub fn cursor_forward(&mut self) { - let (r, c) = self.cursor; - if c + 1 >= self.lines[r].chars().count() { - if r + 1 < self.lines.len() { - self.cursor = (r + 1, 0); - } - } else { - self.cursor.1 += 1; + pub fn move_cursor(&mut self, m: CursorMove) { + if let Some(cursor) = m.next_cursor(self.cursor, &self.lines) { + self.cursor = cursor; } } - pub fn cursor_back(&mut self) { - let (r, c) = self.cursor; - if c == 0 { - if r > 0 { - self.cursor = (r - 1, self.lines[r - 1].chars().count() - 1); - } - } else { - self.cursor.1 -= 1; - } - } - - pub fn cursor_down(&mut self) { - let (r, c) = self.cursor; - if r + 1 >= self.lines.len() { - return; - } - self.cursor.0 += 1; - let len = self.lines[r + 1].chars().count(); - if len <= c { - self.cursor.1 = len - 1; - } - } - - pub fn cursor_up(&mut self) { - let (r, c) = self.cursor; - if r == 0 { - return; - } - self.cursor.0 -= 1; - let len = self.lines[r - 1].chars().count(); - if len <= c { - self.cursor.1 = len - 1; - } - } - - pub fn cursor_start(&mut self) { - self.cursor.1 = 0; - } - - pub fn cursor_end(&mut self) { - self.cursor.1 = self.lines[self.cursor.0].chars().count() - 1; - } - pub fn undo(&mut self) { if let Some(cursor) = self.history.undo(&mut self.lines) { self.cursor = cursor;