1use std::{borrow::Cow, ops::Deref};
2
3use alacritty_terminal::{
4 grid::Dimensions,
5 index::{Column, Direction, Line, Point},
6 term::search::{Match, RegexIter, RegexSearch},
7 Term,
8};
9
10const MAX_SEARCH_LINES: usize = 100;
11
12///Header and impl fom alacritty/src/display/content.rs HintMatches
13#[derive(Default)]
14pub struct SearchMatches<'a> {
15 /// All visible matches.
16 matches: Cow<'a, [Match]>,
17
18 /// Index of the last match checked.
19 index: usize,
20}
21
22impl<'a> SearchMatches<'a> {
23 /// Create new renderable matches iterator..
24 fn new(matches: impl Into<Cow<'a, [Match]>>) -> Self {
25 Self {
26 matches: matches.into(),
27 index: 0,
28 }
29 }
30
31 /// Create from regex matches on term visable part.
32 pub fn visible_regex_matches<T>(term: &Term<T>, dfas: &RegexSearch) -> Self {
33 let matches = visible_regex_match_iter(term, dfas).collect::<Vec<_>>();
34 Self::new(matches)
35 }
36
37 /// Advance the regex tracker to the next point.
38 ///
39 /// This will return `true` if the point passed is part of a regex match.
40 fn advance(&mut self, point: Point) -> bool {
41 while let Some(bounds) = self.get(self.index) {
42 if bounds.start() > &point {
43 break;
44 } else if bounds.end() < &point {
45 self.index += 1;
46 } else {
47 return true;
48 }
49 }
50 false
51 }
52}
53
54impl<'a> Deref for SearchMatches<'a> {
55 type Target = [Match];
56
57 fn deref(&self) -> &Self::Target {
58 self.matches.deref()
59 }
60}
61
62/// Copied from alacritty/src/display/hint.rs
63/// Iterate over all visible regex matches.
64fn visible_regex_match_iter<'a, T>(
65 term: &'a Term<T>,
66 regex: &'a RegexSearch,
67) -> impl Iterator<Item = Match> + 'a {
68 let viewport_start = Line(-(term.grid().display_offset() as i32));
69 let viewport_end = viewport_start + term.bottommost_line();
70 let mut start = term.line_search_left(Point::new(viewport_start, Column(0)));
71 let mut end = term.line_search_right(Point::new(viewport_end, Column(0)));
72 start.line = start.line.max(viewport_start - MAX_SEARCH_LINES);
73 end.line = end.line.min(viewport_end + MAX_SEARCH_LINES);
74
75 RegexIter::new(start, end, Direction::Right, term, regex)
76 .skip_while(move |rm| rm.end().line < viewport_start)
77 .take_while(move |rm| rm.start().line <= viewport_end)
78}