|
3 | 3 | use lazy_static::lazy_static;
|
4 | 4 | use line_numbers::{LinePositions, SingleLineSpan};
|
5 | 5 | use regex::Regex;
|
| 6 | +use std::hash::Hash; |
6 | 7 |
|
7 | 8 | use crate::words::split_words;
|
8 | 9 | use crate::{
|
@@ -73,24 +74,66 @@ fn merge_novel<'a>(
|
73 | 74 | res
|
74 | 75 | }
|
75 | 76 |
|
| 77 | +#[derive(Debug, Clone)] |
| 78 | +struct StringIgnoringNewline<'a>(&'a str); |
| 79 | + |
| 80 | +impl PartialEq for StringIgnoringNewline<'_> { |
| 81 | + fn eq(&self, other: &Self) -> bool { |
| 82 | + let mut s = self.0; |
| 83 | + if s.ends_with('\n') { |
| 84 | + s = &s[..s.len() - 1]; |
| 85 | + } |
| 86 | + |
| 87 | + let mut other_s = other.0; |
| 88 | + if other_s.ends_with('\n') { |
| 89 | + other_s = &other_s[..other_s.len() - 1]; |
| 90 | + } |
| 91 | + |
| 92 | + s == other_s |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +impl Eq for StringIgnoringNewline<'_> {} |
| 97 | + |
| 98 | +impl Hash for StringIgnoringNewline<'_> { |
| 99 | + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { |
| 100 | + let mut s = self.0; |
| 101 | + if s.ends_with('\n') { |
| 102 | + s = &s[..s.len() - 1]; |
| 103 | + } |
| 104 | + |
| 105 | + s.hash(state); |
| 106 | + } |
| 107 | +} |
| 108 | + |
76 | 109 | fn changed_parts<'a>(
|
77 | 110 | src: &'a str,
|
78 | 111 | opposite_src: &'a str,
|
79 | 112 | ) -> Vec<(TextChangeKind, Vec<&'a str>, Vec<&'a str>)> {
|
80 |
| - let src_lines = split_lines_keep_newline(src); |
81 |
| - let opposite_src_lines = split_lines_keep_newline(opposite_src); |
| 113 | + let src_lines = split_lines_keep_newline(src) |
| 114 | + .into_iter() |
| 115 | + .map(StringIgnoringNewline) |
| 116 | + .collect::<Vec<_>>(); |
| 117 | + let opposite_src_lines = split_lines_keep_newline(opposite_src) |
| 118 | + .into_iter() |
| 119 | + .map(StringIgnoringNewline) |
| 120 | + .collect::<Vec<_>>(); |
82 | 121 |
|
83 | 122 | let mut res: Vec<(TextChangeKind, Vec<&'a str>, Vec<&'a str>)> = vec![];
|
84 | 123 | for diff_res in myers_diff::slice_unique_by_hash(&src_lines, &opposite_src_lines) {
|
85 | 124 | match diff_res {
|
86 | 125 | myers_diff::DiffResult::Left(line) => {
|
87 |
| - res.push((TextChangeKind::Novel, vec![line], vec![])); |
| 126 | + res.push((TextChangeKind::Novel, vec![line.0], vec![])); |
88 | 127 | }
|
89 | 128 | myers_diff::DiffResult::Both(line, opposite_line) => {
|
90 |
| - res.push((TextChangeKind::Unchanged, vec![line], vec![opposite_line])); |
| 129 | + res.push(( |
| 130 | + TextChangeKind::Unchanged, |
| 131 | + vec![line.0], |
| 132 | + vec![opposite_line.0], |
| 133 | + )); |
91 | 134 | }
|
92 | 135 | myers_diff::DiffResult::Right(opposite_line) => {
|
93 |
| - res.push((TextChangeKind::Novel, vec![], vec![opposite_line])); |
| 136 | + res.push((TextChangeKind::Novel, vec![], vec![opposite_line.0])); |
94 | 137 | }
|
95 | 138 | }
|
96 | 139 | }
|
|
0 commit comments