1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use similar::{ChangeTag, TextDiff};
use unicode_width::UnicodeWidthStr;
pub fn create_side_by_side_diff(text1: &str, text2: &str, max_width: usize) -> String {
TextDiff::from_lines(text1, text2)
.iter_all_changes()
.map(|change| {
let content = change.to_string().trim_end_matches('\n').to_string();
let width = max_width - (content.width() - content.chars().count());
match change.tag() {
ChangeTag::Delete => format!(
"{:>6} | {:<width$} | {:>6} | {:<blank_width$} |",
change.old_index().unwrap() + 1,
content,
"",
"",
blank_width = max_width,
width = width,
),
ChangeTag::Insert => format!(
"{:>6} | {:<blank_width$} | {:>6} | {:<width$} |",
"",
"",
change.new_index().unwrap() + 1,
content,
blank_width = max_width,
width = width
),
ChangeTag::Equal => format!(
"{:>6} | {token:<width$} | {:>6} | {token:<width$} |",
change.old_index().unwrap() + 1,
change.new_index().unwrap() + 1,
token = content,
width = width
),
}
})
.collect::<Vec<_>>()
.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let actual = create_side_by_side_diff(
"
あああ
bbb
ccc
ddd
いいいいいーeee
かかお
FFFFFFFFFF
ggg"
.trim_matches('\n'),
"
あああ
bbb
いいいいいーeee
かかか
ffffffffff
ggg"
.trim_matches('\n'),
20,
);
let expected = "
1 | あああ | 1 | あああ |
2 | bbb | 2 | bbb |
3 | ccc | | |
4 | ddd | | |
5 | いいいいいーeee | 3 | いいいいいーeee |
6 | かかお | | |
7 | FFFFFFFFFF | | |
| | 4 | かかか |
| | 5 | ffffffffff |
8 | ggg | 6 | ggg |
"
.trim_matches('\n');
assert_eq!(expected, actual);
}
}