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