summaryrefslogtreecommitdiff
path: root/cli/lsp/semantic_tokens.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/lsp/semantic_tokens.rs')
-rw-r--r--cli/lsp/semantic_tokens.rs174
1 files changed, 174 insertions, 0 deletions
diff --git a/cli/lsp/semantic_tokens.rs b/cli/lsp/semantic_tokens.rs
index a2a56cce0..0cf154d0f 100644
--- a/cli/lsp/semantic_tokens.rs
+++ b/cli/lsp/semantic_tokens.rs
@@ -7,6 +7,7 @@
use std::ops::Index;
use std::ops::IndexMut;
+use tower_lsp::lsp_types as lsp;
use tower_lsp::lsp_types::SemanticToken;
use tower_lsp::lsp_types::SemanticTokenModifier;
use tower_lsp::lsp_types::SemanticTokenType;
@@ -247,6 +248,54 @@ impl SemanticTokensBuilder {
}
}
+pub fn tokens_within_range(
+ tokens: &SemanticTokens,
+ range: lsp::Range,
+) -> SemanticTokens {
+ let mut line = 0;
+ let mut character = 0;
+
+ let mut first_token_line = 0;
+ let mut first_token_char = 0;
+ let mut keep_start_idx = tokens.data.len();
+ let mut keep_end_idx = keep_start_idx;
+ for (i, token) in tokens.data.iter().enumerate() {
+ if token.delta_line != 0 {
+ character = 0;
+ }
+ line += token.delta_line;
+ character += token.delta_start;
+ let token_start = lsp::Position::new(line, character);
+ if i < keep_start_idx && token_start >= range.start {
+ keep_start_idx = i;
+ first_token_line = line;
+ first_token_char = character;
+ }
+ if token_start > range.end {
+ keep_end_idx = i;
+ break;
+ }
+ }
+ if keep_end_idx == keep_start_idx {
+ return SemanticTokens {
+ result_id: None,
+ data: Vec::new(),
+ };
+ }
+
+ let mut data = tokens.data[keep_start_idx..keep_end_idx].to_vec();
+ // we need to adjust the delta_line and delta_start on the first token
+ // as it is relative to 0 now, not the previous token
+ let first_token = &mut data[0];
+ first_token.delta_line = first_token_line;
+ first_token.delta_start = first_token_char;
+
+ SemanticTokens {
+ result_id: None,
+ data,
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -352,4 +401,129 @@ mod tests {
]
);
}
+
+ #[test]
+ fn test_tokens_within_range() {
+ let mut builder = SemanticTokensBuilder::new();
+ builder.push(1, 0, 5, 0, 0);
+ builder.push(2, 1, 1, 1, 0);
+ builder.push(2, 2, 3, 2, 0);
+ builder.push(2, 5, 5, 3, 0);
+ builder.push(3, 0, 4, 4, 0);
+ builder.push(5, 2, 3, 5, 0);
+ let tokens = builder.build(None);
+ let range = lsp::Range {
+ start: lsp::Position {
+ line: 2,
+ character: 2,
+ },
+ end: lsp::Position {
+ line: 4,
+ character: 0,
+ },
+ };
+
+ let result = tokens_within_range(&tokens, range);
+
+ assert_eq!(
+ result.data,
+ vec![
+ // line 2 char 2
+ SemanticToken {
+ delta_line: 2,
+ delta_start: 2,
+ length: 3,
+ token_type: 2,
+ token_modifiers_bitset: 0
+ },
+ // line 2 char 5
+ SemanticToken {
+ delta_line: 0,
+ delta_start: 3,
+ length: 5,
+ token_type: 3,
+ token_modifiers_bitset: 0
+ },
+ // line 3 char 0
+ SemanticToken {
+ delta_line: 1,
+ delta_start: 0,
+ length: 4,
+ token_type: 4,
+ token_modifiers_bitset: 0
+ }
+ ]
+ );
+ }
+
+ #[test]
+ fn test_tokens_within_range_include_end() {
+ let mut builder = SemanticTokensBuilder::new();
+ builder.push(1, 0, 1, 0, 0);
+ builder.push(2, 1, 2, 1, 0);
+ builder.push(2, 3, 3, 2, 0);
+ builder.push(3, 0, 4, 3, 0);
+ let tokens = builder.build(None);
+ let range = lsp::Range {
+ start: lsp::Position {
+ line: 2,
+ character: 2,
+ },
+ end: lsp::Position {
+ line: 3,
+ character: 4,
+ },
+ };
+ let result = tokens_within_range(&tokens, range);
+
+ assert_eq!(
+ result.data,
+ vec![
+ // line 2 char 3
+ SemanticToken {
+ delta_line: 2,
+ delta_start: 3,
+ length: 3,
+ token_type: 2,
+ token_modifiers_bitset: 0
+ },
+ // line 3 char 0
+ SemanticToken {
+ delta_line: 1,
+ delta_start: 0,
+ length: 4,
+ token_type: 3,
+ token_modifiers_bitset: 0
+ }
+ ]
+ );
+ }
+
+ #[test]
+ fn test_tokens_within_range_empty() {
+ let mut builder = SemanticTokensBuilder::new();
+ builder.push(1, 0, 1, 0, 0);
+ builder.push(2, 1, 2, 1, 0);
+ builder.push(2, 3, 3, 2, 0);
+ builder.push(3, 0, 4, 3, 0);
+ let tokens = builder.build(None);
+ let range = lsp::Range {
+ start: lsp::Position {
+ line: 3,
+ character: 2,
+ },
+ end: lsp::Position {
+ line: 3,
+ character: 4,
+ },
+ };
+ let result = tokens_within_range(&tokens, range);
+
+ assert_eq!(result.data, vec![]);
+
+ assert_eq!(
+ tokens_within_range(&SemanticTokens::default(), range).data,
+ vec![]
+ );
+ }
}