Auto merge of #15635 - SomeoneToIgnore:fix-vscode-edits, r=Veykril

Do not resolve inlayHint.textEdit for VSCode client

Closes https://github.com/rust-lang/rust-analyzer/issues/15604

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.
This commit is contained in:
bors 2023-09-19 20:36:09 +00:00
commit 0427a239eb
5 changed files with 49 additions and 18 deletions

View File

@ -190,6 +190,12 @@ fn run_server() -> anyhow::Result<()> {
} }
}; };
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_code = client_info.name == "Visual Studio Code";
}
let workspace_roots = workspace_folders let workspace_roots = workspace_folders
.map(|workspaces| { .map(|workspaces| {
workspaces workspaces
@ -201,7 +207,7 @@ fn run_server() -> anyhow::Result<()> {
}) })
.filter(|workspaces| !workspaces.is_empty()) .filter(|workspaces| !workspaces.is_empty())
.unwrap_or_else(|| vec![root_path.clone()]); .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_code);
if let Some(json) = initialization_options { if let Some(json) = initialization_options {
if let Err(e) = config.update(json) { if let Err(e) = config.update(json) {
use lsp_types::{ use lsp_types::{
@ -231,10 +237,6 @@ fn run_server() -> anyhow::Result<()> {
connection.initialize_finish(initialize_id, initialize_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() { if !config.has_linked_projects() && config.detached_files().is_empty() {
config.rediscover_workspaces(); config.rediscover_workspaces();
} }

View File

@ -565,6 +565,7 @@ pub struct Config {
data: ConfigData, data: ConfigData,
detached_files: Vec<AbsPathBuf>, detached_files: Vec<AbsPathBuf>,
snippets: Vec<Snippet>, snippets: Vec<Snippet>,
is_visual_studio_code: bool,
} }
type ParallelCachePrimingNumThreads = u8; type ParallelCachePrimingNumThreads = u8;
@ -760,6 +761,7 @@ impl Config {
root_path: AbsPathBuf, root_path: AbsPathBuf,
caps: ClientCapabilities, caps: ClientCapabilities,
workspace_roots: Vec<AbsPathBuf>, workspace_roots: Vec<AbsPathBuf>,
is_visual_studio_code: bool,
) -> Self { ) -> Self {
Config { Config {
caps, caps,
@ -769,6 +771,7 @@ impl Config {
root_path, root_path,
snippets: Default::default(), snippets: Default::default(),
workspace_roots, workspace_roots,
is_visual_studio_code,
} }
} }
@ -1667,6 +1670,12 @@ impl Config {
pub fn typing_autoclose_angle(&self) -> bool { pub fn typing_autoclose_angle(&self) -> bool {
self.data.typing_autoClosingAngleBrackets_enable 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_code(&self) -> bool {
self.is_visual_studio_code
}
} }
// Deserialization definitions // Deserialization definitions
@ -2555,8 +2564,12 @@ mod tests {
#[test] #[test]
fn proc_macro_srv_null() { fn proc_macro_srv_null() {
let mut config = let mut config = Config::new(
Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); AbsPathBuf::try_from(project_root()).unwrap(),
Default::default(),
vec![],
false,
);
config config
.update(serde_json::json!({ .update(serde_json::json!({
"procMacro_server": null, "procMacro_server": null,
@ -2567,8 +2580,12 @@ mod tests {
#[test] #[test]
fn proc_macro_srv_abs() { fn proc_macro_srv_abs() {
let mut config = let mut config = Config::new(
Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); AbsPathBuf::try_from(project_root()).unwrap(),
Default::default(),
vec![],
false,
);
config config
.update(serde_json::json!({ .update(serde_json::json!({
"procMacro": {"server": project_root().display().to_string()} "procMacro": {"server": project_root().display().to_string()}
@ -2579,8 +2596,12 @@ mod tests {
#[test] #[test]
fn proc_macro_srv_rel() { fn proc_macro_srv_rel() {
let mut config = let mut config = Config::new(
Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); AbsPathBuf::try_from(project_root()).unwrap(),
Default::default(),
vec![],
false,
);
config config
.update(serde_json::json!({ .update(serde_json::json!({
"procMacro": {"server": "./server"} "procMacro": {"server": "./server"}

View File

@ -538,7 +538,12 @@ mod tests {
let (sender, _) = crossbeam_channel::unbounded(); let (sender, _) = crossbeam_channel::unbounded();
let state = GlobalState::new( let state = GlobalState::new(
sender, 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 snap = state.snapshot();
let mut actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap); let mut actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap);

View File

@ -443,15 +443,17 @@ pub(crate) fn inlay_hint(
file_id: FileId, file_id: FileId,
inlay_hint: InlayHint, inlay_hint: InlayHint,
) -> Cancellable<lsp_types::InlayHint> { ) -> Cancellable<lsp_types::InlayHint> {
let is_visual_studio_code = snap.config.is_visual_studio_code();
let needs_resolve = inlay_hint.needs_resolve; let needs_resolve = inlay_hint.needs_resolve;
let (label, tooltip, mut something_to_resolve) = let (label, tooltip, mut something_to_resolve) =
inlay_hint_label(snap, fields_to_resolve, needs_resolve, inlay_hint.label)?; 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 =
something_to_resolve |= inlay_hint.text_edit.is_some(); if !is_visual_studio_code && needs_resolve && fields_to_resolve.resolve_text_edits {
None something_to_resolve |= inlay_hint.text_edit.is_some();
} else { None
inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)) } else {
}; inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it))
};
let data = if needs_resolve && something_to_resolve { let data = if needs_resolve && something_to_resolve {
Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.0 }).unwrap()) Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.0 }).unwrap())
} else { } else {

View File

@ -150,6 +150,7 @@ impl Project<'_> {
..Default::default() ..Default::default()
}, },
roots, roots,
false,
); );
config.update(self.config).expect("invalid config"); config.update(self.config).expect("invalid config");
config.rediscover_workspaces(); config.rediscover_workspaces();