From 1c5350905f25cfd6d651c8f2da1dcbc3957e5278 Mon Sep 17 00:00:00 2001 From: rhysd Date: Tue, 14 Jun 2022 12:35:08 +0900 Subject: [PATCH] add documents to `Input` and `CursorMove` --- src/cursor.rs | 154 +++++++++++++++++++++++++++++++++++++++++++++++++- src/input.rs | 35 ++++++++++++ 2 files changed, 188 insertions(+), 1 deletion(-) diff --git a/src/cursor.rs b/src/cursor.rs index c3577df..1050a3e 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -1,24 +1,176 @@ use crate::word::{find_word_start_backward, find_word_start_forward}; use std::cmp; +/// Specify how to move the cursor. #[derive(Clone, Copy, Debug)] pub enum CursorMove { + /// Move cursor forward by one character. When the cursor is at the end of line, it moves to the head of next line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["abc"]); + /// + /// textarea.move_cursor(CursorMove::Forward); + /// assert_eq!(textarea.cursor(), (0, 1)); + /// textarea.move_cursor(CursorMove::Forward); + /// assert_eq!(textarea.cursor(), (0, 2)); + /// ``` Forward, + /// Move cursor backward by one character. When the cursor is at the head of line, it moves to the end of previous + /// line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["abc"]); + /// + /// textarea.move_cursor(CursorMove::Forward); + /// textarea.move_cursor(CursorMove::Forward); + /// textarea.move_cursor(CursorMove::Back); + /// assert_eq!(textarea.cursor(), (0, 1)); + /// ``` Back, + /// Move cursor up by one line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["a", "b", "c"]); + /// + /// textarea.move_cursor(CursorMove::Down); + /// textarea.move_cursor(CursorMove::Down); + /// textarea.move_cursor(CursorMove::Up); + /// assert_eq!(textarea.cursor(), (1, 0)); + /// ``` Up, + /// Move cursor down by one line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["a", "b", "c"]); + /// + /// textarea.move_cursor(CursorMove::Down); + /// assert_eq!(textarea.cursor(), (1, 0)); + /// textarea.move_cursor(CursorMove::Down); + /// assert_eq!(textarea.cursor(), (2, 0)); + /// ``` Down, + /// Move cursor to the head of line. When the cursor is at the head of line, it moves to the end of previous line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["abc"]); + /// + /// textarea.move_cursor(CursorMove::Forward); + /// textarea.move_cursor(CursorMove::Forward); + /// textarea.move_cursor(CursorMove::Head); + /// assert_eq!(textarea.cursor(), (0, 0)); + /// ``` Head, + /// Move cursor to the end of line. When the cursor is at the end of line, it moves to the head of next line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["abc"]); + /// + /// textarea.move_cursor(CursorMove::End); + /// assert_eq!(textarea.cursor(), (0, 3)); + /// ``` End, + /// Move cursor to the top of lines. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["a", "b", "c"]); + /// + /// textarea.move_cursor(CursorMove::Down); + /// textarea.move_cursor(CursorMove::Down); + /// textarea.move_cursor(CursorMove::Top); + /// assert_eq!(textarea.cursor(), (0, 0)); + /// ``` Top, + /// Move cursor to the bottom of lines. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["a", "b", "c"]); + /// + /// textarea.move_cursor(CursorMove::Bottom); + /// assert_eq!(textarea.cursor(), (2, 0)); + /// ``` Bottom, + /// Move cursor forward by one word. Word boundary appears at spaces, punctuations, and others. For example + /// `fn foo(a)` consists of words `fn`, `foo`, `(`, `a`, `)`. When the cursor is at the end of line, it moves to the + /// head of next line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["aaa bbb ccc"]); + /// + /// textarea.move_cursor(CursorMove::WordForward); + /// assert_eq!(textarea.cursor(), (0, 4)); + /// textarea.move_cursor(CursorMove::WordForward); + /// assert_eq!(textarea.cursor(), (0, 8)); + /// ``` WordForward, + /// Move cursor backward by one word. Word boundary appears at spaces, punctuations, and others. For example + /// `fn foo(a)` consists of words `fn`, `foo`, `(`, `a`, `)`.When the cursor is at the head of line, it moves to + /// the end of previous line. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// let mut textarea = TextArea::from(["aaa bbb ccc"]); + /// + /// textarea.move_cursor(CursorMove::End); + /// textarea.move_cursor(CursorMove::WordBack); + /// assert_eq!(textarea.cursor(), (0, 8)); + /// textarea.move_cursor(CursorMove::WordBack); + /// assert_eq!(textarea.cursor(), (0, 4)); + /// textarea.move_cursor(CursorMove::WordBack); + /// assert_eq!(textarea.cursor(), (0, 0)); + /// ``` WordBack, + /// Move cursor down by one paragraph. Paragraph is a chunk of non-empty lines. Cursor moves to the first line of paragraph. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// // aaa + /// // + /// // bbb + /// // + /// // ccc + /// // ddd + /// let mut textarea = TextArea::from(["aaa", "", "bbb", "", "ccc", "ddd"]); + /// + /// textarea.move_cursor(CursorMove::ParagraphForward); + /// assert_eq!(textarea.cursor(), (2, 0)); + /// textarea.move_cursor(CursorMove::ParagraphForward); + /// assert_eq!(textarea.cursor(), (4, 0)); + /// ``` ParagraphForward, + /// Move cursor up by one paragraph. Paragraph is a chunk of non-empty lines. Cursor moves to the first line of paragraph. + /// ``` + /// use tui_textarea::{TextArea, CursorMove}; + /// + /// // aaa + /// // + /// // bbb + /// // + /// // ccc + /// // ddd + /// let mut textarea = TextArea::from(["aaa", "", "bbb", "", "ccc", "ddd"]); + /// + /// textarea.move_cursor(CursorMove::Bottom); + /// textarea.move_cursor(CursorMove::ParagraphBack); + /// assert_eq!(textarea.cursor(), (4, 0)); + /// textarea.move_cursor(CursorMove::ParagraphBack); + /// assert_eq!(textarea.cursor(), (2, 0)); + /// textarea.move_cursor(CursorMove::ParagraphBack); + /// assert_eq!(textarea.cursor(), (0, 0)); + /// ``` ParagraphBack, } impl CursorMove { - pub fn next_cursor( + pub(crate) fn next_cursor( &self, (row, col): (usize, usize), lines: &[String], diff --git a/src/input.rs b/src/input.rs index e97e474..9a5b509 100644 --- a/src/input.rs +++ b/src/input.rs @@ -3,8 +3,11 @@ use crossterm::event::{Event as CrosstermEvent, KeyCode, KeyEvent, KeyModifiers} #[cfg(feature = "termion")] use termion::event::{Event as TerimonEvent, Key as TermionKey}; +/// Backend-agnostic key input kind. +#[non_exhaustive] #[derive(Clone, Copy, Debug)] pub enum Key { + /// Normal letter key input. Char(char), Backspace, Enter, @@ -18,13 +21,45 @@ pub enum Key { End, PageUp, PageDown, + /// An invalid key input (this key is always ignored by [`TextArea`](crate::TextArea)). Null, } +/// Backend-agnostic key input type. +/// +/// When `crossterm` and/or `termion` features are enabled, converting their key input types into this `Input` type is defined. +/// ```no_run +/// use tui_textarea::{TextArea, Input, Key}; +/// use crossterm::event::{Event, read}; +/// +/// let event = read().unwrap(); +/// let input = Input::from(event); +/// if let Event::Key(key) = event { +/// let input = Input::from(key); // Conversion from `KeyEvent` value is also available +/// } +/// ``` +/// +/// Creating `Input` instance directly can cause backend-agnostic input as follows. +/// +/// ``` +/// use tui_textarea::{TextArea, Input, Key}; +/// +/// let mut textarea = TextArea::default(); +/// +/// // Input Ctrl+A +/// textarea.input(Input { +/// key: Key::Char('a'), +/// ctrl: true, +/// alt: false, +/// }); +/// ``` #[derive(Debug, Clone)] pub struct Input { + /// Typed key. pub key: Key, + /// Ctrl modifier key. `true` means Ctrl key was pressed. pub ctrl: bool, + /// Alt modifier key. `true` means Alt key was pressed. pub alt: bool, }