Repository: rust-analyzer/rust-analyzer (rust)

Issue:
Progress reporting should respect client capabilities
See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#signalingWorkDoneProgressReporting, CC #144.

This affects Sublime, for example.

Pull request:
Check client capabilities before sending progress notifications
Fixes #4384

Patch:
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 22a84b50c0..be35faff09 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -100,9 +100,8 @@ fn run_server() -> Result<()> {
         if let Some(value) = &initialize_params.initialization_options {
             config.update(value);
         }
-        if let Some(caps) = &initialize_params.capabilities.text_document {
-            config.update_caps(caps);
-        }
+        config.update_caps(&initialize_params.capabilities);
+
         config
     };
 
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index ccc38e3bba..53aee833d6 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -9,7 +9,7 @@
 
 use std::{ffi::OsString, path::PathBuf};
 
-use lsp_types::TextDocumentClientCapabilities;
+use lsp_types::ClientCapabilities;
 use ra_flycheck::FlycheckConfig;
 use ra_ide::{CompletionConfig, InlayHintsConfig};
 use ra_project_model::CargoConfig;
@@ -70,6 +70,7 @@ pub struct ClientCapsConfig {
     pub line_folding_only: bool,
     pub hierarchical_symbols: bool,
     pub code_action_literals: bool,
+    pub work_done_progress: bool,
 }
 
 impl Default for Config {
@@ -208,30 +209,43 @@ impl Config {
         }
     }
 
-    pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
-        if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
-            self.client_caps.location_link = value;
-        }
-        if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
-            self.client_caps.line_folding_only = value
-        }
-        if let Some(value) =
-            caps.document_symbol.as_ref().and_then(|it| it.hierarchical_document_symbol_support)
-        {
-            self.client_caps.hierarchical_symbols = value
-        }
-        if let Some(value) =
-            caps.code_action.as_ref().and_then(|it| Some(it.code_action_literal_support.is_some()))
-        {
-            self.client_caps.code_action_literals = value;
-        }
-        self.completion.allow_snippets(false);
-        if let Some(completion) = &caps.completion {
-            if let Some(completion_item) = &completion.completion_item {
-                if let Some(value) = completion_item.snippet_support {
-                    self.completion.allow_snippets(value);
+    pub fn update_caps(&mut self, caps: &ClientCapabilities) {
+        if let Some(doc_caps) = caps.text_document.as_ref() {
+            if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) {
+                self.client_caps.location_link = value;
+            }
+            if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only)
+            {
+                self.client_caps.line_folding_only = value
+            }
+            if let Some(value) = doc_caps
+                .document_symbol
+                .as_ref()
+                .and_then(|it| it.hierarchical_document_symbol_support)
+            {
+                self.client_caps.hierarchical_symbols = value
+            }
+            if let Some(value) = doc_caps
+                .code_action
+                .as_ref()
+                .and_then(|it| Some(it.code_action_literal_support.is_some()))
+            {
+                self.client_caps.code_action_literals = value;
+            }
+            self.completion.allow_snippets(false);
+            if let Some(completion) = &doc_caps.completion {
+                if let Some(completion_item) = &completion.completion_item {
+                    if let Some(value) = completion_item.snippet_support {
+                        self.completion.allow_snippets(value);
+                    }
                 }
             }
         }
+
+        if let Some(window_caps) = caps.window.as_ref() {
+            if let Some(value) = window_caps.work_done_progress {
+                self.client_caps.work_done_progress = value;
+            }
+        }
     }
 }
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 3f12dd7183..13d305b973 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -415,7 +415,8 @@ fn loop_turn(
         });
     }
 
-    let show_progress = !loop_state.workspace_loaded;
+    let show_progress =
+        !loop_state.workspace_loaded && world_state.config.client_caps.work_done_progress;
 
     if !loop_state.workspace_loaded
         && loop_state.roots_scanned == loop_state.roots_total
@@ -750,12 +751,16 @@ fn on_check_task(
         }
 
         CheckTask::Status(progress) => {
-            let params = lsp_types::ProgressParams {
-                token: lsp_types::ProgressToken::String("rustAnalyzer/cargoWatcher".to_string()),
-                value: lsp_types::ProgressParamsValue::WorkDone(progress),
-            };
-            let not = notification_new::<lsp_types::notification::Progress>(params);
-            task_sender.send(Task::Notify(not)).unwrap();
+            if world_state.config.client_caps.work_done_progress {
+                let params = lsp_types::ProgressParams {
+                    token: lsp_types::ProgressToken::String(
+                        "rustAnalyzer/cargoWatcher".to_string(),
+                    ),
+                    value: lsp_types::ProgressParamsValue::WorkDone(progress),
+                };
+                let not = notification_new::<lsp_types::notification::Progress>(params);
+                task_sender.send(Task::Notify(not)).unwrap();
+            }
         }
     };
 


Test patch:
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index 8756ad4a3c..9acbae066f 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -80,6 +80,7 @@ impl<'a> Project<'a> {
             client_caps: ClientCapsConfig {
                 location_link: true,
                 code_action_literals: true,
+                work_done_progress: true,
                 ..Default::default()
             },
             with_sysroot: self.with_sysroot,