Skip to main content

oak_php/lsp/highlighter/
mod.rs

1#![doc = include_str!("readme.md")]
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 PhpHighlighter {
18    pub use_parser: bool,
19}
20
21impl Default for PhpHighlighter {
22    fn default() -> Self {
23        Self { use_parser: false }
24    }
25}
26
27impl PhpHighlighter {
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            "abstract",
40            "and",
41            "array",
42            "as",
43            "break",
44            "callable",
45            "case",
46            "catch",
47            "class",
48            "clone",
49            "const",
50            "continue",
51            "declare",
52            "default",
53            "die",
54            "do",
55            "echo",
56            "else",
57            "elseif",
58            "empty",
59            "enddeclare",
60            "endfor",
61            "endforeach",
62            "endif",
63            "endswitch",
64            "endwhile",
65            "eval",
66            "exit",
67            "extends",
68            "final",
69            "finally",
70            "for",
71            "foreach",
72            "function",
73            "global",
74            "goto",
75            "if",
76            "implements",
77            "include",
78            "include_once",
79            "instanceof",
80            "insteadof",
81            "interface",
82            "isset",
83            "list",
84            "namespace",
85            "new",
86            "or",
87            "print",
88            "private",
89            "protected",
90            "public",
91            "require",
92            "require_once",
93            "return",
94            "static",
95            "switch",
96            "throw",
97            "trait",
98            "try",
99            "unset",
100            "use",
101            "var",
102            "while",
103            "xor",
104            "yield",
105        ];
106
107        for keyword in &keywords {
108            let mut start = 0;
109            while let Some(pos) = text[start..].find(keyword) {
110                let absolute_pos = start + pos;
111                let end_pos = absolute_pos + keyword.len();
112
113                let is_word_boundary_before = absolute_pos == 0 || !text.chars().nth(absolute_pos - 1).unwrap_or(' ').is_alphanumeric();
114                let is_word_boundary_after = end_pos >= text.len() || !text.chars().nth(end_pos).unwrap_or(' ').is_alphanumeric();
115
116                if is_word_boundary_before && is_word_boundary_after {
117                    highlights.push((absolute_pos, end_pos, HighlightKind::Keyword));
118                }
119
120                start = absolute_pos + 1;
121            }
122        }
123
124        highlights
125    }
126}
127
128impl Highlighter for PhpHighlighter {
129    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
130        let mut highlights = self.highlight_keywords(text);
131        highlights.sort_by_key(|h| h.0);
132        highlights
133    }
134}