From cf92421be4eb4302a7c9a209bec9b096cd6b57c9 Mon Sep 17 00:00:00 2001 From: gwenn <gtreguier@gmail.com> Date: Sun, 2 Apr 2017 10:03:37 +0200 Subject: [PATCH] Do not remove change listeners but disable them --- src/completion.rs | 4 +++- src/kill_ring.rs | 12 +++++++++++ src/lib.rs | 40 +++++++++++++++++----------------- src/line_buffer.rs | 32 +++++++++++++-------------- src/undo.rs | 54 +++++++++++++++++++++++++++++++--------------- 5 files changed, 88 insertions(+), 54 deletions(-) diff --git a/src/completion.rs b/src/completion.rs index 28bb8e99..6b049109 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -130,7 +130,9 @@ pub fn escape(input: String, esc_char: Option<char>, break_chars: &BTreeSet<char return input; } let esc_char = esc_char.unwrap(); - let n = input.chars().filter(|c| break_chars.contains(c)).count(); + let n = input.chars() + .filter(|c| break_chars.contains(c)) + .count(); if n == 0 { return input; } diff --git a/src/kill_ring.rs b/src/kill_ring.rs index d28f9203..d76d94b1 100644 --- a/src/kill_ring.rs +++ b/src/kill_ring.rs @@ -20,6 +20,7 @@ pub struct KillRing { index: usize, // whether or not the last command was a kill or a yank last_action: Action, + killing: bool, } impl KillRing { @@ -29,9 +30,17 @@ impl KillRing { slots: Vec::with_capacity(size), index: 0, last_action: Action::Other, + killing: false, } } + pub fn start_killing(&mut self) { + self.killing = true; + } + pub fn stop_killing(&mut self) { + self.killing = false; + } + /// Reset `last_action` state. pub fn reset(&mut self) { self.last_action = Action::Other; @@ -107,6 +116,9 @@ impl ChangeListener for KillRing { fn insert_char(&mut self, _: usize, _: char) {} fn insert_str(&mut self, _: usize, _: &str) {} fn delete(&mut self, _: usize, string: &str, dir: Direction) { + if !self.killing { + return; + } let mode = match dir { Direction::Forward => Mode::Append, Direction::Backward => Mode::Prepend, diff --git a/src/lib.rs b/src/lib.rs index b4cdbda0..d5326c3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -214,7 +214,8 @@ impl<'out, 'prompt> State<'out, 'prompt> { let mut info = try!(self.term.get_console_screen_buffer_info()); info.dwCursorPosition.X = 0; info.dwCursorPosition.Y -= self.cursor.row as i16; - try!(self.term.set_console_cursor_position(info.dwCursorPosition)); + try!(self.term + .set_console_cursor_position(info.dwCursorPosition)); let mut _count = 0; try!(self.term .fill_console_output_character((info.dwSize.X * (self.old_rows as i16 + 1)) as u32, @@ -230,7 +231,8 @@ impl<'out, 'prompt> State<'out, 'prompt> { let mut info = try!(self.term.get_console_screen_buffer_info()); info.dwCursorPosition.X = cursor.col as i16; info.dwCursorPosition.Y -= (end_pos.row - cursor.row) as i16; - try!(self.term.set_console_cursor_position(info.dwCursorPosition)); + try!(self.term + .set_console_cursor_position(info.dwCursorPosition)); self.cursor = cursor; self.old_rows = end_pos.row; @@ -838,9 +840,6 @@ fn reverse_incremental_search<R: RawReader>(rdr: &mut R, Ok(Some(cmd)) } -static KILL_RING_NAME: &'static str = "kill_ring"; -static UNDOS_NAME: &'static str = "undos"; - /// Handles reading and editting the readline buffer. /// It will also handle special inputs in an appropriate fashion /// (e.g., C-c will exit readline) @@ -860,7 +859,10 @@ fn readline_edit<C: Completer>(prompt: &str, prompt, editor.history.len(), editor.custom_bindings.clone()); - s.line.bind(UNDOS_NAME, s.changes.clone()); + + s.line.bind(s.changes.clone()); + s.line.bind(editor.kill_ring.clone()); + try!(s.refresh_line()); let mut rdr = try!(s.term.create_reader(&editor.config)); @@ -945,15 +947,15 @@ fn readline_edit<C: Completer>(prompt: &str, } Cmd::Kill(Movement::EndOfLine) => { // Kill the text from point to the end of the line. - s.line.bind(KILL_RING_NAME, editor.kill_ring.clone()); + editor.kill_ring.borrow_mut().start_killing(); try!(edit_kill_line(&mut s)); - s.line.unbind(KILL_RING_NAME); + editor.kill_ring.borrow_mut().stop_killing(); } Cmd::Kill(Movement::WholeLine) => { try!(edit_move_home(&mut s)); - s.line.bind(KILL_RING_NAME, editor.kill_ring.clone()); + editor.kill_ring.borrow_mut().start_killing(); try!(edit_kill_line(&mut s)); - s.line.unbind(KILL_RING_NAME); + editor.kill_ring.borrow_mut().stop_killing(); } Cmd::ClearScreen => { // Clear the screen leaving the current line at the top of the screen. @@ -974,9 +976,9 @@ fn readline_edit<C: Completer>(prompt: &str, } Cmd::Kill(Movement::BeginningOfLine) => { // Kill backward from point to the beginning of the line. - s.line.bind(KILL_RING_NAME, editor.kill_ring.clone()); + editor.kill_ring.borrow_mut().start_killing(); try!(edit_discard_line(&mut s)); - s.line.unbind(KILL_RING_NAME); + editor.kill_ring.borrow_mut().stop_killing(); } #[cfg(unix)] Cmd::QuotedInsert => { @@ -1003,9 +1005,9 @@ fn readline_edit<C: Completer>(prompt: &str, } Cmd::Kill(Movement::BackwardWord(n, word_def)) => { // kill one word backward (until start of word) - s.line.bind(KILL_RING_NAME, editor.kill_ring.clone()); + editor.kill_ring.borrow_mut().start_killing(); try!(edit_delete_prev_word(&mut s, word_def, n)); - s.line.unbind(KILL_RING_NAME); + editor.kill_ring.borrow_mut().stop_killing(); } Cmd::BeginningOfHistory => { // move to first entry in history @@ -1025,9 +1027,9 @@ fn readline_edit<C: Completer>(prompt: &str, } Cmd::Kill(Movement::ForwardWord(n, at, word_def)) => { // kill one word forward (until start/end of word) - s.line.bind(KILL_RING_NAME, editor.kill_ring.clone()); + editor.kill_ring.borrow_mut().start_killing(); try!(edit_delete_word(&mut s, at, word_def, n)); - s.line.unbind(KILL_RING_NAME); + editor.kill_ring.borrow_mut().stop_killing(); } Cmd::Move(Movement::ForwardWord(n, at, word_def)) => { // move forwards one word @@ -1053,16 +1055,14 @@ fn readline_edit<C: Completer>(prompt: &str, } Cmd::Move(Movement::ViCharSearch(n, cs)) => try!(edit_move_to(&mut s, cs, n)), Cmd::Kill(Movement::ViCharSearch(n, cs)) => { - s.line.bind(KILL_RING_NAME, editor.kill_ring.clone()); + editor.kill_ring.borrow_mut().start_killing(); try!(edit_delete_to(&mut s, cs, n)); - s.line.unbind(KILL_RING_NAME); + editor.kill_ring.borrow_mut().stop_killing(); } Cmd::Undo => { - s.line.unbind(UNDOS_NAME); if s.changes.borrow_mut().undo(&mut s.line) { try!(s.refresh_line()); } - s.line.bind(UNDOS_NAME, s.changes.clone()); } Cmd::Interrupt => { return Err(error::ReadlineError::Interrupted); diff --git a/src/line_buffer.rs b/src/line_buffer.rs index ce05691f..21fe051a 100644 --- a/src/line_buffer.rs +++ b/src/line_buffer.rs @@ -1,6 +1,5 @@ //! Line buffer with current cursor position use std::cell::RefCell; -use std::collections::HashMap; use std::fmt; use std::iter; use std::ops::{Deref, Range}; @@ -40,7 +39,7 @@ pub trait ChangeListener { pub struct LineBuffer { buf: String, // Edited line buffer pos: usize, // Current cursor position (byte position) - cl: HashMap<&'static str, Rc<RefCell<ChangeListener>>>, + cl: Vec<Rc<RefCell<ChangeListener>>>, } impl fmt::Debug for LineBuffer { @@ -58,7 +57,7 @@ impl LineBuffer { LineBuffer { buf: String::with_capacity(capacity), pos: 0, - cl: HashMap::new(), + cl: Vec::new(), } } @@ -68,16 +67,13 @@ impl LineBuffer { assert!(lb.insert_str(0, line)); lb.set_pos(pos); if cl.is_some() { - lb.bind("test", cl.unwrap()); + lb.bind(cl.unwrap()); } lb } - pub fn bind(&mut self, key: &'static str, cl: Rc<RefCell<ChangeListener>>) { - self.cl.insert(key, cl); - } - pub fn unbind(&mut self, key: &'static str) { - self.cl.remove(key); + pub fn bind(&mut self, cl: Rc<RefCell<ChangeListener>>) { + self.cl.push(cl); } /// Extracts a string slice containing the entire buffer. @@ -179,7 +175,7 @@ impl LineBuffer { let push = self.pos == self.buf.len(); if n == 1 { self.buf.insert(self.pos, ch); - for cl in self.cl.values() { + for cl in &self.cl { cl.borrow_mut().insert_char(self.pos, ch); } } else { @@ -269,7 +265,8 @@ impl LineBuffer { match self.next_pos(n) { Some(pos) => { let start = self.pos; - let chars = self.drain(start..pos, Direction::Forward).collect::<String>(); + let chars = self.drain(start..pos, Direction::Forward) + .collect::<String>(); Some(chars) } None => None, @@ -573,7 +570,8 @@ impl LineBuffer { if start == end { return false; } - let word = self.drain(start..end, Direction::default()).collect::<String>(); + let word = self.drain(start..end, Direction::default()) + .collect::<String>(); let result = match a { WordAction::CAPITALIZE => { let ch = (&word).graphemes(true).next().unwrap(); @@ -608,7 +606,8 @@ impl LineBuffer { let w1 = self.buf[w1_beg..w1_end].to_owned(); - let w2 = self.drain(w2_beg..w2_end, Direction::default()).collect::<String>(); + let w2 = self.drain(w2_beg..w2_end, Direction::default()) + .collect::<String>(); self.insert_str(w2_beg, &w1); self.drain(w1_beg..w1_end, Direction::default()); @@ -628,7 +627,7 @@ impl LineBuffer { } pub fn insert_str(&mut self, idx: usize, s: &str) -> bool { - for cl in self.cl.values() { + for cl in &self.cl { cl.borrow_mut().insert_str(idx, s); } if idx == self.buf.len() { @@ -646,8 +645,9 @@ impl LineBuffer { } fn drain(&mut self, range: Range<usize>, dir: Direction) -> Drain { - for cl in self.cl.values() { - cl.borrow_mut().delete(range.start, &self.buf[range.start..range.end], dir); + for cl in &self.cl { + cl.borrow_mut() + .delete(range.start, &self.buf[range.start..range.end], dir); } self.buf.drain(range) } diff --git a/src/undo.rs b/src/undo.rs index fce9e75a..e77f33c4 100644 --- a/src/undo.rs +++ b/src/undo.rs @@ -69,6 +69,7 @@ impl Change { pub struct Changeset { undos: Vec<Change>, // undoable changes redos: Vec<Change>, // undone changes, redoable + undoing: bool, } impl Changeset { @@ -76,6 +77,7 @@ impl Changeset { Changeset { undos: Vec::new(), redos: Vec::new(), + undoing: false, } } @@ -134,20 +136,22 @@ impl Changeset { pub fn insert_str<S: Into<String>>(&mut self, idx: usize, string: S) { self.redos.clear(); - self.undos.push(Change::Insert { - idx: idx, - text: string.into(), - }); + self.undos + .push(Change::Insert { + idx: idx, + text: string.into(), + }); } pub fn delete<S: AsRef<str> + Into<String>>(&mut self, indx: usize, string: S) { self.redos.clear(); if !Self::single_char(string.as_ref()) { - self.undos.push(Change::Delete { - idx: indx, - text: string.into(), - }); + self.undos + .push(Change::Delete { + idx: indx, + text: string.into(), + }); return; } let last_change = self.undos.pop(); @@ -169,24 +173,27 @@ impl Changeset { self.undos.push(last_change); } else { self.undos.push(last_change); - self.undos.push(Change::Delete { - idx: indx, - text: string.into(), - }); + self.undos + .push(Change::Delete { + idx: indx, + text: string.into(), + }); } } None => { - self.undos.push(Change::Delete { - idx: indx, - text: string.into(), - }); + self.undos + .push(Change::Delete { + idx: indx, + text: string.into(), + }); } }; } fn single_char(s: &str) -> bool { let mut graphemes = s.graphemes(true); - graphemes.next().map_or(false, |grapheme| grapheme.is_alphanumeric()) && + graphemes.next() + .map_or(false, |grapheme| grapheme.is_alphanumeric()) && graphemes.next().is_none() } @@ -200,6 +207,7 @@ impl Changeset { }*/ pub fn undo(&mut self, line: &mut LineBuffer) -> bool { + self.undoing = true; let mut waiting_for_begin = 0; let mut undone = false; loop { @@ -224,11 +232,13 @@ impl Changeset { break; } } + self.undoing = false; undone } #[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 { @@ -253,18 +263,28 @@ impl Changeset { 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); } } -- GitLab