1use crate::buffer::RopeBuffer;
5
6#[allow(dead_code)]
7pub struct Search {
8 query: String,
9 matches: Vec<(usize, usize)>, current_match: usize,
11}
12
13#[allow(dead_code)]
14impl Search {
15 pub fn new() -> Self {
16 Self {
17 query: String::new(),
18 matches: Vec::new(),
19 current_match: 0,
20 }
21 }
22
23 pub fn set_query(&mut self, query: String) {
24 self.query = query;
25 self.matches.clear();
26 self.current_match = 0;
27 }
28
29 pub fn find_matches(&mut self, buffer: &RopeBuffer) {
30 self.matches.clear();
31
32 if self.query.is_empty() {
33 return;
34 }
35
36 for line_idx in 0..buffer.line_count() {
37 let line_content = buffer.get_line_content(line_idx);
38 let line_content = line_content.trim_end_matches(['\n', '\r']);
39
40 let mut start = 0;
41 while let Some(pos) = line_content[start..].find(&self.query) {
42 let actual_pos = start + pos;
43 self.matches.push((line_idx, actual_pos));
44 start = actual_pos + self.query.len();
47 }
48 }
49 }
50
51 pub fn next_match(&mut self) -> Option<(usize, usize)> {
52 if self.matches.is_empty() {
53 return None;
54 }
55
56 self.current_match = (self.current_match + 1) % self.matches.len();
57 Some(self.matches[self.current_match])
58 }
59
60 pub fn prev_match(&mut self) -> Option<(usize, usize)> {
61 if self.matches.is_empty() {
62 return None;
63 }
64
65 if self.current_match == 0 {
66 self.current_match = self.matches.len() - 1;
67 } else {
68 self.current_match -= 1;
69 }
70
71 Some(self.matches[self.current_match])
72 }
73
74 pub fn match_count(&self) -> usize {
75 self.matches.len()
76 }
77
78 pub fn current_index(&self) -> usize {
79 self.current_match
80 }
81
82 pub fn get_query(&self) -> &str {
83 &self.query
84 }
85}
86
87impl Default for Search {
88 fn default() -> Self {
89 Self::new()
90 }
91}