зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-03 22:35:50 +03:00
scroll to top/bottom
Этот коммит содержится в:
@@ -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])))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Event> for Input {
|
||||
impl From<KeyEvent> 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<KeyEvent> for Input {
|
||||
KeyCode::End => Key::End,
|
||||
_ => Key::Null,
|
||||
};
|
||||
Self { key, ctrl }
|
||||
Self { key, ctrl, alt }
|
||||
}
|
||||
}
|
||||
|
||||
145
src/textarea.rs
145
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<Input>) {
|
||||
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
|
||||
|
||||
Ссылка в новой задаче
Block a user