зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-06 23:55:49 +03:00
separate Scrolling to src/scroll.rs
Этот коммит содержится в:
@@ -8,6 +8,7 @@ mod cursor;
|
|||||||
mod highlight;
|
mod highlight;
|
||||||
mod history;
|
mod history;
|
||||||
mod input;
|
mod input;
|
||||||
|
mod scroll;
|
||||||
#[cfg(feature = "search")]
|
#[cfg(feature = "search")]
|
||||||
mod search;
|
mod search;
|
||||||
mod textarea;
|
mod textarea;
|
||||||
@@ -17,4 +18,5 @@ mod word;
|
|||||||
|
|
||||||
pub use cursor::CursorMove;
|
pub use cursor::CursorMove;
|
||||||
pub use input::{Input, Key};
|
pub use input::{Input, Key};
|
||||||
pub use textarea::{Scrolling, TextArea};
|
pub use scroll::Scrolling;
|
||||||
|
pub use textarea::TextArea;
|
||||||
|
|||||||
180
src/scroll.rs
Обычный файл
180
src/scroll.rs
Обычный файл
@@ -0,0 +1,180 @@
|
|||||||
|
use crate::widget::Viewport;
|
||||||
|
|
||||||
|
/// Specify how to scroll the textarea.
|
||||||
|
///
|
||||||
|
/// This type is marked as `#[non_exhaustive]` since more variations may be supported in the future. Note that the cursor will
|
||||||
|
/// not move until it goes out the viewport. See also: [`TextArea::scroll`]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Scrolling {
|
||||||
|
/// Scroll the textarea by rows (vertically) and columns (horizontally). Passing positive scroll amounts to `rows` and `cols`
|
||||||
|
/// scolls it to down and right. Negative integers means the opposite directions. `(i16, i16)` pair can be converted into
|
||||||
|
/// `Scrolling::Delta` where 1st element means rows and 2nd means columns.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tui::buffer::Buffer;
|
||||||
|
/// # use tui::layout::Rect;
|
||||||
|
/// # use tui::widgets::Widget;
|
||||||
|
/// use tui_textarea::{TextArea, Scrolling};
|
||||||
|
///
|
||||||
|
/// // Let's say terminal height is 8.
|
||||||
|
///
|
||||||
|
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
||||||
|
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
||||||
|
/// # // Call `render` at least once to populate terminal size
|
||||||
|
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
||||||
|
/// # let mut b = Buffer::empty(r.clone());
|
||||||
|
/// # textarea.widget().render(r, &mut b);
|
||||||
|
///
|
||||||
|
/// // Scroll down by 2 lines.
|
||||||
|
/// textarea.scroll(Scrolling::Delta{rows: 2, cols: 0});
|
||||||
|
/// assert_eq!(textarea.cursor(), (2, 0));
|
||||||
|
///
|
||||||
|
/// // (1, 0) is converted into Scrolling::Delta{rows: 1, cols: 0}
|
||||||
|
/// textarea.scroll((1, 0));
|
||||||
|
/// assert_eq!(textarea.cursor(), (3, 0));
|
||||||
|
/// ```
|
||||||
|
Delta { rows: i16, cols: i16 },
|
||||||
|
/// Scroll down the textarea by one page.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tui::buffer::Buffer;
|
||||||
|
/// # use tui::layout::Rect;
|
||||||
|
/// # use tui::widgets::Widget;
|
||||||
|
/// use tui_textarea::{TextArea, Scrolling};
|
||||||
|
///
|
||||||
|
/// // Let's say terminal height is 8.
|
||||||
|
///
|
||||||
|
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
||||||
|
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
||||||
|
/// # // Call `render` at least once to populate terminal size
|
||||||
|
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
||||||
|
/// # let mut b = Buffer::empty(r.clone());
|
||||||
|
/// # textarea.widget().render(r, &mut b);
|
||||||
|
///
|
||||||
|
/// // Scroll down by one page (8 lines)
|
||||||
|
/// textarea.scroll(Scrolling::PageDown);
|
||||||
|
/// assert_eq!(textarea.cursor(), (8, 0));
|
||||||
|
/// textarea.scroll(Scrolling::PageDown);
|
||||||
|
/// assert_eq!(textarea.cursor(), (16, 0));
|
||||||
|
/// textarea.scroll(Scrolling::PageDown);
|
||||||
|
/// assert_eq!(textarea.cursor(), (19, 0)); // Reached bottom of the textarea
|
||||||
|
/// ```
|
||||||
|
PageDown,
|
||||||
|
/// Scroll up the textarea by one page.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tui::buffer::Buffer;
|
||||||
|
/// # use tui::layout::Rect;
|
||||||
|
/// # use tui::widgets::Widget;
|
||||||
|
/// use tui_textarea::{TextArea, Scrolling, CursorMove};
|
||||||
|
///
|
||||||
|
/// // Let's say terminal height is 8.
|
||||||
|
///
|
||||||
|
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
||||||
|
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
||||||
|
/// # // Call `render` at least once to populate terminal size
|
||||||
|
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
||||||
|
/// # let mut b = Buffer::empty(r.clone());
|
||||||
|
/// # textarea.widget().render(r.clone(), &mut b);
|
||||||
|
///
|
||||||
|
/// // Go to the last line at first
|
||||||
|
/// textarea.move_cursor(CursorMove::Bottom);
|
||||||
|
/// assert_eq!(textarea.cursor(), (19, 0));
|
||||||
|
/// # // Call `render` to populate terminal size
|
||||||
|
/// # textarea.widget().render(r.clone(), &mut b);
|
||||||
|
///
|
||||||
|
/// // Scroll up by one page (8 lines)
|
||||||
|
/// textarea.scroll(Scrolling::PageUp);
|
||||||
|
/// assert_eq!(textarea.cursor(), (11, 0));
|
||||||
|
/// textarea.scroll(Scrolling::PageUp);
|
||||||
|
/// assert_eq!(textarea.cursor(), (7, 0)); // Reached top of the textarea
|
||||||
|
/// ```
|
||||||
|
PageUp,
|
||||||
|
/// Scroll down the textarea by half of the page.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tui::buffer::Buffer;
|
||||||
|
/// # use tui::layout::Rect;
|
||||||
|
/// # use tui::widgets::Widget;
|
||||||
|
/// use tui_textarea::{TextArea, Scrolling};
|
||||||
|
///
|
||||||
|
/// // Let's say terminal height is 8.
|
||||||
|
///
|
||||||
|
/// // Create textarea with 10 lines "0", "1", "2", "3", ...
|
||||||
|
/// let mut textarea: TextArea = (0..10).into_iter().map(|i| i.to_string()).collect();
|
||||||
|
/// # // Call `render` at least once to populate terminal size
|
||||||
|
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
||||||
|
/// # let mut b = Buffer::empty(r.clone());
|
||||||
|
/// # textarea.widget().render(r, &mut b);
|
||||||
|
///
|
||||||
|
/// // Scroll down by half-page (4 lines)
|
||||||
|
/// textarea.scroll(Scrolling::HalfPageDown);
|
||||||
|
/// assert_eq!(textarea.cursor(), (4, 0));
|
||||||
|
/// textarea.scroll(Scrolling::HalfPageDown);
|
||||||
|
/// assert_eq!(textarea.cursor(), (8, 0));
|
||||||
|
/// textarea.scroll(Scrolling::HalfPageDown);
|
||||||
|
/// assert_eq!(textarea.cursor(), (9, 0)); // Reached bottom of the textarea
|
||||||
|
/// ```
|
||||||
|
HalfPageDown,
|
||||||
|
/// Scroll up the textarea by half of the page.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tui::buffer::Buffer;
|
||||||
|
/// # use tui::layout::Rect;
|
||||||
|
/// # use tui::widgets::Widget;
|
||||||
|
/// use tui_textarea::{TextArea, Scrolling, CursorMove};
|
||||||
|
///
|
||||||
|
/// // Let's say terminal height is 8.
|
||||||
|
///
|
||||||
|
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
||||||
|
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
||||||
|
/// # // Call `render` at least once to populate terminal size
|
||||||
|
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
||||||
|
/// # let mut b = Buffer::empty(r.clone());
|
||||||
|
/// # textarea.widget().render(r.clone(), &mut b);
|
||||||
|
///
|
||||||
|
/// // Go to the last line at first
|
||||||
|
/// textarea.move_cursor(CursorMove::Bottom);
|
||||||
|
/// assert_eq!(textarea.cursor(), (19, 0));
|
||||||
|
/// # // Call `render` to populate terminal size
|
||||||
|
/// # textarea.widget().render(r.clone(), &mut b);
|
||||||
|
///
|
||||||
|
/// // Scroll up by half-page (4 lines)
|
||||||
|
/// textarea.scroll(Scrolling::HalfPageUp);
|
||||||
|
/// assert_eq!(textarea.cursor(), (15, 0));
|
||||||
|
/// textarea.scroll(Scrolling::HalfPageUp);
|
||||||
|
/// assert_eq!(textarea.cursor(), (11, 0));
|
||||||
|
/// ```
|
||||||
|
HalfPageUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scrolling {
|
||||||
|
pub(crate) fn scroll(self, viewport: &mut Viewport) {
|
||||||
|
let (rows, cols) = match self {
|
||||||
|
Self::Delta { rows, cols } => (rows, cols),
|
||||||
|
Self::PageDown => {
|
||||||
|
let (_, _, _, height) = viewport.rect();
|
||||||
|
(height as i16, 0)
|
||||||
|
}
|
||||||
|
Self::PageUp => {
|
||||||
|
let (_, _, _, height) = viewport.rect();
|
||||||
|
(-(height as i16), 0)
|
||||||
|
}
|
||||||
|
Self::HalfPageDown => {
|
||||||
|
let (_, _, _, height) = viewport.rect();
|
||||||
|
((height as i16) / 2, 0)
|
||||||
|
}
|
||||||
|
Self::HalfPageUp => {
|
||||||
|
let (_, _, _, height) = viewport.rect();
|
||||||
|
(-(height as i16) / 2, 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
viewport.scroll(rows, cols);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(i16, i16)> for Scrolling {
|
||||||
|
fn from((rows, cols): (i16, i16)) -> Self {
|
||||||
|
Self::Delta { rows, cols }
|
||||||
|
}
|
||||||
|
}
|
||||||
180
src/textarea.rs
180
src/textarea.rs
@@ -2,6 +2,7 @@ use crate::cursor::CursorMove;
|
|||||||
use crate::highlight::LineHighlighter;
|
use crate::highlight::LineHighlighter;
|
||||||
use crate::history::{Edit, EditKind, History};
|
use crate::history::{Edit, EditKind, History};
|
||||||
use crate::input::{Input, Key};
|
use crate::input::{Input, Key};
|
||||||
|
use crate::scroll::Scrolling;
|
||||||
#[cfg(feature = "search")]
|
#[cfg(feature = "search")]
|
||||||
use crate::search::Search;
|
use crate::search::Search;
|
||||||
use crate::util::spaces;
|
use crate::util::spaces;
|
||||||
@@ -12,185 +13,6 @@ use tui::style::{Modifier, Style};
|
|||||||
use tui::text::Spans;
|
use tui::text::Spans;
|
||||||
use tui::widgets::{Block, Widget};
|
use tui::widgets::{Block, Widget};
|
||||||
|
|
||||||
/// Specify how to scroll the textarea.
|
|
||||||
///
|
|
||||||
/// This type is marked as `#[non_exhaustive]` since more variations may be supported in the future. Note that the cursor will
|
|
||||||
/// not move until it goes out the viewport. See also: [`TextArea::scroll`]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum Scrolling {
|
|
||||||
/// Scroll the textarea by rows (vertically) and columns (horizontally). Passing positive scroll amounts to `rows` and `cols`
|
|
||||||
/// scolls it to down and right. Negative integers means the opposite directions. `(i16, i16)` pair can be converted into
|
|
||||||
/// `Scrolling::Delta` where 1st element means rows and 2nd means columns.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tui::buffer::Buffer;
|
|
||||||
/// # use tui::layout::Rect;
|
|
||||||
/// # use tui::widgets::Widget;
|
|
||||||
/// use tui_textarea::{TextArea, Scrolling};
|
|
||||||
///
|
|
||||||
/// // Let's say terminal height is 8.
|
|
||||||
///
|
|
||||||
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
|
||||||
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
|
||||||
/// # // Call `render` at least once to populate terminal size
|
|
||||||
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
|
||||||
/// # let mut b = Buffer::empty(r.clone());
|
|
||||||
/// # textarea.widget().render(r, &mut b);
|
|
||||||
///
|
|
||||||
/// // Scroll down by 2 lines.
|
|
||||||
/// textarea.scroll(Scrolling::Delta{rows: 2, cols: 0});
|
|
||||||
/// assert_eq!(textarea.cursor(), (2, 0));
|
|
||||||
///
|
|
||||||
/// // (1, 0) is converted into Scrolling::Delta{rows: 1, cols: 0}
|
|
||||||
/// textarea.scroll((1, 0));
|
|
||||||
/// assert_eq!(textarea.cursor(), (3, 0));
|
|
||||||
/// ```
|
|
||||||
Delta { rows: i16, cols: i16 },
|
|
||||||
/// Scroll down the textarea by one page.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tui::buffer::Buffer;
|
|
||||||
/// # use tui::layout::Rect;
|
|
||||||
/// # use tui::widgets::Widget;
|
|
||||||
/// use tui_textarea::{TextArea, Scrolling};
|
|
||||||
///
|
|
||||||
/// // Let's say terminal height is 8.
|
|
||||||
///
|
|
||||||
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
|
||||||
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
|
||||||
/// # // Call `render` at least once to populate terminal size
|
|
||||||
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
|
||||||
/// # let mut b = Buffer::empty(r.clone());
|
|
||||||
/// # textarea.widget().render(r, &mut b);
|
|
||||||
///
|
|
||||||
/// // Scroll down by one page (8 lines)
|
|
||||||
/// textarea.scroll(Scrolling::PageDown);
|
|
||||||
/// assert_eq!(textarea.cursor(), (8, 0));
|
|
||||||
/// textarea.scroll(Scrolling::PageDown);
|
|
||||||
/// assert_eq!(textarea.cursor(), (16, 0));
|
|
||||||
/// textarea.scroll(Scrolling::PageDown);
|
|
||||||
/// assert_eq!(textarea.cursor(), (19, 0)); // Reached bottom of the textarea
|
|
||||||
/// ```
|
|
||||||
PageDown,
|
|
||||||
/// Scroll up the textarea by one page.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tui::buffer::Buffer;
|
|
||||||
/// # use tui::layout::Rect;
|
|
||||||
/// # use tui::widgets::Widget;
|
|
||||||
/// use tui_textarea::{TextArea, Scrolling, CursorMove};
|
|
||||||
///
|
|
||||||
/// // Let's say terminal height is 8.
|
|
||||||
///
|
|
||||||
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
|
||||||
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
|
||||||
/// # // Call `render` at least once to populate terminal size
|
|
||||||
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
|
||||||
/// # let mut b = Buffer::empty(r.clone());
|
|
||||||
/// # textarea.widget().render(r.clone(), &mut b);
|
|
||||||
///
|
|
||||||
/// // Go to the last line at first
|
|
||||||
/// textarea.move_cursor(CursorMove::Bottom);
|
|
||||||
/// assert_eq!(textarea.cursor(), (19, 0));
|
|
||||||
/// # // Call `render` to populate terminal size
|
|
||||||
/// # textarea.widget().render(r.clone(), &mut b);
|
|
||||||
///
|
|
||||||
/// // Scroll up by one page (8 lines)
|
|
||||||
/// textarea.scroll(Scrolling::PageUp);
|
|
||||||
/// assert_eq!(textarea.cursor(), (11, 0));
|
|
||||||
/// textarea.scroll(Scrolling::PageUp);
|
|
||||||
/// assert_eq!(textarea.cursor(), (7, 0)); // Reached top of the textarea
|
|
||||||
/// ```
|
|
||||||
PageUp,
|
|
||||||
/// Scroll down the textarea by half of the page.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tui::buffer::Buffer;
|
|
||||||
/// # use tui::layout::Rect;
|
|
||||||
/// # use tui::widgets::Widget;
|
|
||||||
/// use tui_textarea::{TextArea, Scrolling};
|
|
||||||
///
|
|
||||||
/// // Let's say terminal height is 8.
|
|
||||||
///
|
|
||||||
/// // Create textarea with 10 lines "0", "1", "2", "3", ...
|
|
||||||
/// let mut textarea: TextArea = (0..10).into_iter().map(|i| i.to_string()).collect();
|
|
||||||
/// # // Call `render` at least once to populate terminal size
|
|
||||||
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
|
||||||
/// # let mut b = Buffer::empty(r.clone());
|
|
||||||
/// # textarea.widget().render(r, &mut b);
|
|
||||||
///
|
|
||||||
/// // Scroll down by half-page (4 lines)
|
|
||||||
/// textarea.scroll(Scrolling::HalfPageDown);
|
|
||||||
/// assert_eq!(textarea.cursor(), (4, 0));
|
|
||||||
/// textarea.scroll(Scrolling::HalfPageDown);
|
|
||||||
/// assert_eq!(textarea.cursor(), (8, 0));
|
|
||||||
/// textarea.scroll(Scrolling::HalfPageDown);
|
|
||||||
/// assert_eq!(textarea.cursor(), (9, 0)); // Reached bottom of the textarea
|
|
||||||
/// ```
|
|
||||||
HalfPageDown,
|
|
||||||
/// Scroll up the textarea by half of the page.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tui::buffer::Buffer;
|
|
||||||
/// # use tui::layout::Rect;
|
|
||||||
/// # use tui::widgets::Widget;
|
|
||||||
/// use tui_textarea::{TextArea, Scrolling, CursorMove};
|
|
||||||
///
|
|
||||||
/// // Let's say terminal height is 8.
|
|
||||||
///
|
|
||||||
/// // Create textarea with 20 lines "0", "1", "2", "3", ...
|
|
||||||
/// let mut textarea: TextArea = (0..20).into_iter().map(|i| i.to_string()).collect();
|
|
||||||
/// # // Call `render` at least once to populate terminal size
|
|
||||||
/// # let r = Rect { x: 0, y: 0, width: 24, height: 8 };
|
|
||||||
/// # let mut b = Buffer::empty(r.clone());
|
|
||||||
/// # textarea.widget().render(r.clone(), &mut b);
|
|
||||||
///
|
|
||||||
/// // Go to the last line at first
|
|
||||||
/// textarea.move_cursor(CursorMove::Bottom);
|
|
||||||
/// assert_eq!(textarea.cursor(), (19, 0));
|
|
||||||
/// # // Call `render` to populate terminal size
|
|
||||||
/// # textarea.widget().render(r.clone(), &mut b);
|
|
||||||
///
|
|
||||||
/// // Scroll up by half-page (4 lines)
|
|
||||||
/// textarea.scroll(Scrolling::HalfPageUp);
|
|
||||||
/// assert_eq!(textarea.cursor(), (15, 0));
|
|
||||||
/// textarea.scroll(Scrolling::HalfPageUp);
|
|
||||||
/// assert_eq!(textarea.cursor(), (11, 0));
|
|
||||||
/// ```
|
|
||||||
HalfPageUp,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scrolling {
|
|
||||||
fn scroll(self, viewport: &mut Viewport) {
|
|
||||||
let (rows, cols) = match self {
|
|
||||||
Self::Delta { rows, cols } => (rows, cols),
|
|
||||||
Self::PageDown => {
|
|
||||||
let (_, _, _, height) = viewport.rect();
|
|
||||||
(height as i16, 0)
|
|
||||||
}
|
|
||||||
Self::PageUp => {
|
|
||||||
let (_, _, _, height) = viewport.rect();
|
|
||||||
(-(height as i16), 0)
|
|
||||||
}
|
|
||||||
Self::HalfPageDown => {
|
|
||||||
let (_, _, _, height) = viewport.rect();
|
|
||||||
((height as i16) / 2, 0)
|
|
||||||
}
|
|
||||||
Self::HalfPageUp => {
|
|
||||||
let (_, _, _, height) = viewport.rect();
|
|
||||||
(-(height as i16) / 2, 0)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
viewport.scroll(rows, cols);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(i16, i16)> for Scrolling {
|
|
||||||
fn from((rows, cols): (i16, i16)) -> Self {
|
|
||||||
Self::Delta { rows, cols }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type to manage state of textarea.
|
/// A type to manage state of textarea.
|
||||||
///
|
///
|
||||||
/// [`TextArea::default`] creates an empty textarea. [`TextArea::new`] creates a textarea with given text lines.
|
/// [`TextArea::default`] creates an empty textarea. [`TextArea::new`] creates a textarea with given text lines.
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user