diff --git a/src/handlers/semantic_tokens.rs b/src/handlers/semantic_tokens.rs index 8e92113..acfc324 100644 --- a/src/handlers/semantic_tokens.rs +++ b/src/handlers/semantic_tokens.rs @@ -1,5 +1,6 @@ use std::sync::LazyLock; +use regex::Regex; use tower_lsp::{ jsonrpc::Result, lsp_types::{ @@ -15,13 +16,14 @@ use crate::{ util::{INHERITS_REGEX, NodeUtil, TextProviderRope, ToTsPoint}, }; +static FORMAT_IGNORE_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^;+\s*(format-ignore)").unwrap()); static SEM_TOK_QUERY: LazyLock = LazyLock::new(|| { Query::new( &QUERY_LANGUAGE, r#"(named_node (identifier) @ident) (missing_node (identifier) @ident) -(program - . (comment) @comment) +(comment) @comment "#, ) .unwrap() @@ -120,19 +122,48 @@ async fn get_semantic_tokens( prev_col = start_col; } } - // Highlight imported modules + // Highlight special comments (inherits, format ignore) "comment" => { + if let Some(fmt_ignore) = FORMAT_IGNORE_REGEX + .captures(&node_text) + .and_then(|c| c.get(1)) + { + const FMT_IGNORE_LEN: u32 = 13; + let offset = fmt_ignore.start() as u32; + tokens.push(SemanticToken { + delta_line, + delta_start: delta_start + offset, + length: FMT_IGNORE_LEN, + token_type: 3, + token_modifiers_bitset: 0, + }); + prev_line = start_row; + prev_col = start_col + offset; + continue; + }; if start_row != 0 { continue; } - let Some(pre_text) = INHERITS_REGEX.captures(&node_text).and_then(|c| c.get(1)) + let Some(mods) = INHERITS_REGEX.captures(&node_text).and_then(|c| c.get(1)) else { continue; }; - let mods = pre_text.as_str().split(','); - let len = pre_text.start() as u32; - let mut delta_start = delta_start + len; - let mut start_col = start_col + len; + let offset = mods.start() as u32; + let mods = mods.as_str().split(','); + + // Add a token for `inherits:` + const INHERITS_LEN: u32 = 9; + let mut delta_start = delta_start + offset - INHERITS_LEN - 1; + tokens.push(SemanticToken { + delta_line: 0, + delta_start, + length: INHERITS_LEN, + token_type: 3, + token_modifiers_bitset: 0, + }); + delta_start = INHERITS_LEN + 1; + + let mut start_col = start_col + offset; let mut delta_line = delta_line; for module in mods { // We assert that modules are valid ASCII characters, so we can index them @@ -191,6 +222,9 @@ mod test { (MISSING ERROR) @missingerror (MISSING supertype) @missingsupertype + +;;;format-ignore +(foo) "; let mut service = initialize_server( &[( @@ -228,9 +262,17 @@ mod test { let actual = Some(SemanticTokensResult::Tokens(SemanticTokens { result_id: None, data: vec![ + // ; inherits: SemanticToken { delta_line: 0, - delta_start: 12, + delta_start: 2, + length: 9, + token_type: 3, + token_modifiers_bitset: 0, + }, + SemanticToken { + delta_line: 0, + delta_start: 10, length: 1, token_type: 2, token_modifiers_bitset: 0, @@ -242,6 +284,7 @@ mod test { token_type: 2, token_modifiers_bitset: 0, }, + // ERROR, Supertypes SemanticToken { delta_line: 2, delta_start: 1, @@ -284,6 +327,14 @@ mod test { token_type: 0, token_modifiers_bitset: 0, }, + // format-ignore + SemanticToken { + delta_line: 2, + delta_start: 3, + length: 13, + token_type: 3, + token_modifiers_bitset: 0, + }, ], })); assert_eq!( diff --git a/src/main.rs b/src/main.rs index 979dcf2..6387f30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,6 +81,7 @@ static SERVER_CAPABILITIES: LazyLock = LazyLock::new(|| Serv SemanticTokenType::INTERFACE, SemanticTokenType::VARIABLE, SemanticTokenType::NAMESPACE, + SemanticTokenType::KEYWORD, ], token_modifiers: vec![SemanticTokenModifier::DEFAULT_LIBRARY], },