1use crate::search::{Replace, Search};
2use crate::util::{MyError, Range};
3use colored::Colorize;
4use std::str::from_utf8;
5
6pub type Content = Vec<u8>;
7type ContentSlice = [u8];
8
9pub struct Line {
10 pub nr: u64,
11 pub range: Range,
12 pub matches: Vec<Range>,
13}
14impl Line {
15 pub fn new(nr: u64, start: usize, size: usize) -> Line {
17 Line {
18 nr,
19 range: start..start + size,
20 matches: vec![],
21 }
22 }
23
24 pub fn as_slice<'a>(&self, s: &'a ContentSlice) -> &'a ContentSlice {
25 &s[self.range.clone()]
26 }
27
28 pub fn search_for(&mut self, search: &Search, content: &ContentSlice) -> bool {
29 self.matches.clear();
30 let mut found_match = false;
31 for m in search.regex.find_iter(self.as_slice(content)) {
32 self.matches.push(m.start()..m.end());
33 found_match = true;
34 }
35 found_match
36 }
37
38 pub fn print_colored(
39 &self,
40 content: &ContentSlice,
41 search: &Search,
42 replace_opt: &Option<Replace>,
43 ) {
44 let my_print = |replace_opt: &Option<Replace>| {
45 print!("{}:", format!("{}", self.nr).yellow());
46 let mut offset = 0;
47 for r in self.matches.iter() {
48 if let Ok(normal_str) = from_utf8(&content[offset..r.start]) {
49 if let Ok(match_str) = from_utf8(&content[r.start..r.end]) {
50 print!("{}", normal_str);
51 match &replace_opt {
52 None => print!("{}", match_str.bright_cyan().bold()),
53 Some(replace) => {
54 let caps = search.regex.captures(match_str.as_bytes());
55 for (capture_ix, part) in &replace.parts {
56 if *capture_ix >= 0 {
57 if caps.is_none() {
58 fail!("Could not search for capture groups, but they are used here. This happens when a search with word boundary does not match in the substring match_str");
59 }
60 print!(
61 "{}",
62 from_utf8(
63 caps.as_ref()
64 .unwrap()
65 .get(*capture_ix as usize)
66 .unwrap()
67 .as_bytes()
68 )
69 .unwrap()
70 .on_purple()
71 );
72 }
73 print!("{}", part.on_purple());
74 }
75 }
76 }
77 }
78 }
79 offset = r.end;
80 }
81 if let Ok(normal_str) = from_utf8(&content[offset..]) {
82 if replace_opt.is_none() || replace_opt.as_ref().unwrap().prefix.is_none() {
83 print!("{}", normal_str);
84 }
85 }
86
87 Ok(())
88 };
89
90 my_print(&None).ok();
91 if replace_opt.is_some() {
92 my_print(replace_opt).ok();
93 }
94 }
95
96 pub fn print_colored_match(&self, content: &ContentSlice) {
97 for r in self.matches.iter() {
100 if let Ok(match_str) = from_utf8(&content[r.start..r.end]) {
101 print!("{}", match_str.bright_cyan().bold());
102 }
103 }
104 println!("");
105 }
106
107 pub fn replace_with(
108 &self,
109 content: &ContentSlice,
110 search: &Search,
111 replace: &Replace,
112 output: &mut Vec<u8>,
113 ) {
114 output.clear();
115 let mut offset = 0;
116 for r in self.matches.iter() {
117 output.extend_from_slice(&content[offset..r.start]);
118 let match_bytes = &content[r.start..r.end];
119 let caps = search.regex.captures(match_bytes).unwrap();
120 for (capture_ix, part) in &replace.parts {
121 if *capture_ix >= 0 {
122 output.extend_from_slice(caps.get(*capture_ix as usize).unwrap().as_bytes());
123 }
124 output.extend_from_slice(part.as_bytes());
125 }
126 offset = r.end;
127 }
128 output.extend_from_slice(&content[offset..]);
129 }
130
131 pub fn only_matches(&self, content: &ContentSlice, output: &mut Vec<u8>) {
132 output.clear();
133 for r in self.matches.iter() {
134 output.extend_from_slice(&content[r.start..r.end]);
135 }
136 }
137}