|
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