1use std::fmt::Debug;
3
4use keymap::RepeatCount;
5use line_buffer::{ChangeListener, DeleteListener, Direction, LineBuffer};
6use unicode_segmentation::UnicodeSegmentation;
7
8enum Change {
9 Begin,
10 End,
11 Insert {
12 idx: usize,
13 text: String,
14 }, Delete {
16 idx: usize,
17 text: String,
18 }, Replace {
22 idx: usize,
23 old: String,
24 new: String,
25 }, }
28
29impl Change {
30 fn undo(&self, line: &mut LineBuffer) {
31 match *self {
32 Change::Begin | Change::End => {
33 unreachable!();
34 }
35 Change::Insert { idx, ref text } => {
36 line.delete_range(idx..idx + text.len());
37 }
38 Change::Delete { idx, ref text } => {
39 line.insert_str(idx, text);
40 line.set_pos(idx + text.len());
41 }
42 Change::Replace {
43 idx,
44 ref old,
45 ref new,
46 } => {
47 line.replace(idx..idx + new.len(), old);
48 }
49 }
50 }
51
52 #[cfg(test)]
53 fn redo(&self, line: &mut LineBuffer) {
54 match *self {
55 Change::Begin | Change::End => {
56 unreachable!();
57 }
58 Change::Insert { idx, ref text } => {
59 line.insert_str(idx, text);
60 }
61 Change::Delete { idx, ref text } => {
62 line.delete_range(idx..idx + text.len());
63 }
64 Change::Replace {
65 idx,
66 ref old,
67 ref new,
68 } => {
69 line.replace(idx..idx + old.len(), new);
70 }
71 }
72 }
73
74 fn insert_seq(&self, indx: usize) -> bool {
75 if let Change::Insert { idx, ref text } = *self {
76 idx + text.len() == indx
77 } else {
78 false
79 }
80 }
81
82 fn delete_seq(&self, indx: usize, len: usize) -> bool {
83 if let Change::Delete { idx, .. } = *self {
84 idx == indx || idx == indx + len
86 } else {
87 false
88 }
89 }
90
91 fn replace_seq(&self, indx: usize) -> bool {
92 if let Change::Replace { idx, ref new, .. } = *self {
93 idx + new.len() == indx
94 } else {
95 false
96 }
97 }
98}
99
100pub struct Changeset {
101 undo_group_level: u32,
102 undos: Vec<Change>, redos: Vec<Change>, }
105
106impl Changeset {
107 pub fn new() -> Changeset {
108 Changeset {
109 undo_group_level: 0,
110 undos: Vec::new(),
111 redos: Vec::new(),
112 }
113 }
114
115 pub fn begin(&mut self) -> usize {
116 debug!(target: "rustyline", "Changeset::begin");
117 self.redos.clear();
118 let mark = self.undos.len();
119 self.undos.push(Change::Begin);
120 self.undo_group_level += 1;
121 mark
122 }
123
124 pub fn end(&mut self) {
125 debug!(target: "rustyline", "Changeset::end");
126 self.redos.clear();
127 while self.undo_group_level > 0 {
128 self.undo_group_level -= 1;
129 if let Some(&Change::Begin) = self.undos.last() {
130 self.undos.pop();
132 } else {
133 self.undos.push(Change::End);
134 }
135 }
136 }
137
138 fn insert_char(idx: usize, c: char) -> Change {
139 let mut text = String::new();
140 text.push(c);
141 Change::Insert { idx, text }
142 }
143
144 pub fn insert(&mut self, idx: usize, c: char) {
145 debug!(target: "rustyline", "Changeset::insert({}, {:?})", idx, c);
146 self.redos.clear();
147 if !c.is_alphanumeric() || !self.undos.last().map_or(false, |lc| lc.insert_seq(idx)) {
148 self.undos.push(Self::insert_char(idx, c));
149 return;
150 }
151 let mut last_change = self.undos.pop().unwrap();
153 if let Change::Insert { ref mut text, .. } = last_change {
154 text.push(c);
155 } else {
156 unreachable!();
157 }
158 self.undos.push(last_change);
159 }
160
161 pub fn insert_str<S: AsRef<str> + Into<String> + Debug>(&mut self, idx: usize, string: S) {
162 debug!(target: "rustyline", "Changeset::insert_str({}, {:?})", idx, string);
163 self.redos.clear();
164 if string.as_ref().is_empty() {
165 return;
166 }
167 self.undos.push(Change::Insert {
168 idx,
169 text: string.into(),
170 });
171 }
172
173 pub fn delete<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, string: S) {
174 debug!(target: "rustyline", "Changeset::delete({}, {:?})", indx, string);
175 self.redos.clear();
176 if string.as_ref().is_empty() {
177 return;
178 }
179
180 if !Self::single_char(string.as_ref()) || !self
181 .undos
182 .last()
183 .map_or(false, |lc| lc.delete_seq(indx, string.as_ref().len()))
184 {
185 self.undos.push(Change::Delete {
186 idx: indx,
187 text: string.into(),
188 });
189 return;
190 }
191 let mut last_change = self.undos.pop().unwrap();
193 if let Change::Delete {
194 ref mut idx,
195 ref mut text,
196 } = last_change
197 {
198 if *idx == indx {
199 text.push_str(string.as_ref());
200 } else {
201 text.insert_str(0, string.as_ref());
202 *idx = indx;
203 }
204 } else {
205 unreachable!();
206 }
207 self.undos.push(last_change);
208 }
209
210 fn single_char(s: &str) -> bool {
211 let mut graphemes = s.graphemes(true);
212 graphemes.next().map_or(false, |grapheme| {
213 grapheme.chars().all(|c| c.is_alphanumeric())
214 }) && graphemes.next().is_none()
215 }
216
217 pub fn replace<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, old_: S, new_: S) {
218 debug!(target: "rustyline", "Changeset::replace({}, {:?}, {:?})", indx, old_, new_);
219 self.redos.clear();
220
221 if !self.undos.last().map_or(false, |lc| lc.replace_seq(indx)) {
222 self.undos.push(Change::Replace {
223 idx: indx,
224 old: old_.into(),
225 new: new_.into(),
226 });
227 return;
228 }
229
230 let mut last_change = self.undos.pop().unwrap();
232 if let Change::Replace {
233 ref mut old,
234 ref mut new,
235 ..
236 } = last_change
237 {
238 old.push_str(old_.as_ref());
239 new.push_str(new_.as_ref());
240 } else {
241 unreachable!();
242 }
243 self.undos.push(last_change);
244 }
245
246 pub fn undo(&mut self, line: &mut LineBuffer, n: RepeatCount) -> bool {
247 debug!(target: "rustyline", "Changeset::undo");
248 let mut count = 0;
249 let mut waiting_for_begin = 0;
250 let mut undone = false;
251 loop {
252 if let Some(change) = self.undos.pop() {
253 match change {
254 Change::Begin => {
255 waiting_for_begin -= 1;
256 }
257 Change::End => {
258 waiting_for_begin += 1;
259 }
260 _ => {
261 change.undo(line);
262 undone = true;
263 }
264 };
265 self.redos.push(change);
266 } else {
267 break;
268 }
269 if waiting_for_begin <= 0 {
270 count += 1;
271 if count >= n {
272 break;
273 }
274 }
275 }
276 undone
277 }
278
279 pub fn truncate(&mut self, len: usize) {
280 debug!(target: "rustyline", "Changeset::truncate({})", len);
281 self.undos.truncate(len);
282 }
283
284 #[cfg(test)]
285 pub fn redo(&mut self, line: &mut LineBuffer) -> bool {
286 let mut waiting_for_end = 0;
287 let mut redone = false;
288 loop {
289 if let Some(change) = self.redos.pop() {
290 match change {
291 Change::Begin => {
292 waiting_for_end += 1;
293 }
294 Change::End => {
295 waiting_for_end -= 1;
296 }
297 _ => {
298 change.redo(line);
299 redone = true;
300 }
301 };
302 self.undos.push(change);
303 } else {
304 break;
305 }
306 if waiting_for_end <= 0 {
307 break;
308 }
309 }
310 redone
311 }
312
313 pub fn last_insert(&self) -> Option<String> {
314 for change in self.undos.iter().rev() {
315 match change {
316 Change::Insert { ref text, .. } => return Some(text.to_owned()),
317 Change::Replace { ref new, .. } => return Some(new.to_owned()),
318 Change::End => {
319 continue;
320 }
321 _ => {
322 return None;
323 }
324 }
325 }
326 None
327 }
328}
329
330impl DeleteListener for Changeset {
331 fn start_killing(&mut self) {}
332
333 fn delete(&mut self, idx: usize, string: &str, _: Direction) {
334 self.delete(idx, string);
335 }
336
337 fn stop_killing(&mut self) {}
338}
339impl ChangeListener for Changeset {
340 fn insert_char(&mut self, idx: usize, c: char) {
341 self.insert(idx, c);
342 }
343
344 fn insert_str(&mut self, idx: usize, string: &str) {
345 self.insert_str(idx, string);
346 }
347
348 fn replace(&mut self, idx: usize, old: &str, new: &str) {
349 self.replace(idx, old, new);
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use super::Changeset;
356 use line_buffer::LineBuffer;
357
358 #[test]
359 fn test_insert_chars() {
360 let mut cs = Changeset::new();
361 cs.insert(0, 'H');
362 cs.insert(1, 'i');
363 assert_eq!(1, cs.undos.len());
364 assert_eq!(0, cs.redos.len());
365 cs.insert(0, ' ');
366 assert_eq!(2, cs.undos.len());
367 }
368
369 #[test]
370 fn test_insert_strings() {
371 let mut cs = Changeset::new();
372 cs.insert_str(0, "Hello");
373 cs.insert_str(5, ", ");
374 assert_eq!(2, cs.undos.len());
375 assert_eq!(0, cs.redos.len());
376 }
377
378 #[test]
379 fn test_undo_insert() {
380 let mut buf = LineBuffer::init("", 0, None);
381 buf.insert_str(0, "Hello");
382 buf.insert_str(5, ", world!");
383 let mut cs = Changeset::new();
384 assert_eq!(buf.as_str(), "Hello, world!");
385
386 cs.insert_str(5, ", world!");
387
388 cs.undo(&mut buf, 1);
389 assert_eq!(0, cs.undos.len());
390 assert_eq!(1, cs.redos.len());
391 assert_eq!(buf.as_str(), "Hello");
392
393 cs.redo(&mut buf);
394 assert_eq!(1, cs.undos.len());
395 assert_eq!(0, cs.redos.len());
396 assert_eq!(buf.as_str(), "Hello, world!");
397 }
398
399 #[test]
400 fn test_undo_delete() {
401 let mut buf = LineBuffer::init("", 0, None);
402 buf.insert_str(0, "Hello");
403 let mut cs = Changeset::new();
404 assert_eq!(buf.as_str(), "Hello");
405
406 cs.delete(5, ", world!");
407
408 cs.undo(&mut buf, 1);
409 assert_eq!(buf.as_str(), "Hello, world!");
410
411 cs.redo(&mut buf);
412 assert_eq!(buf.as_str(), "Hello");
413 }
414
415 #[test]
416 fn test_delete_chars() {
417 let mut buf = LineBuffer::init("", 0, None);
418 buf.insert_str(0, "Hlo");
419
420 let mut cs = Changeset::new();
421 cs.delete(1, "e");
422 cs.delete(1, "l");
423 assert_eq!(1, cs.undos.len());
424
425 cs.undo(&mut buf, 1);
426 assert_eq!(buf.as_str(), "Hello");
427 }
428
429 #[test]
430 fn test_backspace_chars() {
431 let mut buf = LineBuffer::init("", 0, None);
432 buf.insert_str(0, "Hlo");
433
434 let mut cs = Changeset::new();
435 cs.delete(2, "l");
436 cs.delete(1, "e");
437 assert_eq!(1, cs.undos.len());
438
439 cs.undo(&mut buf, 1);
440 assert_eq!(buf.as_str(), "Hello");
441 }
442
443 #[test]
444 fn test_undo_replace() {
445 let mut buf = LineBuffer::init("", 0, None);
446 buf.insert_str(0, "Hello, world!");
447 let mut cs = Changeset::new();
448 assert_eq!(buf.as_str(), "Hello, world!");
449
450 buf.replace(1..5, "i");
451 assert_eq!(buf.as_str(), "Hi, world!");
452 cs.replace(1, "ello", "i");
453
454 cs.undo(&mut buf, 1);
455 assert_eq!(buf.as_str(), "Hello, world!");
456
457 cs.redo(&mut buf);
458 assert_eq!(buf.as_str(), "Hi, world!");
459 }
460
461 #[test]
462 fn test_last_insert() {
463 let mut cs = Changeset::new();
464 cs.begin();
465 cs.delete(0, "Hello");
466 cs.insert_str(0, "Bye");
467 cs.end();
468 let insert = cs.last_insert();
469 assert_eq!(Some("Bye".to_owned()), insert);
470 }
471}