diff options
author | Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> | 2024-05-14 18:51:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-15 01:51:48 +0000 |
commit | 36d877be4a220cb30ddf69d43c386ae8d15f4b32 (patch) | |
tree | 08bdf14935f68928452a5b9665f3c65e6e9670b7 /cli/lsp/documents.rs | |
parent | 1a788b58a0e80c4504a0fdf5d47db41c46dc8d37 (diff) |
perf(lsp): Cache semantic tokens for open documents (#23799)
VScode will typically send a `textDocument/semanticTokens/full` request
followed by `textDocument/semanticTokens/range`, and occassionally
request semantic tokens even when we know nothing has changed. Semantic
tokens also get refreshed on each change. Computing semantic tokens is
relatively heavy in TSC, so we should avoid it as much as possible.
Caches the semantic tokens for open documents, to avoid making TSC do
unnecessary work. Results in a noticeable improvement in local
benchmarking
before:
```
Starting Deno benchmark
-> Start benchmarking lsp
- Simple Startup/Shutdown
(10 runs, mean: 383ms)
- Big Document/Several Edits
(5 runs, mean: 1079ms)
- Find/Replace
(10 runs, mean: 59ms)
- Code Lens
(10 runs, mean: 440ms)
- deco-cx/apps Multiple Edits + Navigation
(5 runs, mean: 9921ms)
<- End benchmarking lsp
```
after:
```
Starting Deno benchmark
-> Start benchmarking lsp
- Simple Startup/Shutdown
(10 runs, mean: 395ms)
- Big Document/Several Edits
(5 runs, mean: 1024ms)
- Find/Replace
(10 runs, mean: 56ms)
- Code Lens
(10 runs, mean: 438ms)
- deco-cx/apps Multiple Edits + Navigation
(5 runs, mean: 8927ms)
<- End benchmarking lsp
```
Diffstat (limited to 'cli/lsp/documents.rs')
-rw-r--r-- | cli/lsp/documents.rs | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 5ae15b362..8c553b03d 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -143,6 +143,16 @@ impl AssetOrDocument { } } + pub fn maybe_semantic_tokens(&self) -> Option<lsp::SemanticTokens> { + match self { + AssetOrDocument::Asset(_) => None, + AssetOrDocument::Document(d) => d + .open_data + .as_ref() + .and_then(|d| d.maybe_semantic_tokens.lock().clone()), + } + } + pub fn text(&self) -> Arc<str> { match self { AssetOrDocument::Asset(a) => a.text(), @@ -249,6 +259,7 @@ fn get_maybe_test_module_fut( pub struct DocumentOpenData { lsp_version: i32, maybe_parsed_source: Option<ParsedSourceResult>, + maybe_semantic_tokens: Arc<Mutex<Option<lsp::SemanticTokens>>>, } #[derive(Debug)] @@ -330,6 +341,7 @@ impl Document { open_data: maybe_lsp_version.map(|v| DocumentOpenData { lsp_version: v, maybe_parsed_source, + maybe_semantic_tokens: Default::default(), }), resolver, specifier, @@ -421,6 +433,8 @@ impl Document { open_data: self.open_data.as_ref().map(|d| DocumentOpenData { lsp_version: d.lsp_version, maybe_parsed_source, + // reset semantic tokens + maybe_semantic_tokens: Default::default(), }), resolver, specifier: self.specifier.clone(), @@ -499,6 +513,7 @@ impl Document { open_data: self.open_data.is_some().then_some(DocumentOpenData { lsp_version: version, maybe_parsed_source, + maybe_semantic_tokens: Default::default(), }), resolver: self.resolver.clone(), })) @@ -652,6 +667,15 @@ impl Document { ) { *self.maybe_navigation_tree.lock() = Some(navigation_tree); } + + pub fn cache_semantic_tokens_full( + &self, + semantic_tokens: lsp::SemanticTokens, + ) { + if let Some(open_data) = self.open_data.as_ref() { + *open_data.maybe_semantic_tokens.lock() = Some(semantic_tokens); + } + } } fn resolve_media_type( |