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