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