Skip to main content

oak_lua/lsp/highlighter/
mod.rs

1#![doc = include_str!("readme.md")]
2/// Local definition of highlight kinds
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum HighlightKind {
5    /// Keyword
6    Keyword,
7    /// String
8    String,
9    /// Number
10    Number,
11    /// Comment
12    Comment,
13    /// Macro
14    Macro,
15    /// Identifier
16    Identifier,
17    /// Operator
18    Operator,
19}
20
21/// Highlighter trait
22pub trait Highlighter {
23    /// Highlight the given text
24    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)>;
25}
26
27/// Lua syntax highlighter
28pub struct LuaHighlighter;
29
30impl LuaHighlighter {
31    /// Creates a new `LuaHighlighter`.
32    pub fn new() -> Self {
33        Self
34    }
35}
36
37impl Highlighter for LuaHighlighter {
38    fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
39        let mut highlights = Vec::new();
40
41        // Simple regex or lexer-based highlighting implementation
42        // Here we can reuse LuaLexer to get Tokens
43        use crate::lexer::{LuaLexer, token_type::LuaTokenType};
44        use oak_core::{LexOutput, Lexer, LexerCache, SourceText, Token};
45
46        struct SimpleCache {
47            tokens: Vec<Token<LuaTokenType>>,
48        }
49
50        impl LexerCache<crate::language::LuaLanguage> for SimpleCache {
51            fn set_lex_output(&mut self, output: LexOutput<crate::language::LuaLanguage>) {
52                if let Ok(tokens) = output.result {
53                    self.tokens = tokens.to_vec()
54                }
55            }
56            fn get_token(&self, index: usize) -> Option<Token<LuaTokenType>> {
57                self.tokens.get(index).cloned()
58            }
59            fn count_tokens(&self) -> usize {
60                self.tokens.len()
61            }
62            fn has_tokens(&self) -> bool {
63                !self.tokens.is_empty()
64            }
65        }
66
67        let config = crate::language::LuaLanguage::default();
68        let lexer = LuaLexer::new(&config);
69        let mut cache = SimpleCache { tokens: Vec::new() };
70        let source = SourceText::new(text);
71        let output = lexer.lex(&source, &[], &mut cache);
72
73        if let Ok(tokens) = output.result {
74            for token in tokens.iter() {
75                let kind = match token.kind {
76                    LuaTokenType::And
77                    | LuaTokenType::Break
78                    | LuaTokenType::Do
79                    | LuaTokenType::Else
80                    | LuaTokenType::Elseif
81                    | LuaTokenType::End
82                    | LuaTokenType::False
83                    | LuaTokenType::For
84                    | LuaTokenType::Function
85                    | LuaTokenType::Goto
86                    | LuaTokenType::If
87                    | LuaTokenType::In
88                    | LuaTokenType::Local
89                    | LuaTokenType::Nil
90                    | LuaTokenType::Not
91                    | LuaTokenType::Or
92                    | LuaTokenType::Repeat
93                    | LuaTokenType::Return
94                    | LuaTokenType::Then
95                    | LuaTokenType::True
96                    | LuaTokenType::Until
97                    | LuaTokenType::While => Some(HighlightKind::Keyword),
98                    LuaTokenType::String => Some(HighlightKind::String),
99                    LuaTokenType::Number => Some(HighlightKind::Number),
100                    LuaTokenType::Comment => Some(HighlightKind::Comment),
101                    LuaTokenType::Identifier => Some(HighlightKind::Identifier),
102                    LuaTokenType::Plus
103                    | LuaTokenType::Minus
104                    | LuaTokenType::Star
105                    | LuaTokenType::Slash
106                    | LuaTokenType::Percent
107                    | LuaTokenType::Caret
108                    | LuaTokenType::Hash
109                    | LuaTokenType::EqEq
110                    | LuaTokenType::TildeEq
111                    | LuaTokenType::LtEq
112                    | LuaTokenType::GtEq
113                    | LuaTokenType::Lt
114                    | LuaTokenType::Gt
115                    | LuaTokenType::Eq => Some(HighlightKind::Operator),
116                    _ => None,
117                };
118
119                if let Some(h_kind) = kind {
120                    highlights.push((token.span.start, token.span.end, h_kind))
121                }
122            }
123        }
124
125        highlights
126    }
127}