@@ -296,19 +296,28 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
.await;
let active_call_a = cx_a.read(ActiveCall::global);
+ let capabilities = lsp::ServerCapabilities {
+ completion_provider: Some(lsp::CompletionOptions {
+ trigger_characters: Some(vec![".".to_string()]),
+ resolve_provider: Some(true),
+ ..lsp::CompletionOptions::default()
+ }),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- capabilities: lsp::ServerCapabilities {
- completion_provider: Some(lsp::CompletionOptions {
- trigger_characters: Some(vec![".".to_string()]),
- resolve_provider: Some(true),
- ..Default::default()
- }),
- ..Default::default()
- },
- ..Default::default()
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
},
);
@@ -566,11 +575,14 @@ async fn test_collaborating_with_code_actions(
cx_b.update(editor::init);
- // Set up a fake language server.
client_a.language_registry().add(rust_lang());
let mut fake_language_servers = client_a
.language_registry()
.register_fake_lsp("Rust", FakeLspAdapter::default());
+ client_b.language_registry().add(rust_lang());
+ client_b
+ .language_registry()
+ .register_fake_lsp("Rust", FakeLspAdapter::default());
client_a
.fs()
@@ -775,19 +787,27 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
cx_b.update(editor::init);
- // Set up a fake language server.
+ let capabilities = lsp::ServerCapabilities {
+ rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
+ prepare_provider: Some(true),
+ work_done_progress_options: Default::default(),
+ })),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- capabilities: lsp::ServerCapabilities {
- rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
- prepare_provider: Some(true),
- work_done_progress_options: Default::default(),
- })),
- ..Default::default()
- },
- ..Default::default()
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
},
);
@@ -818,6 +838,8 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
.downcast::<Editor>()
.unwrap();
let fake_language_server = fake_language_servers.next().await.unwrap();
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
// Move cursor to a location that can be renamed.
let prepare_rename = editor_b.update_in(cx_b, |editor, window, cx| {
@@ -1055,7 +1077,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
project_a.read_with(cx_a, |project, cx| {
let status = project.language_server_statuses(cx).next().unwrap().1;
- assert_eq!(status.name, "the-language-server");
+ assert_eq!(status.name.0, "the-language-server");
assert_eq!(status.pending_work.len(), 1);
assert_eq!(
status.pending_work["the-token"].message.as_ref().unwrap(),
@@ -1072,7 +1094,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
project_b.read_with(cx_b, |project, cx| {
let status = project.language_server_statuses(cx).next().unwrap().1;
- assert_eq!(status.name, "the-language-server");
+ assert_eq!(status.name.0, "the-language-server");
});
executor.advance_clock(SERVER_PROGRESS_THROTTLE_TIMEOUT);
@@ -1089,7 +1111,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
project_a.read_with(cx_a, |project, cx| {
let status = project.language_server_statuses(cx).next().unwrap().1;
- assert_eq!(status.name, "the-language-server");
+ assert_eq!(status.name.0, "the-language-server");
assert_eq!(status.pending_work.len(), 1);
assert_eq!(
status.pending_work["the-token"].message.as_ref().unwrap(),
@@ -1099,7 +1121,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
project_b.read_with(cx_b, |project, cx| {
let status = project.language_server_statuses(cx).next().unwrap().1;
- assert_eq!(status.name, "the-language-server");
+ assert_eq!(status.name.0, "the-language-server");
assert_eq!(status.pending_work.len(), 1);
assert_eq!(
status.pending_work["the-token"].message.as_ref().unwrap(),
@@ -1422,18 +1444,27 @@ async fn test_on_input_format_from_guest_to_host(
.await;
let active_call_a = cx_a.read(ActiveCall::global);
+ let capabilities = lsp::ServerCapabilities {
+ document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
+ first_trigger_character: ":".to_string(),
+ more_trigger_character: Some(vec![">".to_string()]),
+ }),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- capabilities: lsp::ServerCapabilities {
- document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
- first_trigger_character: ":".to_string(),
- more_trigger_character: Some(vec![">".to_string()]),
- }),
- ..Default::default()
- },
- ..Default::default()
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
},
);
@@ -1588,16 +1619,24 @@ async fn test_mutual_editor_inlay_hint_cache_update(
});
});
+ let capabilities = lsp::ServerCapabilities {
+ inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
- client_b.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- capabilities: lsp::ServerCapabilities {
- inlay_hint_provider: Some(lsp::OneOf::Left(true)),
- ..Default::default()
- },
- ..Default::default()
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
},
);
@@ -1830,16 +1869,24 @@ async fn test_inlay_hint_refresh_is_forwarded(
});
});
+ let capabilities = lsp::ServerCapabilities {
+ inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
- client_b.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- capabilities: lsp::ServerCapabilities {
- inlay_hint_provider: Some(lsp::OneOf::Left(true)),
- ..Default::default()
- },
- ..Default::default()
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
},
);
@@ -2004,15 +2051,23 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
});
});
+ let capabilities = lsp::ServerCapabilities {
+ color_provider: Some(lsp::ColorProviderCapability::Simple(true)),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
- client_b.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- capabilities: lsp::ServerCapabilities {
- color_provider: Some(lsp::ColorProviderCapability::Simple(true)),
- ..lsp::ServerCapabilities::default()
- },
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
..FakeLspAdapter::default()
},
);
@@ -2063,6 +2118,8 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
.unwrap();
let fake_language_server = fake_language_servers.next().await.unwrap();
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
let requests_made = Arc::new(AtomicUsize::new(0));
let closure_requests_made = Arc::clone(&requests_made);
@@ -2264,24 +2321,32 @@ async fn test_lsp_pull_diagnostics(
cx_a.update(editor::init);
cx_b.update(editor::init);
+ let capabilities = lsp::ServerCapabilities {
+ diagnostic_provider: Some(lsp::DiagnosticServerCapabilities::Options(
+ lsp::DiagnosticOptions {
+ identifier: Some("test-pulls".to_string()),
+ inter_file_dependencies: true,
+ workspace_diagnostics: true,
+ work_done_progress_options: lsp::WorkDoneProgressOptions {
+ work_done_progress: None,
+ },
+ },
+ )),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
- client_b.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- capabilities: lsp::ServerCapabilities {
- diagnostic_provider: Some(lsp::DiagnosticServerCapabilities::Options(
- lsp::DiagnosticOptions {
- identifier: Some("test-pulls".to_string()),
- inter_file_dependencies: true,
- workspace_diagnostics: true,
- work_done_progress_options: lsp::WorkDoneProgressOptions {
- work_done_progress: None,
- },
- },
- )),
- ..lsp::ServerCapabilities::default()
- },
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
..FakeLspAdapter::default()
},
);
@@ -2334,6 +2399,8 @@ async fn test_lsp_pull_diagnostics(
.unwrap();
let fake_language_server = fake_language_servers.next().await.unwrap();
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
let expected_push_diagnostic_main_message = "pushed main diagnostic";
let expected_push_diagnostic_lib_message = "pushed lib diagnostic";
let expected_pull_diagnostic_main_message = "pulled main diagnostic";
@@ -2689,6 +2756,7 @@ async fn test_lsp_pull_diagnostics(
.unwrap()
.downcast::<Editor>()
.unwrap();
+ cx_b.run_until_parked();
pull_diagnostics_handle.next().await.unwrap();
assert_eq!(
@@ -4778,10 +4778,27 @@ async fn test_definition(
.await;
let active_call_a = cx_a.read(ActiveCall::global);
- let mut fake_language_servers = client_a
- .language_registry()
- .register_fake_lsp("Rust", Default::default());
+ let capabilities = lsp::ServerCapabilities {
+ definition_provider: Some(OneOf::Left(true)),
+ type_definition_provider: Some(lsp::TypeDefinitionProviderCapability::Simple(true)),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
+ let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
+ "Rust",
+ FakeLspAdapter {
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
+ },
+ );
client_a
.fs()
@@ -4827,13 +4844,19 @@ async fn test_definition(
)))
},
);
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
let definitions_1 = project_b
.update(cx_b, |p, cx| p.definitions(&buffer_b, 23, cx))
.await
.unwrap();
cx_b.read(|cx| {
- assert_eq!(definitions_1.len(), 1);
+ assert_eq!(
+ definitions_1.len(),
+ 1,
+ "Unexpected definitions: {definitions_1:?}"
+ );
assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
let target_buffer = definitions_1[0].target.buffer.read(cx);
assert_eq!(
@@ -4901,7 +4924,11 @@ async fn test_definition(
.await
.unwrap();
cx_b.read(|cx| {
- assert_eq!(type_definitions.len(), 1);
+ assert_eq!(
+ type_definitions.len(),
+ 1,
+ "Unexpected type definitions: {type_definitions:?}"
+ );
let target_buffer = type_definitions[0].target.buffer.read(cx);
assert_eq!(target_buffer.text(), "type T2 = usize;");
assert_eq!(
@@ -4925,16 +4952,26 @@ async fn test_references(
.await;
let active_call_a = cx_a.read(ActiveCall::global);
+ let capabilities = lsp::ServerCapabilities {
+ references_provider: Some(lsp::OneOf::Left(true)),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
name: "my-fake-lsp-adapter",
- capabilities: lsp::ServerCapabilities {
- references_provider: Some(lsp::OneOf::Left(true)),
- ..Default::default()
- },
- ..Default::default()
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ name: "my-fake-lsp-adapter",
+ capabilities: capabilities,
+ ..FakeLspAdapter::default()
},
);
@@ -4989,6 +5026,8 @@ async fn test_references(
}
}
});
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
let references = project_b.update(cx_b, |p, cx| p.references(&buffer_b, 7, cx));
@@ -4996,7 +5035,7 @@ async fn test_references(
executor.run_until_parked();
project_b.read_with(cx_b, |project, cx| {
let status = project.language_server_statuses(cx).next().unwrap().1;
- assert_eq!(status.name, "my-fake-lsp-adapter");
+ assert_eq!(status.name.0, "my-fake-lsp-adapter");
assert_eq!(
status.pending_work.values().next().unwrap().message,
Some("Finding references...".into())
@@ -5054,7 +5093,7 @@ async fn test_references(
executor.run_until_parked();
project_b.read_with(cx_b, |project, cx| {
let status = project.language_server_statuses(cx).next().unwrap().1;
- assert_eq!(status.name, "my-fake-lsp-adapter");
+ assert_eq!(status.name.0, "my-fake-lsp-adapter");
assert_eq!(
status.pending_work.values().next().unwrap().message,
Some("Finding references...".into())
@@ -5204,10 +5243,26 @@ async fn test_document_highlights(
)
.await;
- let mut fake_language_servers = client_a
- .language_registry()
- .register_fake_lsp("Rust", Default::default());
client_a.language_registry().add(rust_lang());
+ let capabilities = lsp::ServerCapabilities {
+ document_highlight_provider: Some(lsp::OneOf::Left(true)),
+ ..lsp::ServerCapabilities::default()
+ };
+ let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
+ "Rust",
+ FakeLspAdapter {
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
+ },
+ );
let (project_a, worktree_id) = client_a.build_local_project(path!("/root-1"), cx_a).await;
let project_id = active_call_a
@@ -5256,6 +5311,8 @@ async fn test_document_highlights(
]))
},
);
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
let highlights = project_b
.update(cx_b, |p, cx| p.document_highlights(&buffer_b, 34, cx))
@@ -5306,30 +5363,49 @@ async fn test_lsp_hover(
client_a.language_registry().add(rust_lang());
let language_server_names = ["rust-analyzer", "CrabLang-ls"];
+ let capabilities_1 = lsp::ServerCapabilities {
+ hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
+ ..lsp::ServerCapabilities::default()
+ };
+ let capabilities_2 = lsp::ServerCapabilities {
+ hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
+ ..lsp::ServerCapabilities::default()
+ };
let mut language_servers = [
client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- name: "rust-analyzer",
- capabilities: lsp::ServerCapabilities {
- hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
- ..lsp::ServerCapabilities::default()
- },
+ name: language_server_names[0],
+ capabilities: capabilities_1.clone(),
..FakeLspAdapter::default()
},
),
client_a.language_registry().register_fake_lsp(
"Rust",
FakeLspAdapter {
- name: "CrabLang-ls",
- capabilities: lsp::ServerCapabilities {
- hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
- ..lsp::ServerCapabilities::default()
- },
+ name: language_server_names[1],
+ capabilities: capabilities_2.clone(),
..FakeLspAdapter::default()
},
),
];
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ name: language_server_names[0],
+ capabilities: capabilities_1,
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ name: language_server_names[1],
+ capabilities: capabilities_2,
+ ..FakeLspAdapter::default()
+ },
+ );
let (project_a, worktree_id) = client_a.build_local_project(path!("/root-1"), cx_a).await;
let project_id = active_call_a
@@ -5423,6 +5499,8 @@ async fn test_lsp_hover(
unexpected => panic!("Unexpected server name: {unexpected}"),
}
}
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
// Request hover information as the guest.
let mut hovers = project_b
@@ -5605,10 +5683,26 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
.await;
let active_call_a = cx_a.read(ActiveCall::global);
+ let capabilities = lsp::ServerCapabilities {
+ definition_provider: Some(OneOf::Left(true)),
+ ..lsp::ServerCapabilities::default()
+ };
client_a.language_registry().add(rust_lang());
- let mut fake_language_servers = client_a
- .language_registry()
- .register_fake_lsp("Rust", Default::default());
+ let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
+ "Rust",
+ FakeLspAdapter {
+ capabilities: capabilities.clone(),
+ ..FakeLspAdapter::default()
+ },
+ );
+ client_b.language_registry().add(rust_lang());
+ client_b.language_registry().register_fake_lsp_adapter(
+ "Rust",
+ FakeLspAdapter {
+ capabilities,
+ ..FakeLspAdapter::default()
+ },
+ );
client_a
.fs()
@@ -5649,6 +5743,8 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
let definitions;
let buffer_b2;
if rng.r#gen() {
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
definitions = project_b.update(cx_b, |p, cx| p.definitions(&buffer_b1, 23, cx));
(buffer_b2, _) = project_b
.update(cx_b, |p, cx| {
@@ -5663,11 +5759,17 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
})
.await
.unwrap();
+ cx_a.run_until_parked();
+ cx_b.run_until_parked();
definitions = project_b.update(cx_b, |p, cx| p.definitions(&buffer_b1, 23, cx));
}
let definitions = definitions.await.unwrap();
- assert_eq!(definitions.len(), 1);
+ assert_eq!(
+ definitions.len(),
+ 1,
+ "Unexpected definitions: {definitions:?}"
+ );
assert_eq!(definitions[0].target.buffer, buffer_b2);
}
@@ -58,12 +58,12 @@ use language::{
range_from_lsp, range_to_lsp,
};
use lsp::{
- CodeActionKind, CompletionContext, DiagnosticSeverity, DiagnosticTag,
- DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
- FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
- LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
- LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
- RenameFilesParams, SymbolKind, TextEdit, WillRenameFiles, WorkDoneProgressCancelParams,
+ AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticSeverity,
+ DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
+ FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
+ LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
+ LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
+ OneOf, RenameFilesParams, SymbolKind, TextEdit, WillRenameFiles, WorkDoneProgressCancelParams,
WorkspaceFolder, notification::DidRenameFiles,
};
use node_runtime::read_package_installed_version;
@@ -622,7 +622,7 @@ impl LocalLspStore {
.on_request::<lsp::request::RegisterCapability, _, _>({
let this = this.clone();
move |params, cx| {
- let this = this.clone();
+ let lsp_store = this.clone();
let mut cx = cx.clone();
async move {
for reg in params.registrations {
@@ -630,7 +630,7 @@ impl LocalLspStore {
"workspace/didChangeWatchedFiles" => {
if let Some(options) = reg.register_options {
let options = serde_json::from_value(options)?;
- this.update(&mut cx, |this, cx| {
+ lsp_store.update(&mut cx, |this, cx| {
this.as_local_mut()?.on_lsp_did_change_watched_files(
server_id, ®.id, options, cx,
);
@@ -639,8 +639,9 @@ impl LocalLspStore {
}
}
"textDocument/rangeFormatting" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
@@ -659,14 +660,16 @@ impl LocalLspStore {
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider =
Some(provider);
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
anyhow::Ok(())
})??;
}
"textDocument/onTypeFormatting" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
@@ -683,15 +686,17 @@ impl LocalLspStore {
capabilities
.document_on_type_formatting_provider =
Some(options);
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
}
anyhow::Ok(())
})??;
}
"textDocument/formatting" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
@@ -710,7 +715,8 @@ impl LocalLspStore {
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider =
Some(provider);
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
anyhow::Ok(())
})??;
@@ -719,8 +725,9 @@ impl LocalLspStore {
// Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
}
"textDocument/rename" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
let options = reg
.register_options
@@ -737,7 +744,8 @@ impl LocalLspStore {
server.update_capabilities(|capabilities| {
capabilities.rename_provider = Some(options);
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
anyhow::Ok(())
})??;
@@ -755,14 +763,15 @@ impl LocalLspStore {
.on_request::<lsp::request::UnregisterCapability, _, _>({
let this = this.clone();
move |params, cx| {
- let this = this.clone();
+ let lsp_store = this.clone();
let mut cx = cx.clone();
async move {
for unreg in params.unregisterations.iter() {
match unreg.method.as_str() {
"workspace/didChangeWatchedFiles" => {
- this.update(&mut cx, |this, cx| {
- this.as_local_mut()?
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ lsp_store
+ .as_local_mut()?
.on_lsp_unregister_did_change_watched_files(
server_id, &unreg.id, cx,
);
@@ -773,44 +782,52 @@ impl LocalLspStore {
// Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
}
"textDocument/rename" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.rename_provider = None
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
})?;
}
"textDocument/rangeFormatting" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider =
None
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
})?;
}
"textDocument/onTypeFormatting" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_on_type_formatting_provider =
None;
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
})?;
}
"textDocument/formatting" => {
- this.read_with(&mut cx, |this, _| {
- if let Some(server) = this.language_server_for_id(server_id)
+ lsp_store.update(&mut cx, |lsp_store, cx| {
+ if let Some(server) =
+ lsp_store.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider = None;
- })
+ });
+ notify_server_capabilities_updated(&server, cx);
}
})?;
}
@@ -2426,7 +2443,6 @@ impl LocalLspStore {
let server_id = server_node.server_id_or_init(
|LaunchDisposition {
server_name,
-
path,
settings,
}| {
@@ -2468,18 +2484,6 @@ impl LocalLspStore {
}
};
- let lsp_store = self.weak.clone();
- let server_name = server_node.name();
- let buffer_abs_path = abs_path.to_string_lossy().to_string();
- cx.defer(move |cx| {
- lsp_store.update(cx, |_, cx| cx.emit(LspStoreEvent::LanguageServerUpdate {
- language_server_id: server_id,
- name: server_name,
- message: proto::update_language_server::Variant::RegisteredForBuffer(proto::RegisteredForBuffer {
- buffer_abs_path,
- })
- })).ok();
- });
server_id
},
)?;
@@ -2515,11 +2519,13 @@ impl LocalLspStore {
snapshot: initial_snapshot.clone(),
};
+ let mut registered = false;
self.buffer_snapshots
.entry(buffer_id)
.or_default()
.entry(server.server_id())
.or_insert_with(|| {
+ registered = true;
server.register_buffer(
uri.clone(),
adapter.language_id(&language.name()),
@@ -2534,15 +2540,18 @@ impl LocalLspStore {
.entry(buffer_id)
.or_default()
.insert(server.server_id());
- cx.emit(LspStoreEvent::LanguageServerUpdate {
- language_server_id: server.server_id(),
- name: None,
- message: proto::update_language_server::Variant::RegisteredForBuffer(
- proto::RegisteredForBuffer {
- buffer_abs_path: abs_path.to_string_lossy().to_string(),
- },
- ),
- });
+ if registered {
+ cx.emit(LspStoreEvent::LanguageServerUpdate {
+ language_server_id: server.server_id(),
+ name: None,
+ message: proto::update_language_server::Variant::RegisteredForBuffer(
+ proto::RegisteredForBuffer {
+ buffer_abs_path: abs_path.to_string_lossy().to_string(),
+ buffer_id: buffer_id.to_proto(),
+ },
+ ),
+ });
+ }
}
}
@@ -3494,6 +3503,20 @@ impl LocalLspStore {
}
}
+fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
+ if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
+ cx.emit(LspStoreEvent::LanguageServerUpdate {
+ language_server_id: server.server_id(),
+ name: Some(server.name()),
+ message: proto::update_language_server::Variant::MetadataUpdated(
+ proto::ServerMetadataUpdated {
+ capabilities: Some(capabilities),
+ },
+ ),
+ });
+ }
+}
+
#[derive(Debug)]
pub struct FormattableBuffer {
handle: Entity<Buffer>,
@@ -3533,6 +3556,7 @@ pub struct LspStore {
_maintain_buffer_languages: Task<()>,
diagnostic_summaries:
HashMap<WorktreeId, HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>>,
+ pub(super) lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
lsp_document_colors: HashMap<BufferId, DocumentColorData>,
lsp_code_lens: HashMap<BufferId, CodeLensData>,
}
@@ -3604,7 +3628,7 @@ pub enum LspStoreEvent {
#[derive(Clone, Debug, Serialize)]
pub struct LanguageServerStatus {
- pub name: String,
+ pub name: LanguageServerName,
pub pending_work: BTreeMap<String, LanguageServerProgress>,
pub has_pending_diagnostic_updates: bool,
progress_tokens: HashSet<String>,
@@ -3795,6 +3819,7 @@ impl LspStore {
language_server_statuses: Default::default(),
nonce: StdRng::from_entropy().r#gen(),
diagnostic_summaries: HashMap::default(),
+ lsp_server_capabilities: HashMap::default(),
lsp_document_colors: HashMap::default(),
lsp_code_lens: HashMap::default(),
active_entry: None,
@@ -3811,6 +3836,9 @@ impl LspStore {
request: R,
cx: &mut Context<LspStore>,
) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
+ if !self.is_capable_for_proto_request(&buffer, &request, cx) {
+ return Task::ready(Ok(R::Response::default()));
+ }
let message = request.to_proto(upstream_project_id, buffer.read(cx));
cx.spawn(async move |this, cx| {
let response = client.request(message).await?;
@@ -3853,6 +3881,7 @@ impl LspStore {
language_server_statuses: Default::default(),
nonce: StdRng::from_entropy().r#gen(),
diagnostic_summaries: HashMap::default(),
+ lsp_server_capabilities: HashMap::default(),
lsp_document_colors: HashMap::default(),
lsp_code_lens: HashMap::default(),
active_entry: None,
@@ -4428,20 +4457,73 @@ impl LspStore {
}
}
- pub fn request_lsp<R: LspCommand>(
+ // TODO: remove MultiLspQuery: instead, the proto handler should pick appropriate server(s)
+ // Then, use `send_lsp_proto_request` or analogue for most of the LSP proto requests and inline this check inside
+ fn is_capable_for_proto_request<R>(
+ &self,
+ buffer: &Entity<Buffer>,
+ request: &R,
+ cx: &Context<Self>,
+ ) -> bool
+ where
+ R: LspCommand,
+ {
+ self.check_if_capable_for_proto_request(
+ buffer,
+ |capabilities| {
+ request.check_capabilities(AdapterServerCapabilities {
+ server_capabilities: capabilities.clone(),
+ code_action_kinds: None,
+ })
+ },
+ cx,
+ )
+ }
+
+ fn check_if_capable_for_proto_request<F>(
+ &self,
+ buffer: &Entity<Buffer>,
+ check: F,
+ cx: &Context<Self>,
+ ) -> bool
+ where
+ F: Fn(&lsp::ServerCapabilities) -> bool,
+ {
+ let Some(language) = buffer.read(cx).language().cloned() else {
+ return false;
+ };
+ let relevant_language_servers = self
+ .languages
+ .lsp_adapters(&language.name())
+ .into_iter()
+ .map(|lsp_adapter| lsp_adapter.name())
+ .collect::<HashSet<_>>();
+ self.language_server_statuses
+ .iter()
+ .filter_map(|(server_id, server_status)| {
+ relevant_language_servers
+ .contains(&server_status.name)
+ .then_some(server_id)
+ })
+ .filter_map(|server_id| self.lsp_server_capabilities.get(&server_id))
+ .any(check)
+ }
+
+ pub fn request_lsp<R>(
&mut self,
- buffer_handle: Entity<Buffer>,
+ buffer: Entity<Buffer>,
server: LanguageServerToQuery,
request: R,
cx: &mut Context<Self>,
) -> Task<Result<R::Response>>
where
+ R: LspCommand,
<R::LspRequest as lsp::request::Request>::Result: Send,
<R::LspRequest as lsp::request::Request>::Params: Send,
{
if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
return self.send_lsp_proto_request(
- buffer_handle,
+ buffer,
upstream_client,
upstream_project_id,
request,
@@ -4449,7 +4531,7 @@ impl LspStore {
);
}
- let Some(language_server) = buffer_handle.update(cx, |buffer, cx| match server {
+ let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
local
.language_servers_for_buffer(buffer, cx)
@@ -4469,8 +4551,7 @@ impl LspStore {
return Task::ready(Ok(Default::default()));
};
- let buffer = buffer_handle.read(cx);
- let file = File::from_dyn(buffer.file()).and_then(File::as_local);
+ let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
let Some(file) = file else {
return Task::ready(Ok(Default::default()));
@@ -4478,7 +4559,7 @@ impl LspStore {
let lsp_params = match request.to_lsp_params_or_response(
&file.abs_path(cx),
- buffer,
+ buffer.read(cx),
&language_server,
cx,
) {
@@ -4554,7 +4635,7 @@ impl LspStore {
.response_from_lsp(
response,
this.upgrade().context("no app context")?,
- buffer_handle,
+ buffer,
language_server.server_id(),
cx.clone(),
)
@@ -4624,7 +4705,8 @@ impl LspStore {
)
}) {
let buffer = buffer_handle.read(cx);
- if !local.registered_buffers.contains_key(&buffer.remote_id()) {
+ let buffer_id = buffer.remote_id();
+ if !local.registered_buffers.contains_key(&buffer_id) {
continue;
}
if let Some((file, language)) = File::from_dyn(buffer.file())
@@ -4725,6 +4807,7 @@ impl LspStore {
proto::update_language_server::Variant::RegisteredForBuffer(
proto::RegisteredForBuffer {
buffer_abs_path: abs_path.to_string_lossy().to_string(),
+ buffer_id: buffer_id.to_proto(),
},
),
});
@@ -4900,15 +4983,20 @@ impl LspStore {
pub fn resolve_inlay_hint(
&self,
- hint: InlayHint,
- buffer_handle: Entity<Buffer>,
+ mut hint: InlayHint,
+ buffer: Entity<Buffer>,
server_id: LanguageServerId,
cx: &mut Context<Self>,
) -> Task<anyhow::Result<InlayHint>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
+ {
+ hint.resolve_state = ResolveState::Resolved;
+ return Task::ready(Ok(hint));
+ }
let request = proto::ResolveInlayHint {
project_id,
- buffer_id: buffer_handle.read(cx).remote_id().into(),
+ buffer_id: buffer.read(cx).remote_id().into(),
language_server_id: server_id.0 as u64,
hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
};
@@ -4924,7 +5012,7 @@ impl LspStore {
}
})
} else {
- let Some(lang_server) = buffer_handle.update(cx, |buffer, cx| {
+ let Some(lang_server) = buffer.update(cx, |buffer, cx| {
self.language_server_for_local_buffer(buffer, server_id, cx)
.map(|(_, server)| server.clone())
}) else {
@@ -4933,7 +5021,7 @@ impl LspStore {
if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
return Task::ready(Ok(hint));
}
- let buffer_snapshot = buffer_handle.read(cx).snapshot();
+ let buffer_snapshot = buffer.read(cx).snapshot();
cx.spawn(async move |_, cx| {
let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
@@ -4944,7 +5032,7 @@ impl LspStore {
.context("inlay hint resolve LSP request")?;
let resolved_hint = InlayHints::lsp_to_project_hint(
resolved_hint,
- &buffer_handle,
+ &buffer,
server_id,
ResolveState::Resolved,
false,
@@ -5055,7 +5143,7 @@ impl LspStore {
}
}
- pub(crate) fn linked_edit(
+ pub(crate) fn linked_edits(
&mut self,
buffer: &Entity<Buffer>,
position: Anchor,
@@ -5097,7 +5185,7 @@ impl LspStore {
}) == Some(true)
})
else {
- return Task::ready(Ok(vec![]));
+ return Task::ready(Ok(Vec::new()));
};
self.request_lsp(
@@ -5116,6 +5204,15 @@ impl LspStore {
cx: &mut Context<Self>,
) -> Task<Result<Option<Transaction>>> {
if let Some((client, project_id)) = self.upstream_client() {
+ if !self.check_if_capable_for_proto_request(
+ &buffer,
+ |capabilities| {
+ OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
+ },
+ cx,
+ ) {
+ return Task::ready(Ok(None));
+ }
let request = proto::OnTypeFormatting {
project_id,
buffer_id: buffer.read(cx).remote_id().into(),
@@ -5227,6 +5324,10 @@ impl LspStore {
cx: &mut Context<Self>,
) -> Task<Result<Vec<LocationLink>>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetDefinitions { position };
+ if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
let request_task = upstream_client.request(proto::MultiLspQuery {
buffer_id: buffer_handle.read(cx).remote_id().into(),
version: serialize_version(&buffer_handle.read(cx).version()),
@@ -5235,7 +5336,7 @@ impl LspStore {
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetDefinition(
- GetDefinitions { position }.to_proto(project_id, buffer_handle.read(cx)),
+ request.to_proto(project_id, buffer_handle.read(cx)),
)),
});
let buffer = buffer_handle.clone();
@@ -5300,6 +5401,10 @@ impl LspStore {
cx: &mut Context<Self>,
) -> Task<Result<Vec<LocationLink>>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetDeclarations { position };
+ if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
let request_task = upstream_client.request(proto::MultiLspQuery {
buffer_id: buffer_handle.read(cx).remote_id().into(),
version: serialize_version(&buffer_handle.read(cx).version()),
@@ -5308,7 +5413,7 @@ impl LspStore {
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetDeclaration(
- GetDeclarations { position }.to_proto(project_id, buffer_handle.read(cx)),
+ request.to_proto(project_id, buffer_handle.read(cx)),
)),
});
let buffer = buffer_handle.clone();
@@ -5368,23 +5473,27 @@ impl LspStore {
pub fn type_definitions(
&mut self,
- buffer_handle: &Entity<Buffer>,
+ buffer: &Entity<Buffer>,
position: PointUtf16,
cx: &mut Context<Self>,
) -> Task<Result<Vec<LocationLink>>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetTypeDefinitions { position };
+ if !self.is_capable_for_proto_request(&buffer, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
let request_task = upstream_client.request(proto::MultiLspQuery {
- buffer_id: buffer_handle.read(cx).remote_id().into(),
- version: serialize_version(&buffer_handle.read(cx).version()),
+ buffer_id: buffer.read(cx).remote_id().into(),
+ version: serialize_version(&buffer.read(cx).version()),
project_id,
strategy: Some(proto::multi_lsp_query::Strategy::All(
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
- GetTypeDefinitions { position }.to_proto(project_id, buffer_handle.read(cx)),
+ request.to_proto(project_id, buffer.read(cx)),
)),
});
- let buffer = buffer_handle.clone();
+ let buffer = buffer.clone();
cx.spawn(async move |weak_project, cx| {
let Some(project) = weak_project.upgrade() else {
return Ok(Vec::new());
@@ -5423,7 +5532,7 @@ impl LspStore {
})
} else {
let type_definitions_task = self.request_multiple_lsp_locally(
- buffer_handle,
+ buffer,
Some(position),
GetTypeDefinitions { position },
cx,
@@ -5441,23 +5550,27 @@ impl LspStore {
pub fn implementations(
&mut self,
- buffer_handle: &Entity<Buffer>,
+ buffer: &Entity<Buffer>,
position: PointUtf16,
cx: &mut Context<Self>,
) -> Task<Result<Vec<LocationLink>>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetImplementations { position };
+ if !self.is_capable_for_proto_request(buffer, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
let request_task = upstream_client.request(proto::MultiLspQuery {
- buffer_id: buffer_handle.read(cx).remote_id().into(),
- version: serialize_version(&buffer_handle.read(cx).version()),
+ buffer_id: buffer.read(cx).remote_id().into(),
+ version: serialize_version(&buffer.read(cx).version()),
project_id,
strategy: Some(proto::multi_lsp_query::Strategy::All(
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetImplementation(
- GetImplementations { position }.to_proto(project_id, buffer_handle.read(cx)),
+ request.to_proto(project_id, buffer.read(cx)),
)),
});
- let buffer = buffer_handle.clone();
+ let buffer = buffer.clone();
cx.spawn(async move |weak_project, cx| {
let Some(project) = weak_project.upgrade() else {
return Ok(Vec::new());
@@ -5496,7 +5609,7 @@ impl LspStore {
})
} else {
let implementations_task = self.request_multiple_lsp_locally(
- buffer_handle,
+ buffer,
Some(position),
GetImplementations { position },
cx,
@@ -5514,23 +5627,27 @@ impl LspStore {
pub fn references(
&mut self,
- buffer_handle: &Entity<Buffer>,
+ buffer: &Entity<Buffer>,
position: PointUtf16,
cx: &mut Context<Self>,
) -> Task<Result<Vec<Location>>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetReferences { position };
+ if !self.is_capable_for_proto_request(&buffer, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
let request_task = upstream_client.request(proto::MultiLspQuery {
- buffer_id: buffer_handle.read(cx).remote_id().into(),
- version: serialize_version(&buffer_handle.read(cx).version()),
+ buffer_id: buffer.read(cx).remote_id().into(),
+ version: serialize_version(&buffer.read(cx).version()),
project_id,
strategy: Some(proto::multi_lsp_query::Strategy::All(
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetReferences(
- GetReferences { position }.to_proto(project_id, buffer_handle.read(cx)),
+ request.to_proto(project_id, buffer.read(cx)),
)),
});
- let buffer = buffer_handle.clone();
+ let buffer = buffer.clone();
cx.spawn(async move |weak_project, cx| {
let Some(project) = weak_project.upgrade() else {
return Ok(Vec::new());
@@ -5569,7 +5686,7 @@ impl LspStore {
})
} else {
let references_task = self.request_multiple_lsp_locally(
- buffer_handle,
+ buffer,
Some(position),
GetReferences { position },
cx,
@@ -5587,28 +5704,31 @@ impl LspStore {
pub fn code_actions(
&mut self,
- buffer_handle: &Entity<Buffer>,
+ buffer: &Entity<Buffer>,
range: Range<Anchor>,
kinds: Option<Vec<CodeActionKind>>,
cx: &mut Context<Self>,
) -> Task<Result<Vec<CodeAction>>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetCodeActions {
+ range: range.clone(),
+ kinds: kinds.clone(),
+ };
+ if !self.is_capable_for_proto_request(buffer, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
let request_task = upstream_client.request(proto::MultiLspQuery {
- buffer_id: buffer_handle.read(cx).remote_id().into(),
- version: serialize_version(&buffer_handle.read(cx).version()),
+ buffer_id: buffer.read(cx).remote_id().into(),
+ version: serialize_version(&buffer.read(cx).version()),
project_id,
strategy: Some(proto::multi_lsp_query::Strategy::All(
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetCodeActions(
- GetCodeActions {
- range: range.clone(),
- kinds: kinds.clone(),
- }
- .to_proto(project_id, buffer_handle.read(cx)),
+ request.to_proto(project_id, buffer.read(cx)),
)),
});
- let buffer = buffer_handle.clone();
+ let buffer = buffer.clone();
cx.spawn(async move |weak_project, cx| {
let Some(project) = weak_project.upgrade() else {
return Ok(Vec::new());
@@ -5650,7 +5770,7 @@ impl LspStore {
})
} else {
let all_actions_task = self.request_multiple_lsp_locally(
- buffer_handle,
+ buffer,
Some(range.start),
GetCodeActions {
range: range.clone(),
@@ -5752,6 +5872,10 @@ impl LspStore {
cx: &mut Context<Self>,
) -> Task<Result<HashMap<LanguageServerId, Vec<CodeAction>>>> {
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetCodeLens;
+ if !self.is_capable_for_proto_request(buffer, &request, cx) {
+ return Task::ready(Ok(HashMap::default()));
+ }
let request_task = upstream_client.request(proto::MultiLspQuery {
buffer_id: buffer.read(cx).remote_id().into(),
version: serialize_version(&buffer.read(cx).version()),
@@ -5760,7 +5884,7 @@ impl LspStore {
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetCodeLens(
- GetCodeLens.to_proto(project_id, buffer.read(cx)),
+ request.to_proto(project_id, buffer.read(cx)),
)),
});
let buffer = buffer.clone();
@@ -5844,11 +5968,15 @@ impl LspStore {
let language_registry = self.languages.clone();
if let Some((upstream_client, project_id)) = self.upstream_client() {
+ let request = GetCompletions { position, context };
+ if !self.is_capable_for_proto_request(buffer, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
let task = self.send_lsp_proto_request(
buffer.clone(),
upstream_client,
project_id,
- GetCompletions { position, context },
+ request,
cx,
);
let language = buffer.read(cx).language().cloned();
@@ -5986,11 +6114,17 @@ impl LspStore {
cx: &mut Context<Self>,
) -> Task<Result<bool>> {
let client = self.upstream_client();
-
let buffer_id = buffer.read(cx).remote_id();
let buffer_snapshot = buffer.read(cx).snapshot();
- cx.spawn(async move |this, cx| {
+ if !self.check_if_capable_for_proto_request(
+ &buffer,
+ GetCompletions::can_resolve_completions,
+ cx,
+ ) {
+ return Task::ready(Ok(false));
+ }
+ cx.spawn(async move |lsp_store, cx| {
let mut did_resolve = false;
if let Some((client, project_id)) = client {
for completion_index in completion_indices {
@@ -6027,7 +6161,7 @@ impl LspStore {
completion.source.server_id()
};
if let Some(server_id) = server_id {
- let server_and_adapter = this
+ let server_and_adapter = lsp_store
.read_with(cx, |lsp_store, _| {
let server = lsp_store.language_server_for_id(server_id)?;
let adapter =
@@ -6078,13 +6212,7 @@ impl LspStore {
completion_index: usize,
) -> Result<()> {
let server_id = server.server_id();
- let can_resolve = server
- .capabilities()
- .completion_provider
- .as_ref()
- .and_then(|options| options.resolve_provider)
- .unwrap_or(false);
- if !can_resolve {
+ if !GetCompletions::can_resolve_completions(&server.capabilities()) {
return Ok(());
}
@@ -6435,16 +6563,24 @@ impl LspStore {
pub fn pull_diagnostics(
&mut self,
- buffer_handle: Entity<Buffer>,
+ buffer: Entity<Buffer>,
cx: &mut Context<Self>,
) -> Task<Result<Vec<LspPullDiagnostics>>> {
- let buffer = buffer_handle.read(cx);
- let buffer_id = buffer.remote_id();
+ let buffer_id = buffer.read(cx).remote_id();
if let Some((client, upstream_project_id)) = self.upstream_client() {
+ if !self.is_capable_for_proto_request(
+ &buffer,
+ &GetDocumentDiagnostics {
+ previous_result_id: None,
+ },
+ cx,
+ ) {
+ return Task::ready(Ok(Vec::new()));
+ }
let request_task = client.request(proto::MultiLspQuery {
buffer_id: buffer_id.to_proto(),
- version: serialize_version(&buffer_handle.read(cx).version()),
+ version: serialize_version(&buffer.read(cx).version()),
project_id: upstream_project_id,
strategy: Some(proto::multi_lsp_query::Strategy::All(
proto::AllLanguageServers {},
@@ -6453,7 +6589,7 @@ impl LspStore {
proto::GetDocumentDiagnostics {
project_id: upstream_project_id,
buffer_id: buffer_id.to_proto(),
- version: serialize_version(&buffer_handle.read(cx).version()),
+ version: serialize_version(&buffer.read(cx).version()),
},
)),
});
@@ -6475,7 +6611,7 @@ impl LspStore {
.collect())
})
} else {
- let server_ids = buffer_handle.update(cx, |buffer, cx| {
+ let server_ids = buffer.update(cx, |buffer, cx| {
self.language_servers_for_local_buffer(buffer, cx)
.map(|(_, server)| server.server_id())
.collect::<Vec<_>>()
@@ -6485,7 +6621,7 @@ impl LspStore {
.map(|server_id| {
let result_id = self.result_id(server_id, buffer_id, cx);
self.request_lsp(
- buffer_handle.clone(),
+ buffer.clone(),
LanguageServerToQuery::Other(server_id),
GetDocumentDiagnostics {
previous_result_id: result_id,
@@ -6507,34 +6643,36 @@ impl LspStore {
pub fn inlay_hints(
&mut self,
- buffer_handle: Entity<Buffer>,
+ buffer: Entity<Buffer>,
range: Range<Anchor>,
cx: &mut Context<Self>,
) -> Task<anyhow::Result<Vec<InlayHint>>> {
- let buffer = buffer_handle.read(cx);
let range_start = range.start;
let range_end = range.end;
- let buffer_id = buffer.remote_id().into();
- let lsp_request = InlayHints { range };
+ let buffer_id = buffer.read(cx).remote_id().into();
+ let request = InlayHints { range };
if let Some((client, project_id)) = self.upstream_client() {
- let request = proto::InlayHints {
+ if !self.is_capable_for_proto_request(&buffer, &request, cx) {
+ return Task::ready(Ok(Vec::new()));
+ }
+ let proto_request = proto::InlayHints {
project_id,
buffer_id,
start: Some(serialize_anchor(&range_start)),
end: Some(serialize_anchor(&range_end)),
- version: serialize_version(&buffer_handle.read(cx).version()),
+ version: serialize_version(&buffer.read(cx).version()),
};
cx.spawn(async move |project, cx| {
let response = client
- .request(request)
+ .request(proto_request)
.await
.context("inlay hints proto request")?;
LspCommand::response_from_proto(
- lsp_request,
+ request,
response,
project.upgrade().context("No project")?,
- buffer_handle.clone(),
+ buffer.clone(),
cx.clone(),
)
.await
@@ -6542,13 +6680,13 @@ impl LspStore {
})
} else {
let lsp_request_task = self.request_lsp(
- buffer_handle.clone(),
+ buffer.clone(),
LanguageServerToQuery::FirstCapable,
- lsp_request,
+ request,
cx,
);
cx.spawn(async move |_, cx| {
- buffer_handle
+ buffer
.update(cx, |buffer, _| {
buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
})?
@@ -6772,6 +6910,11 @@ impl LspStore {
cx: &mut Context<Self>,
) -> Task<anyhow::Result<HashMap<LanguageServerId, HashSet<DocumentColor>>>> {
if let Some((client, project_id)) = self.upstream_client() {
+ let request = GetDocumentColor {};
+ if !self.is_capable_for_proto_request(buffer, &request, cx) {
+ return Task::ready(Ok(HashMap::default()));
+ }
+
let request_task = client.request(proto::MultiLspQuery {
project_id,
buffer_id: buffer.read(cx).remote_id().to_proto(),
@@ -6780,7 +6923,7 @@ impl LspStore {
proto::AllLanguageServers {},
)),
request: Some(proto::multi_lsp_query::Request::GetDocumentColor(
- GetDocumentColor {}.to_proto(project_id, buffer.read(cx)),
+ request.to_proto(project_id, buffer.read(cx)),
)),
});
let buffer = buffer.clone();
@@ -6808,7 +6951,7 @@ impl LspStore {
}
})
.map(|(server_id, color_response)| {
- let response = GetDocumentColor {}.response_from_proto(
+ let response = request.response_from_proto(
color_response,
project.clone(),
buffer.clone(),