1use super::Matcher;
4use crate::selector::{Position, Selector};
5use crate::{Line, MatchInfo};
6
7pub struct PositionMatcher {
8 positions: Vec<Position>,
10 cursor: usize,
12}
13
14impl PositionMatcher {
15 pub fn from_selector(sel: &Selector) -> Self {
17 let positions = match sel.normalize() {
18 Selector::Positions(mut p) => {
19 p.sort();
20 p.dedup();
21 p
22 }
23 _ => panic!("PositionMatcher::from_selector needs Selector::Positions"),
24 };
25 Self {
26 positions,
27 cursor: 0,
28 }
29 }
30}
31
32impl Matcher for PositionMatcher {
33 fn match_line(&mut self, line: &Line) -> MatchInfo {
34 while self.cursor < self.positions.len()
36 && (self.positions[self.cursor].line as u64) < line.no
37 {
38 self.cursor += 1;
39 }
40 if let Some(p) = self.positions.get(self.cursor)
42 && p.line as u64 == line.no
43 {
44 return MatchInfo {
45 hit: true,
46 spans: Vec::new(),
47 col: Some(p.column),
48 };
49 }
50 MatchInfo::default()
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 fn mk_line(n: u64) -> Line {
59 Line::new(n, Vec::new())
60 }
61
62 #[test]
63 fn single_position_hits_correct_line_with_col() {
64 let sel = Selector::parse("23:260").unwrap();
65 let mut m = PositionMatcher::from_selector(&sel);
66 assert!(!m.match_line(&mk_line(22)).hit);
67 let info = m.match_line(&mk_line(23));
68 assert!(info.hit);
69 assert_eq!(info.col, Some(260));
70 assert!(!m.match_line(&mk_line(24)).hit);
71 }
72
73 #[test]
74 fn multiple_positions_hit_in_order() {
75 let sel = Selector::parse("5:10,5:20,9:3").unwrap();
76 let mut m = PositionMatcher::from_selector(&sel);
77 let h5 = m.match_line(&mk_line(5));
78 assert!(h5.hit);
79 assert_eq!(h5.col, Some(10));
80 let h9 = m.match_line(&mk_line(9));
81 assert!(h9.hit);
82 assert_eq!(h9.col, Some(3));
83 }
84}