Skip to main content

oak_powershell/highlighter/
mod.rs

1//! PowerShell highlighter
2#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum HighlightKind {
4    Keyword,
5    String,
6    Number,
7    Comment,
8    Identifier,
9}
10
11/// 高亮器 trait
12pub trait Highlighter {
13    /// 对给定的文本进行高亮处理
14    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)>;
15}
16
17pub struct PowerShellHighlighter {
18    pub use_parser: bool,
19}
20
21impl Default for PowerShellHighlighter {
22    fn default() -> Self {
23        Self { use_parser: false }
24    }
25}
26
27impl PowerShellHighlighter {
28    pub fn new() -> Self {
29        Self::default()
30    }
31
32    pub fn with_parser() -> Self {
33        Self { use_parser: true }
34    }
35
36    fn highlight_keywords(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
37        let mut highlights = Vec::new();
38        let keywords = [
39            "begin",
40            "break",
41            "catch",
42            "class",
43            "continue",
44            "data",
45            "define",
46            "do",
47            "dynamicparam",
48            "else",
49            "elseif",
50            "end",
51            "exit",
52            "filter",
53            "finally",
54            "for",
55            "foreach",
56            "from",
57            "function",
58            "if",
59            "in",
60            "inline",
61            "parallel",
62            "param",
63            "process",
64            "return",
65            "switch",
66            "throw",
67            "trap",
68            "try",
69            "until",
70            "using",
71            "var",
72            "while",
73            "workflow",
74        ];
75
76        for keyword in &keywords {
77            let mut start = 0;
78            while let Some(pos) = text[start..].to_lowercase().find(&keyword.to_lowercase()) {
79                let absolute_pos = start + pos;
80                let end_pos = absolute_pos + keyword.len();
81
82                let is_word_boundary_before = absolute_pos == 0 || !text.chars().nth(absolute_pos - 1).unwrap_or(' ').is_alphanumeric();
83                let is_word_boundary_after = end_pos >= text.len() || !text.chars().nth(end_pos).unwrap_or(' ').is_alphanumeric();
84
85                if is_word_boundary_before && is_word_boundary_after {
86                    highlights.push((absolute_pos, end_pos, HighlightKind::Keyword));
87                }
88
89                start = absolute_pos + 1;
90            }
91        }
92
93        highlights
94    }
95}
96
97impl Highlighter for PowerShellHighlighter {
98    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
99        let mut highlights = self.highlight_keywords(text);
100        highlights.sort_by_key(|h| h.0);
101        highlights
102    }
103}