1use crate::{common::*, RopeExt};
2
3#[derive(Debug, Clone)]
5pub struct Diff {
6 pub content: String,
8 pub range: Range<usize>,
10}
11
12impl Diff {
13 pub(crate) fn offset(&mut self, offset: isize) {
19 if offset >= 0 {
20 let offset = offset as usize;
21 self.range.start = self.range.start.saturating_add(offset);
22 self.range.end = self.range.end.saturating_add(offset);
23 } else {
24 let abs_offset = offset.unsigned_abs();
25 self.range.start = self.range.start.saturating_sub(abs_offset);
26 self.range.end = self.range.end.saturating_sub(abs_offset);
27 }
28 }
29
30 pub fn print(&self, content: &Rope) {
36 for change in TextDiff::from_lines(
37 &content.to_string(),
38 &content.simulate(self.clone()).to_string(),
39 )
40 .iter_all_changes()
41 {
42 let (sign, style) = match change.tag() {
43 ChangeTag::Delete => ("-", Style::new().red()),
44 ChangeTag::Insert => ("+", Style::new().green()),
45 ChangeTag::Equal => ("", Style::new()),
46 };
47 eprint!("{}{}", style.apply_to(sign).bold(), style.apply_to(change));
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 fn diff() -> Diff {
57 Diff {
58 content: "foobar".into(),
59 range: 1..4,
60 }
61 }
62
63 #[test]
64 fn offset_positive() {
65 let mut diff = diff();
66 diff.offset(1);
67 assert_eq!(diff.range, 2..5);
68 }
69
70 #[test]
71 fn offset_negative() {
72 let mut diff = diff();
73 diff.offset(-1);
74 assert_eq!(diff.range, 0..3);
75 }
76
77 #[test]
78 fn offset_negative_overflow() {
79 let mut diff = diff();
80 diff.offset(-10);
81 assert_eq!(diff.range, 0..0);
82 }
83
84 #[test]
85 fn offset_positive_large() {
86 let mut diff = diff();
87
88 diff.offset(isize::MAX);
89
90 assert_eq!(
91 diff.range,
92 (1 + isize::MAX as usize)..(4 + isize::MAX as usize)
93 );
94 }
95
96 #[test]
97 fn offset_negative_large() {
98 let mut diff = diff();
99 diff.offset(isize::MIN);
100 assert_eq!(diff.range, 0..0);
101 }
102}