|
1 | 1 | use crate::{utils, Error, Result}; |
2 | 2 | use regex::bytes::Regex; |
| 3 | +use similar::{TextDiff, ChangeTag}; |
3 | 4 | use std::{fs, fs::File, io::prelude::*, path::Path}; |
4 | 5 |
|
5 | 6 | pub(crate) struct Replacer { |
@@ -94,28 +95,61 @@ impl Replacer { |
94 | 95 | &'a self, |
95 | 96 | content: &[u8], |
96 | 97 | ) -> std::borrow::Cow<'a, [u8]> { |
| 98 | + use ansi_term::{Color, Style}; |
| 99 | + |
| 100 | + let replaced = self.replace(content); |
| 101 | + let diff = TextDiff::from_lines(&*content, &*replaced); |
| 102 | + |
97 | 103 | let mut v = Vec::<u8>::new(); |
98 | | - let mut captures = self.regex.captures_iter(content); |
99 | | - |
100 | | - self.regex.split(content).for_each(|sur_text| { |
101 | | - use regex::bytes::Replacer; |
102 | | - |
103 | | - v.extend(sur_text); |
104 | | - if let Some(capture) = captures.next() { |
105 | | - v.extend_from_slice( |
106 | | - ansi_term::Color::Green.prefix().to_string().as_bytes(), |
107 | | - ); |
108 | | - if self.is_literal { |
109 | | - regex::bytes::NoExpand(&self.replace_with) |
110 | | - .replace_append(&capture, &mut v); |
111 | | - } else { |
112 | | - (&*self.replace_with).replace_append(&capture, &mut v); |
| 104 | + |
| 105 | + for group in diff.grouped_ops(3).iter() { |
| 106 | + for op in group { |
| 107 | + for change in diff.iter_inline_changes(op) { |
| 108 | + match change.tag() { |
| 109 | + ChangeTag::Delete => { |
| 110 | + v.extend(Color::Red.prefix().to_string().as_bytes()); |
| 111 | + let idx = match change.old_index() { |
| 112 | + Some(old_idx) => format!("{:>3} ", old_idx).into_bytes(), |
| 113 | + None => b" ".to_vec(), |
| 114 | + }; |
| 115 | + v.extend(idx); |
| 116 | + v.push(b'-'); |
| 117 | + }, |
| 118 | + ChangeTag::Insert => { |
| 119 | + v.extend(Color::Green.prefix().to_string().as_bytes()); |
| 120 | + let idx = match change.new_index() { |
| 121 | + Some(new_idx) => format!("{:>3} ", new_idx).into_bytes(), |
| 122 | + None => b" ".to_vec(), |
| 123 | + }; |
| 124 | + v.extend(idx); |
| 125 | + v.push(b'+'); |
| 126 | + }, |
| 127 | + ChangeTag::Equal => { |
| 128 | + v.extend(b" "); |
| 129 | + }, |
| 130 | + } |
| 131 | + v.push(b' '); |
| 132 | + |
| 133 | + for (emphasized, value) in change.iter_strings_lossy() { |
| 134 | + if emphasized { |
| 135 | + v.extend(Style::new().bold().paint(value).as_bytes()); |
| 136 | + } else { |
| 137 | + v.extend(value.as_bytes()); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + match change.tag() { |
| 142 | + ChangeTag::Delete => v.extend(Color::Red.suffix().to_string().as_bytes()), |
| 143 | + ChangeTag::Insert => v.extend(Color::Green.suffix().to_string().as_bytes()), |
| 144 | + ChangeTag::Equal => (), |
| 145 | + } |
| 146 | + |
| 147 | + if change.missing_newline() { |
| 148 | + v.push(b'\n'); |
| 149 | + } |
113 | 150 | } |
114 | | - v.extend_from_slice( |
115 | | - ansi_term::Color::Green.suffix().to_string().as_bytes(), |
116 | | - ); |
117 | 151 | } |
118 | | - }); |
| 152 | + } |
119 | 153 |
|
120 | 154 | return std::borrow::Cow::Owned(v); |
121 | 155 | } |
|
0 commit comments