molybdenum/
line.rs

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    //(start, size) indicate a part from some ContentSlice
16    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        //@todo: make configurable
98        // print!("{}:", format!("{}", self.nr).yellow());
99        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}