Fix undos
diff --git a/src/lib.rs b/src/lib.rs
index 27e246b..d17ecda 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -137,10 +137,6 @@
// TODO swap ChangeListener ?
}
- fn backup(&mut self) {
- self.snapshot.backup(&self.line);
- }
-
/// Rewrite the currently edited line accordingly to the buffer content,
/// cursor position, and number of columns of the terminal.
fn refresh_line(&mut self) -> Result<()> {
@@ -629,8 +625,10 @@
try!(beep());
Ok(None)
} else if CompletionType::Circular == config.completion_type() {
- // Save the current edited line before to overwrite it
- s.backup();
+ s.changes.borrow_mut().begin();
+ // Save the current edited line before overwriting it
+ let backup = s.line.as_str().to_owned();
+ let backup_pos = s.line.pos();
let mut cmd;
let mut i = 0;
loop {
@@ -640,9 +638,8 @@
try!(s.refresh_line());
} else {
// Restore current edited line
- s.snapshot();
+ s.line.update(&backup, backup_pos);
try!(s.refresh_line());
- s.snapshot();
}
cmd = try!(s.next_cmd(rdr));
@@ -655,16 +652,15 @@
}
Cmd::Abort => {
// Re-show original buffer
- s.snapshot();
if i < candidates.len() {
+ s.line.update(&backup, backup_pos);
try!(s.refresh_line());
}
+ s.changes.borrow_mut().cancel();
return Ok(None);
}
_ => {
- if i == candidates.len() {
- s.snapshot();
- }
+ s.changes.borrow_mut().end();
break;
}
}
@@ -887,8 +883,9 @@
editor.history.len(),
editor.custom_bindings.clone());
- s.line.bind(s.changes.clone());
s.line.bind(editor.kill_ring.clone());
+ // must be the last
+ s.line.bind(s.changes.clone());
try!(s.refresh_line());
@@ -1093,9 +1090,11 @@
editor.kill_ring.borrow_mut().stop_killing();
}
Cmd::Undo => {
+ s.line.unbind();
if s.changes.borrow_mut().undo(&mut s.line) {
try!(s.refresh_line());
}
+ s.line.bind(s.changes.clone());
}
Cmd::Interrupt => {
return Err(error::ReadlineError::Interrupted);
diff --git a/src/line_buffer.rs b/src/line_buffer.rs
index 23da995..c9f251f 100644
--- a/src/line_buffer.rs
+++ b/src/line_buffer.rs
@@ -75,6 +75,9 @@
pub fn bind(&mut self, cl: Rc<RefCell<ChangeListener>>) {
self.cl.push(cl);
}
+ pub fn unbind(&mut self) {
+ self.cl.pop();
+ }
/// Extracts a string slice containing the entire buffer.
pub fn as_str(&self) -> &str {
@@ -123,14 +126,6 @@
}
}
- /// Backup `src`
- pub fn backup(&mut self, src: &LineBuffer) {
- let end = self.len();
- self.drain(0..end, Direction::default());
- self.insert_str(0, &src.buf);
- self.pos = src.pos;
- }
-
/// Returns the character at current cursor position.
fn grapheme_at_cursor(&self) -> Option<&str> {
if self.pos == self.buf.len() {
diff --git a/src/undo.rs b/src/undo.rs
index d8f52e9..5fe4d25 100644
--- a/src/undo.rs
+++ b/src/undo.rs
@@ -1,4 +1,6 @@
//! Undo API
+use std::fmt::Debug;
+
use line_buffer::{ChangeListener, Direction, LineBuffer};
use std_unicode::str::UnicodeStr;
use unicode_segmentation::UnicodeSegmentation;
@@ -69,7 +71,6 @@
pub struct Changeset {
undos: Vec<Change>, // undoable changes
redos: Vec<Change>, // undone changes, redoable
- undoing: bool,
}
impl Changeset {
@@ -77,16 +78,17 @@
Changeset {
undos: Vec::new(),
redos: Vec::new(),
- undoing: false,
}
}
pub fn begin(&mut self) {
+ debug!(target: "rustyline", "Changeset::begin");
self.redos.clear();
self.undos.push(Change::Begin);
}
pub fn end(&mut self) {
+ debug!(target: "rustyline", "Changeset::end");
self.redos.clear();
if let Some(&Change::Begin) = self.undos.last() {
// emtpy Begin..End
@@ -106,6 +108,7 @@
}
pub fn insert(&mut self, idx: usize, c: char) {
+ debug!(target: "rustyline", "Changeset::insert({:?}, {:?})", idx, c);
self.redos.clear();
if !c.is_alphanumeric() {
self.undos.push(Self::insert_char(idx, c));
@@ -134,7 +137,8 @@
};
}
- pub fn insert_str<S: Into<String>>(&mut self, idx: usize, string: S) {
+ pub fn insert_str<S: Into<String> + Debug>(&mut self, idx: usize, string: S) {
+ debug!(target: "rustyline", "Changeset::insert_str({:?}, {:?})", idx, string);
self.redos.clear();
self.undos
.push(Change::Insert {
@@ -143,7 +147,8 @@
});
}
- pub fn delete<S: AsRef<str> + Into<String>>(&mut self, indx: usize, string: S) {
+ pub fn delete<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, string: S) {
+ debug!(target: "rustyline", "Changeset::delete({:?}, {:?})", indx, string);
self.redos.clear();
if !Self::single_char(string.as_ref()) {
@@ -211,7 +216,7 @@
}*/
pub fn undo(&mut self, line: &mut LineBuffer) -> bool {
- self.undoing = true;
+ debug!(target: "rustyline", "Changeset::undo");
let mut waiting_for_begin = 0;
let mut undone = false;
loop {
@@ -236,13 +241,34 @@
break;
}
}
- self.undoing = false;
undone
}
+ pub fn cancel(&mut self) {
+ debug!(target: "rustyline", "Changeset::cancel");
+ let mut waiting_for_begin = 1;
+ loop {
+ if let Some(change) = self.undos.pop() {
+ match change {
+ Change::Begin => {
+ waiting_for_begin -= 1;
+ }
+ Change::End => {
+ waiting_for_begin += 1;
+ }
+ _ => {}
+ };
+ } else {
+ break;
+ }
+ if waiting_for_begin <= 0 {
+ break;
+ }
+ }
+ }
+
#[cfg(test)]
pub fn redo(&mut self, line: &mut LineBuffer) -> bool {
- self.undoing = true;
let mut waiting_for_end = 0;
let mut redone = false;
loop {
@@ -267,28 +293,18 @@
break;
}
}
- self.undoing = false;
redone
}
}
impl ChangeListener for Changeset {
fn insert_char(&mut self, idx: usize, c: char) {
- if self.undoing {
- return;
- }
self.insert(idx, c);
}
fn insert_str(&mut self, idx: usize, string: &str) {
- if self.undoing {
- return;
- }
self.insert_str(idx, string);
}
fn delete(&mut self, idx: usize, string: &str, _: Direction) {
- if self.undoing {
- return;
- }
self.delete(idx, string);
}
}