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().is_some_and(|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 .is_some_and(|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
221 .next()
222 .is_some_and(|grapheme| grapheme.chars().all(char::is_alphanumeric))
223 && graphemes.next().is_none()
224 }
225
226 pub(crate) fn replace<S: AsRef<str> + Into<String> + Debug>(
227 &mut self,
228 indx: usize,
229 old_: S,
230 new_: S,
231 ) {
232 debug!(target: "rustyline", "Changeset::replace({indx}, {old_:?}, {new_:?})");
233 self.redos.clear();
234
235 if !self.undos.last().is_some_and(|lc| lc.replace_seq(indx)) {
236 self.undos.push(Change::Replace {
237 idx: indx,
238 old: old_.into(),
239 new: new_.into(),
240 });
241 return;
242 }
243
244 let mut last_change = self.undos.pop().unwrap();
246 if let Change::Replace {
247 ref mut old,
248 ref mut new,
249 ..
250 } = last_change
251 {
252 old.push_str(old_.as_ref());
253 new.push_str(new_.as_ref());
254 } else {
255 unreachable!();
256 }
257 self.undos.push(last_change);
258 }
259
260 pub(crate) fn undo(&mut self, line: &mut LineBuffer, n: RepeatCount) -> bool {
261 debug!(target: "rustyline", "Changeset::undo");
262 let mut count = 0;
263 let mut waiting_for_begin = 0;
264 let mut undone = false;
265 while let Some(change) = self.undos.pop() {
266 match change {
267 Change::Begin => {
268 waiting_for_begin -= 1;
269 }
270 Change::End => {
271 waiting_for_begin += 1;
272 }
273 _ => {
274 change.undo(line);
275 undone = true;
276 }
277 };
278 self.redos.push(change);
279 if waiting_for_begin <= 0 {
280 count += 1;
281 if count >= n {
282 break;
283 }
284 }
285 }
286 undone
287 }
288
289 pub(crate) fn truncate(&mut self, len: usize) {
290 debug!(target: "rustyline", "Changeset::truncate({len})");
291 self.undos.truncate(len);
292 }
293
294 #[cfg(test)]
295 pub(crate) fn redo(&mut self, line: &mut LineBuffer) -> bool {
296 let mut waiting_for_end = 0;
297 let mut redone = false;
298 while let Some(change) = self.redos.pop() {
299 match change {
300 Change::Begin => {
301 waiting_for_end += 1;
302 }
303 Change::End => {
304 waiting_for_end -= 1;
305 }
306 _ => {
307 change.redo(line);
308 redone = true;
309 }
310 };
311 self.undos.push(change);
312 if waiting_for_end <= 0 {
313 break;
314 }
315 }
316 redone
317 }
318
319 pub(crate) fn last_insert(&self) -> Option<String> {
320 for change in self.undos.iter().rev() {
321 match change {
322 Change::Insert { ref text, .. } => return Some(text.clone()),
323 Change::Replace { ref new, .. } => return Some(new.clone()),
324 Change::End => {
325 continue;
326 }
327 _ => {
328 return None;
329 }
330 }
331 }
332 None
333 }
334}
335
336impl DeleteListener for Changeset {
337 fn delete(&mut self, idx: usize, string: &str, _: Direction) {
338 self.delete(idx, string);
339 }
340}
341impl ChangeListener for Changeset {
342 fn insert_char(&mut self, idx: usize, c: char) {
343 self.insert(idx, c);
344 }
345
346 fn insert_str(&mut self, idx: usize, string: &str) {
347 self.insert_str(idx, string);
348 }
349
350 fn replace(&mut self, idx: usize, old: &str, new: &str) {
351 self.replace(idx, old, new);
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use super::Changeset;
358 use crate::line_buffer::{LineBuffer, NoListener};
359
360 #[test]
361 fn test_insert_chars() {
362 let mut cs = Changeset::new();
363 cs.insert(0, 'H');
364 cs.insert(1, 'i');
365 assert_eq!(1, cs.undos.len());
366 assert_eq!(0, cs.redos.len());
367 cs.insert(0, ' ');
368 assert_eq!(2, cs.undos.len());
369 }
370
371 #[test]
372 fn test_insert_strings() {
373 let mut cs = Changeset::new();
374 cs.insert_str(0, "Hello");
375 cs.insert_str(5, ", ");
376 assert_eq!(2, cs.undos.len());
377 assert_eq!(0, cs.redos.len());
378 }
379
380 #[test]
381 fn test_undo_insert() {
382 let mut buf = LineBuffer::init("", 0);
383 buf.insert_str(0, "Hello", &mut NoListener);
384 buf.insert_str(5, ", world!", &mut NoListener);
385 let mut cs = Changeset::new();
386 assert_eq!(buf.as_str(), "Hello, world!");
387
388 cs.insert_str(5, ", world!");
389
390 cs.undo(&mut buf, 1);
391 assert_eq!(0, cs.undos.len());
392 assert_eq!(1, cs.redos.len());
393 assert_eq!(buf.as_str(), "Hello");
394
395 cs.redo(&mut buf);
396 assert_eq!(1, cs.undos.len());
397 assert_eq!(0, cs.redos.len());
398 assert_eq!(buf.as_str(), "Hello, world!");
399 }
400
401 #[test]
402 fn test_undo_delete() {
403 let mut buf = LineBuffer::init("", 0);
404 buf.insert_str(0, "Hello", &mut NoListener);
405 let mut cs = Changeset::new();
406 assert_eq!(buf.as_str(), "Hello");
407
408 cs.delete(5, ", world!");
409
410 cs.undo(&mut buf, 1);
411 assert_eq!(buf.as_str(), "Hello, world!");
412
413 cs.redo(&mut buf);
414 assert_eq!(buf.as_str(), "Hello");
415 }
416
417 #[test]
418 fn test_delete_chars() {
419 let mut buf = LineBuffer::init("", 0);
420 buf.insert_str(0, "Hlo", &mut NoListener);
421
422 let mut cs = Changeset::new();
423 cs.delete(1, "e");
424 cs.delete(1, "l");
425 assert_eq!(1, cs.undos.len());
426
427 cs.undo(&mut buf, 1);
428 assert_eq!(buf.as_str(), "Hello");
429 }
430
431 #[test]
432 fn test_backspace_chars() {
433 let mut buf = LineBuffer::init("", 0);
434 buf.insert_str(0, "Hlo", &mut NoListener);
435
436 let mut cs = Changeset::new();
437 cs.delete(2, "l");
438 cs.delete(1, "e");
439 assert_eq!(1, cs.undos.len());
440
441 cs.undo(&mut buf, 1);
442 assert_eq!(buf.as_str(), "Hello");
443 }
444
445 #[test]
446 fn test_undo_replace() {
447 let mut buf = LineBuffer::init("", 0);
448 buf.insert_str(0, "Hello, world!", &mut NoListener);
449 let mut cs = Changeset::new();
450 assert_eq!(buf.as_str(), "Hello, world!");
451
452 buf.replace(1..5, "i", &mut NoListener);
453 assert_eq!(buf.as_str(), "Hi, world!");
454 cs.replace(1, "ello", "i");
455
456 cs.undo(&mut buf, 1);
457 assert_eq!(buf.as_str(), "Hello, world!");
458
459 cs.redo(&mut buf);
460 assert_eq!(buf.as_str(), "Hi, world!");
461 }
462
463 #[test]
464 fn test_last_insert() {
465 let mut cs = Changeset::new();
466 cs.begin();
467 cs.delete(0, "Hello");
468 cs.insert_str(0, "Bye");
469 cs.end();
470 let insert = cs.last_insert();
471 assert_eq!(Some("Bye".to_owned()), insert);
472 }
473
474 #[test]
475 fn test_end() {
476 let mut cs = Changeset::new();
477 cs.begin();
478 assert!(!cs.end());
479 cs.begin();
480 cs.insert_str(0, "Hi");
481 assert!(cs.end());
482 }
483}