1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use crate::*;
pub struct Pattern {
pub pattern: String, // might change later
}
impl Pattern {
// Current limitations:
// - a match can't span over more than 2 lines. This is probably fine.
pub fn search_lines<'i, I>(
&self,
lines: I,
) -> Vec<Found>
where
I: IntoIterator<Item = &'i Line>,
{
let lines = lines.into_iter();
let pattern = &self.pattern;
let len = pattern.len();
let mut founds = Vec::new();
let mut previous_line: Option<&Line> = None;
for (line_idx, line) in lines.enumerate() {
if line.is_continuation() {
if let Some(previous_line) = previous_line {
// we check for a match broken by wrapping
if !previous_line.content.strings.is_empty() && !line.content.strings.is_empty()
{
let previous_line_string_idx = previous_line.content.strings.len() - 1;
let previous_last_raw =
&previous_line.content.strings[previous_line_string_idx].raw;
if let Some(cut) = find_cut_pattern(
pattern,
previous_last_raw,
&line.content.strings[0].raw,
) {
let found = Found {
line_idx: line_idx - 1,
trange: TRange {
string_idx: previous_line_string_idx,
start_byte_in_string: previous_last_raw.len() - cut,
end_byte_in_string: previous_last_raw.len(),
},
continued: Some(TRange {
string_idx: 0,
start_byte_in_string: 0,
end_byte_in_string: len - cut,
}),
};
founds.push(found);
}
}
}
}
previous_line = Some(line);
for (string_idx, tstring) in line.content.strings.iter().enumerate() {
let mut offset = 0;
while offset + len < tstring.raw.len() {
let haystack = &tstring.raw[offset..];
let Some(pos) = haystack.find(pattern) else {
break;
};
let found = Found {
line_idx,
trange: TRange {
string_idx,
start_byte_in_string: pos + offset,
end_byte_in_string: pos + offset + pattern.len(),
},
continued: None,
};
founds.push(found);
offset += pos + pattern.len();
}
}
}
founds
}
}
fn find_cut_pattern(
pattern: &str,
a: &str,
b: &str,
) -> Option<usize> {
let len = pattern.len();
(1..len).find(|&i| a.ends_with(&pattern[..i]) && b.starts_with(&pattern[i..]))
}