diff --git a/src/actions.rs b/src/actions.rs index b9a5dd6..7150714 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -130,10 +130,12 @@ pub fn visual_mode(state: &mut State) { } pub fn insert_mode(state: &mut State) { + state.save_buffer(); state.mode = Mode::Insert(InsertState { append: false }); } pub fn append_mode(state: &mut State) { + state.save_buffer(); state.move_cursor(Direction::Right); state.mode = Mode::Insert(InsertState { append: true }); } @@ -149,24 +151,24 @@ pub fn insert_at_line_end(state: &mut State) { } pub fn open_below(state: &mut State) { + insert_mode(state); state.cursor.line += 1; state.cursor.column = 0; state.buffer.insert_char(state.cursor, '\n'); - state.mode = Mode::Insert(InsertState { append: false }); } pub fn open_above(state: &mut State) { + insert_mode(state); state.cursor.column = 0; state.buffer.insert_char(state.cursor, '\n'); - state.mode = Mode::Insert(InsertState { append: false }); } pub fn undo(state: &mut State) { - state.set_error("undo is unimplemented"); + state.undo(); } pub fn redo(state: &mut State) { - state.set_error("redo is unimplemented"); + state.redo(); } pub fn delete_char_backward(state: &mut State) { diff --git a/src/state.rs b/src/state.rs index 2258e42..f659b55 100644 --- a/src/state.rs +++ b/src/state.rs @@ -71,6 +71,8 @@ pub struct State { pub styles: Arc>, pub config: Config, pub buffer: Buffer, + pub undo_buffers: Vec, + pub redo_buffers: Vec, pub cursor: Cursor, pub file: Option, pub mode: Mode, @@ -95,6 +97,8 @@ impl State { styles, config: Default::default(), buffer, + undo_buffers: Vec::new(), + redo_buffers: Vec::new(), cursor: Cursor::default(), file: file_name, mode: Mode::default(), @@ -375,4 +379,39 @@ impl State { self.scroll.line = self.cursor.line + 3 - self.size.1; } } + + /// If modified, saves the current buffer in undo history and clears the redo history. + pub fn save_buffer(&mut self) { + /*if let Some(last) = self.undo_buffers.last() { + if *last.as_ref() == *self.buffer.as_ref() { + return; + } + }*/ + + let current = self.buffer.clone(); + self.undo_buffers.push(current); + self.redo_buffers.clear(); + } + + /// Pops the last undo state from the history and pushes the current state to the redo buffers. + pub fn undo(&mut self) { + match self.undo_buffers.pop() { + None => self.set_error("Already at oldest change"), + Some(last) => { + let current = std::mem::replace(&mut self.buffer, last); + self.redo_buffers.push(current); + } + } + } + + /// Pops the next redo state from the history and pushes the current state to the undo buffers. + pub fn redo(&mut self) { + match self.redo_buffers.pop() { + None => self.set_error("Already at newest change"), + Some(next) => { + let current = std::mem::replace(&mut self.buffer, next); + self.undo_buffers.push(current); + } + } + } }