1
0
зеркало из https://github.com/glebtv/tui-textarea.git synced 2026-09-03 22:35:50 +03:00

return if TextArea::undo and TextArea::redo modified contents

Этот коммит содержится в:
rhysd
2022-06-14 13:45:04 +09:00
родитель 1c5350905f
Коммит 32c31c7b9b
3 изменённых файлов: 37 добавлений и 15 удалений

Просмотреть файл

@@ -132,10 +132,7 @@ impl History {
}
pub fn undo(&mut self, lines: &mut Vec<String>) -> Option<(usize, usize)> {
if self.index == 0 {
return None;
}
self.index -= 1;
self.index = self.index.checked_sub(1)?;
let edit = &self.edits[self.index];
edit.undo(lines);
Some(edit.cursor_before())

Просмотреть файл

@@ -64,6 +64,7 @@ pub struct Input {
}
impl Default for Input {
/// The default input is [`Key::Null`] without pressing Ctrl nor Alt, which means invalid input.
fn default() -> Self {
Input {
key: Key::Null,

Просмотреть файл

@@ -53,12 +53,19 @@ pub struct TextArea<'a> {
/// ```
/// use tui_textarea::TextArea;
///
/// // From `String`
/// let text = "hello\nworld";
/// let textarea = TextArea::from(text.lines());
/// assert_eq!(textarea.lines(), ["hello", "world"]);
///
/// // From array of `&str`
/// let textarea = TextArea::from(["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>
where
@@ -347,12 +354,16 @@ impl<'a> TextArea<'a> {
key: Key::Char('u'),
ctrl: true,
alt: false,
} => self.undo(),
} => {
self.undo();
}
Input {
key: Key::Char('r'),
ctrl: true,
alt: false,
} => self.redo(),
} => {
self.redo();
}
Input {
key: Key::Char('y' | 'v'),
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};
///
@@ -760,13 +772,16 @@ impl<'a> TextArea<'a> {
/// textarea.undo();
/// 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) {
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};
///
@@ -779,9 +794,12 @@ impl<'a> TextArea<'a> {
/// textarea.redo();
/// 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) {
self.cursor = cursor;
true
} else {
false
}
}
@@ -850,7 +868,7 @@ impl<'a> TextArea<'a> {
}
let inner = Paragraph::new(Text::from(lines)).style(self.style);
TextAreaWidget {
Renderer {
scroll_top: &self.scroll_top,
cursor: (self.cursor.0 as u16, self.cursor.1 as u16),
block: self.block.clone(),
@@ -1055,16 +1073,22 @@ impl<'a> TextArea<'a> {
}
}
struct TextAreaWidget<'a> {
// &mut 'a (u16, u16) is not available since TextAreaWidget instance takes over the ownership of TextArea instance.
// In the case the TextArea instance cannot be accessed from any other objects since it is mutablly borrowed.
struct Renderer<'a> {
// &mut 'a (u16, u16) is not available since TextAreaWidget instance totally takes over the ownership of TextArea
// 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),
cursor: (u16, u16),
block: Option<Block<'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) {
let inner_area = if let Some(b) = self.block.take() {
let area = b.inner(area);