1 
2 /// a displayable representation of where
3 /// the needle was found, with some text around
4 #[derive(Debug, Clone)]
5 pub struct ContentMatch {
6     pub extract: String,
7     pub needle_start: usize, // position in the extract, in bytes
8     pub needle_end: usize,   // length in bytes
9 }
10 
11 impl ContentMatch {
build( hay: &[u8], pos: usize, needle: &str, desired_len: usize, ) -> Self12     pub fn build(
13         hay: &[u8],
14         pos: usize, // position in the hay
15         needle: &str,
16         desired_len: usize, // max length of the extract in bytes
17     ) -> Self {
18         if hay.is_empty() {
19             // this happens if you search `cr/.*` and a file starts with an empty line
20             return Self {
21                 extract: "".to_string(),
22                 needle_start: 0,
23                 needle_end: 0,
24             };
25         }
26         let mut extract_start = pos;
27         let mut extract_end = pos + needle.len(); // not included
28         loop {
29             if extract_start == 0 || extract_end - extract_start >= desired_len / 2 {
30                 break;
31             }
32             let c = hay[extract_start - 1];
33             if c < 32 {
34                 break;
35             }
36             extract_start -= 1;
37         }
38         // left trimming
39         while (hay[extract_start] == 32) && extract_start < pos {
40             extract_start += 1;
41         }
42         loop {
43             if extract_end == hay.len() || extract_end - extract_start >= desired_len {
44                 break;
45             }
46             let c = hay[extract_end];
47             if c < 32 {
48                 break;
49             }
50             extract_end += 1;
51         }
52         // at this point we're unsure whether we start at a correct char boundary, hence
53         // the from_utf8_lossy
54         let extract = String::from_utf8_lossy(&hay[extract_start..extract_end]).to_string();
55         let needle_start = extract.find(needle).unwrap_or(0);
56         Self {
57             extract,
58             needle_start,
59             needle_end: needle_start + needle.len(),
60         }
61     }
62 }
63