From 184119258e256b656f30d89ea5e1512fe1d927db Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 19 Sep 2023 21:34:43 +0300 Subject: [PATCH 1/2] Do not resolve inlayHint.textEdit for VSCode client VSCode behaves strangely, allowing to navigate into label location, but not allowing to apply hint's text edit, after hint is resolved. See https://github.com/microsoft/vscode/issues/193124 for details. For now, stub hint resolution for VSCode specifically. --- crates/rust-analyzer/src/bin/main.rs | 12 ++++--- crates/rust-analyzer/src/config.rs | 33 +++++++++++++++---- .../rust-analyzer/src/diagnostics/to_proto.rs | 7 +++- crates/rust-analyzer/src/lsp/to_proto.rs | 3 +- .../rust-analyzer/tests/slow-tests/support.rs | 1 + 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 2fa14fc7e28..c1d0d24b96d 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -190,6 +190,12 @@ fn run_server() -> anyhow::Result<()> { } }; + let mut is_visual_studio = false; + if let Some(client_info) = client_info { + tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); + is_visual_studio = client_info.name == "Visual Studio Code"; + } + let workspace_roots = workspace_folders .map(|workspaces| { workspaces @@ -201,7 +207,7 @@ fn run_server() -> anyhow::Result<()> { }) .filter(|workspaces| !workspaces.is_empty()) .unwrap_or_else(|| vec![root_path.clone()]); - let mut config = Config::new(root_path, capabilities, workspace_roots); + let mut config = Config::new(root_path, capabilities, workspace_roots, is_visual_studio); if let Some(json) = initialization_options { if let Err(e) = config.update(json) { use lsp_types::{ @@ -231,10 +237,6 @@ fn run_server() -> anyhow::Result<()> { connection.initialize_finish(initialize_id, initialize_result)?; - if let Some(client_info) = client_info { - tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); - } - if !config.has_linked_projects() && config.detached_files().is_empty() { config.rediscover_workspaces(); } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index ea3a21241cb..683b3deb6ee 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -565,6 +565,7 @@ pub struct Config { data: ConfigData, detached_files: Vec, snippets: Vec, + is_visual_studio: bool, } type ParallelCachePrimingNumThreads = u8; @@ -760,6 +761,7 @@ pub fn new( root_path: AbsPathBuf, caps: ClientCapabilities, workspace_roots: Vec, + is_visual_studio: bool, ) -> Self { Config { caps, @@ -769,6 +771,7 @@ pub fn new( root_path, snippets: Default::default(), workspace_roots, + is_visual_studio, } } @@ -1667,6 +1670,12 @@ pub fn main_loop_num_threads(&self) -> usize { pub fn typing_autoclose_angle(&self) -> bool { self.data.typing_autoClosingAngleBrackets_enable } + + // FIXME: VSCode seems to work wrong sometimes, see https://github.com/microsoft/vscode/issues/193124 + // hence, distinguish it for now. + pub fn is_visual_studio(&self) -> bool { + self.is_visual_studio + } } // Deserialization definitions @@ -2555,8 +2564,12 @@ fn remove_ws(text: &str) -> String { #[test] fn proc_macro_srv_null() { - let mut config = - Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); config .update(serde_json::json!({ "procMacro_server": null, @@ -2567,8 +2580,12 @@ fn proc_macro_srv_null() { #[test] fn proc_macro_srv_abs() { - let mut config = - Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); config .update(serde_json::json!({ "procMacro": {"server": project_root().display().to_string()} @@ -2579,8 +2596,12 @@ fn proc_macro_srv_abs() { #[test] fn proc_macro_srv_rel() { - let mut config = - Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); config .update(serde_json::json!({ "procMacro": {"server": "./server"} diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 731580557c2..f8bc66ff8e7 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -538,7 +538,12 @@ fn check_with_config(config: DiagnosticsMapConfig, diagnostics_json: &str, expec let (sender, _) = crossbeam_channel::unbounded(); let state = GlobalState::new( sender, - Config::new(workspace_root.to_path_buf(), ClientCapabilities::default(), Vec::new()), + Config::new( + workspace_root.to_path_buf(), + ClientCapabilities::default(), + Vec::new(), + false, + ), ); let snap = state.snapshot(); let mut actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap); diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index 23074493aee..9190c203146 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -443,10 +443,11 @@ pub(crate) fn inlay_hint( file_id: FileId, inlay_hint: InlayHint, ) -> Cancellable { + let is_visual_studio = snap.config.is_visual_studio(); let needs_resolve = inlay_hint.needs_resolve; let (label, tooltip, mut something_to_resolve) = inlay_hint_label(snap, fields_to_resolve, needs_resolve, inlay_hint.label)?; - let text_edits = if needs_resolve && fields_to_resolve.resolve_text_edits { + let text_edits = if !is_visual_studio && needs_resolve && fields_to_resolve.resolve_text_edits { something_to_resolve |= inlay_hint.text_edit.is_some(); None } else { diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs index e49b5768fa4..106b99cb935 100644 --- a/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/crates/rust-analyzer/tests/slow-tests/support.rs @@ -150,6 +150,7 @@ pub(crate) fn server(self) -> Server { ..Default::default() }, roots, + false, ); config.update(self.config).expect("invalid config"); config.rediscover_workspaces(); From f9fac02c571a4f5520246ab80f5c4b825ca492a5 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 19 Sep 2023 23:34:43 +0300 Subject: [PATCH 2/2] Use proper editor name --- crates/rust-analyzer/src/bin/main.rs | 6 +++--- crates/rust-analyzer/src/config.rs | 10 +++++----- crates/rust-analyzer/src/lsp/to_proto.rs | 15 ++++++++------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index c1d0d24b96d..b8875ef87a4 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -190,10 +190,10 @@ fn run_server() -> anyhow::Result<()> { } }; - let mut is_visual_studio = false; + let mut is_visual_studio_code = false; if let Some(client_info) = client_info { tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); - is_visual_studio = client_info.name == "Visual Studio Code"; + is_visual_studio_code = client_info.name == "Visual Studio Code"; } let workspace_roots = workspace_folders @@ -207,7 +207,7 @@ fn run_server() -> anyhow::Result<()> { }) .filter(|workspaces| !workspaces.is_empty()) .unwrap_or_else(|| vec![root_path.clone()]); - let mut config = Config::new(root_path, capabilities, workspace_roots, is_visual_studio); + let mut config = Config::new(root_path, capabilities, workspace_roots, is_visual_studio_code); if let Some(json) = initialization_options { if let Err(e) = config.update(json) { use lsp_types::{ diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 683b3deb6ee..af2a8436efb 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -565,7 +565,7 @@ pub struct Config { data: ConfigData, detached_files: Vec, snippets: Vec, - is_visual_studio: bool, + is_visual_studio_code: bool, } type ParallelCachePrimingNumThreads = u8; @@ -761,7 +761,7 @@ pub fn new( root_path: AbsPathBuf, caps: ClientCapabilities, workspace_roots: Vec, - is_visual_studio: bool, + is_visual_studio_code: bool, ) -> Self { Config { caps, @@ -771,7 +771,7 @@ pub fn new( root_path, snippets: Default::default(), workspace_roots, - is_visual_studio, + is_visual_studio_code, } } @@ -1673,8 +1673,8 @@ pub fn typing_autoclose_angle(&self) -> bool { // FIXME: VSCode seems to work wrong sometimes, see https://github.com/microsoft/vscode/issues/193124 // hence, distinguish it for now. - pub fn is_visual_studio(&self) -> bool { - self.is_visual_studio + pub fn is_visual_studio_code(&self) -> bool { + self.is_visual_studio_code } } // Deserialization definitions diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index 9190c203146..aca91570f7c 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -443,16 +443,17 @@ pub(crate) fn inlay_hint( file_id: FileId, inlay_hint: InlayHint, ) -> Cancellable { - let is_visual_studio = snap.config.is_visual_studio(); + let is_visual_studio_code = snap.config.is_visual_studio_code(); let needs_resolve = inlay_hint.needs_resolve; let (label, tooltip, mut something_to_resolve) = inlay_hint_label(snap, fields_to_resolve, needs_resolve, inlay_hint.label)?; - let text_edits = if !is_visual_studio && needs_resolve && fields_to_resolve.resolve_text_edits { - something_to_resolve |= inlay_hint.text_edit.is_some(); - None - } else { - inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)) - }; + let text_edits = + if !is_visual_studio_code && needs_resolve && fields_to_resolve.resolve_text_edits { + something_to_resolve |= inlay_hint.text_edit.is_some(); + None + } else { + inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)) + }; let data = if needs_resolve && something_to_resolve { Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.0 }).unwrap()) } else {