Skip to main content

oak_rust/highlighter/
mod.rs

1//! Rust 语法高亮器
2//!
3//! 这个模块提供了 Rust 源代码的语法高亮功能,支持关键字、字符串、数字、注释等的高亮显示。
4
5/// 高亮类型的本地定义
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum HighlightKind {
8    /// 关键字
9    Keyword,
10    /// 字符串
11    String,
12    /// 数字
13    Number,
14    /// 注释
15    Comment,
16    /// 宏
17    Macro,
18    /// 标识符
19    Identifier,
20}
21
22/// 高亮器 trait
23pub trait Highlighter {
24    /// 对给定的文本进行高亮处理
25    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)>;
26}
27
28/// Rust 语法高亮器
29///
30/// `RustHighlighter` 实现了 `Highlighter` trait,为 Rust 代码提供语法高亮功能。
31pub struct RustHighlighter {
32    /// 是否使用基于解析器的高亮以提高准确性
33    pub use_parser: bool,
34}
35
36impl Default for RustHighlighter {
37    fn default() -> Self {
38        Self { use_parser: false }
39    }
40}
41
42impl RustHighlighter {
43    /// 创建一个新的 Rust 高亮器实例
44    pub fn new() -> Self {
45        Self::default()
46    }
47
48    /// 创建一个使用解析器的高亮器实例
49    pub fn with_parser() -> Self {
50        Self { use_parser: true }
51    }
52
53    /// 高亮 Rust 关键字
54    fn highlight_keywords(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
55        let mut highlights = Vec::new();
56        let keywords = [
57            "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait",
58            "true", "type", "unsafe", "use", "where", "while", "async", "await", "dyn", "abstract", "become", "box", "do", "final", "macro", "override", "priv", "typeof", "unsized", "virtual", "yield", "try", "union", "raw",
59        ];
60
61        for keyword in &keywords {
62            let mut start = 0;
63            while let Some(pos) = text[start..].find(keyword) {
64                let absolute_pos = start + pos;
65                let end_pos = absolute_pos + keyword.len();
66
67                // 确保这是一个完整的单词
68                let is_word_boundary_before = absolute_pos == 0 || !text.chars().nth(absolute_pos - 1).unwrap_or(' ').is_alphanumeric();
69                let is_word_boundary_after = end_pos >= text.len() || !text.chars().nth(end_pos).unwrap_or(' ').is_alphanumeric();
70
71                if is_word_boundary_before && is_word_boundary_after {
72                    highlights.push((absolute_pos, end_pos, HighlightKind::Keyword));
73                }
74
75                start = absolute_pos + 1;
76            }
77        }
78
79        highlights
80    }
81
82    /// 高亮字符串字面量
83    fn highlight_strings(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
84        let mut highlights = Vec::new();
85        let mut chars = text.char_indices().peekable();
86
87        while let Some((i, ch)) = chars.next() {
88            match ch {
89                '"' => {
90                    let start = i;
91                    let mut end = i + 1;
92                    let mut escaped = false;
93
94                    while let Some((j, next_ch)) = chars.next() {
95                        end = j + next_ch.len_utf8();
96                        if escaped {
97                            escaped = false;
98                        }
99                        else if next_ch == '\\' {
100                            escaped = true;
101                        }
102                        else if next_ch == '"' {
103                            break;
104                        }
105                    }
106
107                    highlights.push((start, end, HighlightKind::String));
108                }
109                '\'' => {
110                    let start = i;
111                    let mut end = i + 1;
112                    let mut escaped = false;
113
114                    while let Some((j, next_ch)) = chars.next() {
115                        end = j + next_ch.len_utf8();
116                        if escaped {
117                            escaped = false;
118                        }
119                        else if next_ch == '\\' {
120                            escaped = true;
121                        }
122                        else if next_ch == '\'' {
123                            break;
124                        }
125                    }
126
127                    highlights.push((start, end, HighlightKind::String));
128                }
129                _ => {}
130            }
131        }
132
133        highlights
134    }
135
136    /// 高亮数字字面量
137    fn highlight_numbers(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
138        let mut highlights = Vec::new();
139        let mut chars = text.char_indices().peekable();
140
141        while let Some((i, ch)) = chars.next() {
142            if ch.is_ascii_digit() {
143                let start = i;
144                let mut end = i + 1;
145
146                // 继续读取数字字符
147                while let Some(&(j, next_ch)) = chars.peek() {
148                    if next_ch.is_ascii_digit() || next_ch == '.' || next_ch == '_' {
149                        end = j + next_ch.len_utf8();
150                        chars.next();
151                    }
152                    else {
153                        break;
154                    }
155                }
156
157                highlights.push((start, end, HighlightKind::Number));
158            }
159        }
160
161        highlights
162    }
163
164    /// 高亮注释
165    fn highlight_comments(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
166        let mut highlights = Vec::new();
167        let lines: Vec<&str> = text.lines().collect();
168        let mut pos = 0;
169
170        for line in lines {
171            if let Some(comment_start) = line.find("//") {
172                let start = pos + comment_start;
173                let end = pos + line.len();
174                highlights.push((start, end, HighlightKind::Comment));
175            }
176            pos += line.len() + 1; // +1 for newline
177        }
178
179        highlights
180    }
181}
182
183impl Highlighter for RustHighlighter {
184    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
185        let mut highlights = Vec::new();
186
187        highlights.extend(self.highlight_keywords(text));
188        highlights.extend(self.highlight_strings(text));
189        highlights.extend(self.highlight_numbers(text));
190        highlights.extend(self.highlight_comments(text));
191
192        // 按位置排序
193        highlights.sort_by_key(|&(start, _, _)| start);
194        highlights
195    }
196}