зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-08 16:35:49 +03:00
return if TextArea::undo and TextArea::redo modified contents
Этот коммит содержится в:
@@ -132,10 +132,7 @@ impl History {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo(&mut self, lines: &mut Vec<String>) -> Option<(usize, usize)> {
|
pub fn undo(&mut self, lines: &mut Vec<String>) -> Option<(usize, usize)> {
|
||||||
if self.index == 0 {
|
self.index = self.index.checked_sub(1)?;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
self.index -= 1;
|
|
||||||
let edit = &self.edits[self.index];
|
let edit = &self.edits[self.index];
|
||||||
edit.undo(lines);
|
edit.undo(lines);
|
||||||
Some(edit.cursor_before())
|
Some(edit.cursor_before())
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ pub struct Input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Input {
|
impl Default for Input {
|
||||||
|
/// The default input is [`Key::Null`] without pressing Ctrl nor Alt, which means invalid input.
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Input {
|
Input {
|
||||||
key: Key::Null,
|
key: Key::Null,
|
||||||
|
|||||||
@@ -53,12 +53,19 @@ pub struct TextArea<'a> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use tui_textarea::TextArea;
|
/// use tui_textarea::TextArea;
|
||||||
///
|
///
|
||||||
|
/// // From `String`
|
||||||
/// let text = "hello\nworld";
|
/// let text = "hello\nworld";
|
||||||
/// let textarea = TextArea::from(text.lines());
|
/// let textarea = TextArea::from(text.lines());
|
||||||
/// assert_eq!(textarea.lines(), ["hello", "world"]);
|
/// assert_eq!(textarea.lines(), ["hello", "world"]);
|
||||||
///
|
///
|
||||||
|
/// // From array of `&str`
|
||||||
/// let textarea = TextArea::from(["hello", "world"]);
|
/// let textarea = TextArea::from(["hello", "world"]);
|
||||||
/// assert_eq!(textarea.lines(), ["hello", "world"]);
|
/// assert_eq!(textarea.lines(), ["hello", "world"]);
|
||||||
|
///
|
||||||
|
/// // From slice of `&str`
|
||||||
|
/// let slice = &["hello", "world"];
|
||||||
|
/// let textarea = TextArea::from(slice.iter().copied());
|
||||||
|
/// assert_eq!(textarea.lines(), ["hello", "world"]);
|
||||||
/// ```
|
/// ```
|
||||||
impl<'a, I> From<I> for TextArea<'a>
|
impl<'a, I> From<I> for TextArea<'a>
|
||||||
where
|
where
|
||||||
@@ -347,12 +354,16 @@ impl<'a> TextArea<'a> {
|
|||||||
key: Key::Char('u'),
|
key: Key::Char('u'),
|
||||||
ctrl: true,
|
ctrl: true,
|
||||||
alt: false,
|
alt: false,
|
||||||
} => self.undo(),
|
} => {
|
||||||
|
self.undo();
|
||||||
|
}
|
||||||
Input {
|
Input {
|
||||||
key: Key::Char('r'),
|
key: Key::Char('r'),
|
||||||
ctrl: true,
|
ctrl: true,
|
||||||
alt: false,
|
alt: false,
|
||||||
} => self.redo(),
|
} => {
|
||||||
|
self.redo();
|
||||||
|
}
|
||||||
Input {
|
Input {
|
||||||
key: Key::Char('y' | 'v'),
|
key: Key::Char('y' | 'v'),
|
||||||
ctrl: true,
|
ctrl: true,
|
||||||
@@ -749,7 +760,8 @@ impl<'a> TextArea<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Undo the last modification. When no modification is added to the text, this method does nothing.
|
/// Undo the last modification. When no modification is added to the text, this method does not modify contents and
|
||||||
|
/// returns `false`.
|
||||||
/// ```
|
/// ```
|
||||||
/// use tui_textarea::{TextArea, CursorMove};
|
/// use tui_textarea::{TextArea, CursorMove};
|
||||||
///
|
///
|
||||||
@@ -760,13 +772,16 @@ impl<'a> TextArea<'a> {
|
|||||||
/// textarea.undo();
|
/// textarea.undo();
|
||||||
/// assert_eq!(textarea.lines(), ["abc def"]);
|
/// assert_eq!(textarea.lines(), ["abc def"]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn undo(&mut self) {
|
pub fn undo(&mut self) -> bool {
|
||||||
if let Some(cursor) = self.history.undo(&mut self.lines) {
|
if let Some(cursor) = self.history.undo(&mut self.lines) {
|
||||||
self.cursor = cursor;
|
self.cursor = cursor;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redo the last undo change. When no undo change remain, this method does nothing.
|
/// Redo the last undo change. When no undo change remain, this method does not modify contents and returns `false`.
|
||||||
/// ```
|
/// ```
|
||||||
/// use tui_textarea::{TextArea, CursorMove};
|
/// use tui_textarea::{TextArea, CursorMove};
|
||||||
///
|
///
|
||||||
@@ -779,9 +794,12 @@ impl<'a> TextArea<'a> {
|
|||||||
/// textarea.redo();
|
/// textarea.redo();
|
||||||
/// assert_eq!(textarea.lines(), [" def"]);
|
/// assert_eq!(textarea.lines(), [" def"]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn redo(&mut self) {
|
pub fn redo(&mut self) -> bool {
|
||||||
if let Some(cursor) = self.history.redo(&mut self.lines) {
|
if let Some(cursor) = self.history.redo(&mut self.lines) {
|
||||||
self.cursor = cursor;
|
self.cursor = cursor;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,7 +868,7 @@ impl<'a> TextArea<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let inner = Paragraph::new(Text::from(lines)).style(self.style);
|
let inner = Paragraph::new(Text::from(lines)).style(self.style);
|
||||||
TextAreaWidget {
|
Renderer {
|
||||||
scroll_top: &self.scroll_top,
|
scroll_top: &self.scroll_top,
|
||||||
cursor: (self.cursor.0 as u16, self.cursor.1 as u16),
|
cursor: (self.cursor.0 as u16, self.cursor.1 as u16),
|
||||||
block: self.block.clone(),
|
block: self.block.clone(),
|
||||||
@@ -1055,16 +1073,22 @@ impl<'a> TextArea<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TextAreaWidget<'a> {
|
struct Renderer<'a> {
|
||||||
// &mut 'a (u16, u16) is not available since TextAreaWidget instance takes over the ownership of TextArea instance.
|
// &mut 'a (u16, u16) is not available since TextAreaWidget instance totally takes over the ownership of TextArea
|
||||||
// In the case the TextArea instance cannot be accessed from any other objects since it is mutablly borrowed.
|
// instance. In the case, the TextArea instance cannot be accessed from any other objects since it is mutablly
|
||||||
|
// borrowed.
|
||||||
|
//
|
||||||
|
// `tui::terminal::Frame::render_stateful_widget` would be an assumed way to render a stateful widget. But at this
|
||||||
|
// point we stick with using `tui::terminal::Frame::render_widget` because it is simpler API. Users don't need to
|
||||||
|
// manage states of textarea instances separately.
|
||||||
|
// https://docs.rs/tui/latest/tui/terminal/struct.Frame.html#method.render_stateful_widget
|
||||||
scroll_top: &'a (AtomicU16, AtomicU16),
|
scroll_top: &'a (AtomicU16, AtomicU16),
|
||||||
cursor: (u16, u16),
|
cursor: (u16, u16),
|
||||||
block: Option<Block<'a>>,
|
block: Option<Block<'a>>,
|
||||||
inner: Paragraph<'a>,
|
inner: Paragraph<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for TextAreaWidget<'a> {
|
impl<'a> Widget for Renderer<'a> {
|
||||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
||||||
let inner_area = if let Some(b) = self.block.take() {
|
let inner_area = if let Some(b) = self.block.take() {
|
||||||
let area = b.inner(area);
|
let area = b.inner(area);
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user