1use crate::ChangesetMulti;
2
3use super::{Changeset, Difference};
4use std::{char::REPLACEMENT_CHARACTER, fmt};
5
6impl fmt::Display for Changeset {
7 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8 for d in &self.diffs {
9 match *d {
10 Difference::Same(ref x) => {
11 write!(f, "{}{}", x, self.split)?;
12 }
13 Difference::Add(ref x) => {
14 write!(f, "\x1b[92m{}\x1b[0m{}", x, self.split)?;
15 }
16 Difference::Rem(ref x) => {
17 write!(f, "\x1b[91m{}\x1b[0m{}", x, self.split)?;
18 }
19 }
20 }
21 Ok(())
22 }
23}
24
25impl fmt::Display for ChangesetMulti {
26 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27 let mut orig_counter = 0;
28 let mut edit_counter = 0;
29 for d in &self.diffs {
30 match *d {
31 Difference::Same(ref x) => {
32 let orig = x.as_str().split(REPLACEMENT_CHARACTER).collect::<Vec<_>>();
33 for word in orig {
34 orig_counter += word.len();
35 edit_counter += word.len();
36 if let Some(split) = self
37 .splits
38 .iter()
39 .find(|(idx, _split)| idx == &orig_counter)
40 {
41 orig_counter += split.1.len();
42 edit_counter += split.1.len();
43 write!(f, "{}{}", word, split.1)?;
44 } else {
45 write!(f, "{word}")?;
46 }
47 }
48 }
49 Difference::Add(ref x) => {
50 let edit = x.as_str().split(REPLACEMENT_CHARACTER).collect::<Vec<_>>();
51 for word in edit {
52 edit_counter += word.len();
53 if let Some(split) = self
54 .edit_splits
55 .iter()
56 .find(|(idx, _split)| idx == &edit_counter)
57 {
58 edit_counter += split.1.len();
59 write!(f, "\x1b[92m{}\x1b[0m{}", word, split.1)?;
60 } else {
61 write!(f, "\x1b[92m{word}\x1b[0m")?;
62 }
63 }
64 }
65 Difference::Rem(ref x) => {
66 let orig = x.as_str().split(REPLACEMENT_CHARACTER).collect::<Vec<_>>();
67 for word in orig {
68 orig_counter += word.len();
69 if let Some(split) = self
70 .splits
71 .iter()
72 .find(|(idx, _split)| idx == &orig_counter)
73 {
74 orig_counter += split.1.len();
75 write!(f, "\x1b[91m{}\x1b[0m{}", word, split.1)?;
76 } else {
77 write!(f, "\x1b[91m{word}\x1b[0m")?;
78 }
79 }
80 }
81 }
82 }
83 Ok(())
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::super::Changeset;
90 use std::io::Write;
91 use std::thread;
92 use std::time;
93
94 fn vb(b: &'static [u8]) -> Vec<u8> {
96 b.to_vec()
97 }
98
99 #[allow(dead_code)]
102 fn debug_bytes(result: &[u8], expected: &[u8]) {
103 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
106 thread::sleep(time::Duration::new(0, 2e8 as u32));
107 println!("Debug Result:");
108 for b in result {
109 print!("{}", *b as char);
110 }
111 println!("Repr Result:");
112 repr_bytes(result);
113 println!();
114 println!("--Result Repr DONE");
115
116 println!("Debug Expected:");
117 for b in expected {
118 print!("{}", *b as char);
119 }
120 println!("Repr Expected:");
121 repr_bytes(expected);
122 println!();
123 println!("--Expected Repr DONE");
124 }
125
126 fn repr_bytes(bytes: &[u8]) {
129 for b in bytes {
130 match *b {
131 b'\n' => print!("\\n"),
133 b'\r' => print!("\\r"),
134 32..=126 => print!("{}", *b as char), _ => print!(r"\x{b:0>2x}"),
136 }
137 }
138 }
139
140 #[test]
141 fn test_display() {
142 let text1 = "Roses are red, violets are blue,\n\
143 I wrote this library,\n\
144 just for you.\n\
145 (It's true).";
146
147 let text2 = "Roses are red, violets are blue,\n\
148 I wrote this documentation,\n\
149 just for you.\n\
150 (It's quite true).";
151 let expected = b"Roses are red, violets are blue,\n\x1b[91mI wrote this library,\x1b\
152 [0m\n\x1b[92mI wrote this documentation,\x1b[0m\njust for you.\n\x1b\
153 [91m(It's true).\x1b[0m\n\x1b[92m(It's quite true).\x1b[0m\n";
154
155 let ch = Changeset::new(text1, text2, "\n");
156 let mut result: Vec<u8> = Vec::new();
157 write!(result, "{ch}").unwrap();
158 debug_bytes(&result, expected);
159 assert_eq!(result, vb(expected));
160 }
161
162 #[test]
163 fn test_display_multi() {
164 let text1 = "https://localhost:8080/path?query=value";
165 let text2 = "https://myapi.com/api/path?query=asset";
166 let expected = b"https://\x1b[91mlocalhost:8080/\x1b[0m\x1b[92mmyapi.com/api/\x1b[0mpath?query=\x1b[91mvalue\x1b[0m\x1b[92masset\x1b[0m";
167
168 let cg = Changeset::new_multi(text1, text2, &["://", "/", "?", "="]);
169 let mut result: Vec<u8> = Vec::new();
170 write!(result, "{cg}").unwrap();
171 debug_bytes(&result, expected);
172 assert_eq!(result, vb(expected));
173 }
174}