Skip to main content

wedi_core/
search.rs

1// 搜索功能
2// 這個模組將在後續階段實現
3
4use crate::buffer::RopeBuffer;
5
6#[allow(dead_code)]
7pub struct Search {
8    query: String,
9    matches: Vec<(usize, usize)>, // (line, col) pairs
10    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                // 使用查詢字符串的字節長度來避免 UTF-8 字符邊界錯誤
45                // 這樣可以正確處理中文等多字節字符
46                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}