Allow to fetch cargo diagnostics separately (#29706)
Adjusts the way `cargo` and `rust-analyzer` diagnostics are fetched into Zed. Nothing is changed for defaults: in this mode, Zed does nothing but reports file updates, which trigger rust-analyzers' mechanisms: * generating internal diagnostics, which it is able to produce on the fly, without blocking cargo lock. Unfortunately, there are not that many diagnostics in r-a, and some of them have false-positives compared to rustc ones * running `cargo check --workspace --all-targets` on each file save, taking the cargo lock For large projects like Zed, this might take a while, reducing the ability to choose how to work with the project: e.g. it's impossible to save multiple times without long diagnostics refreshes (may happen automatically on e.g. focus loss), save the project and run it instantly without waiting for cargo check to finish, etc. In addition, it's relatively tricky to reconfigure r-a to run a different command, with different arguments and maybe different env vars: that would require a language server restart (and a large project reindex) and fiddling with multiple JSON fields. The new mode aims to separate out cargo diagnostics into its own loop so that all Zed diagnostics features are supported still. For that, an extra mode was introduced: ```jsonc "rust": { // When enabled, Zed runs `cargo check --message-format=json`-based commands and // collect cargo diagnostics instead of rust-analyzer. "fetch_cargo_diagnostics": false, // A command override for fetching the cargo diagnostics. // First argument is the command, followed by the arguments. "diagnostics_fetch_command": [ "cargo", "check", "--quiet", "--workspace", "--message-format=json", "--all-targets", "--keep-going" ], // Extra environment variables to pass to the diagnostics fetch command. "env": {} } ``` which calls to cargo, parses its output and mixes in with the existing diagnostics: https://github.com/user-attachments/assets/e986f955-b452-4995-8aac-3049683dd22c Release Notes: - Added a way to get diagnostics from cargo and rust-analyzer without mutually locking each other - Added `ctrl-r` binding to refresh diagnostics in the project diagnostics editor context
This commit is contained in:
parent
5e4be013af
commit
e07ffe7cf1
20 changed files with 1306 additions and 89 deletions
|
@ -467,10 +467,11 @@ impl LocalLspStore {
|
|||
adapter.process_diagnostics(&mut params, server_id, buffer);
|
||||
}
|
||||
|
||||
this.update_diagnostics(
|
||||
this.merge_diagnostics(
|
||||
server_id,
|
||||
params,
|
||||
&adapter.disk_based_diagnostic_sources,
|
||||
|diagnostic, cx| adapter.retain_old_diagnostic(diagnostic, cx),
|
||||
cx,
|
||||
)
|
||||
.log_err();
|
||||
|
@ -3395,7 +3396,7 @@ pub struct LanguageServerStatus {
|
|||
pub name: String,
|
||||
pub pending_work: BTreeMap<String, LanguageServerProgress>,
|
||||
pub has_pending_diagnostic_updates: bool,
|
||||
progress_tokens: HashSet<String>,
|
||||
pub progress_tokens: HashSet<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -6237,6 +6238,13 @@ impl LspStore {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn language_server_with_name(&self, name: &str, cx: &App) -> Option<LanguageServerId> {
|
||||
self.as_local()?
|
||||
.lsp_tree
|
||||
.read(cx)
|
||||
.server_id_for_name(&LanguageServerName::from(name))
|
||||
}
|
||||
|
||||
pub fn language_servers_for_local_buffer<'a>(
|
||||
&'a self,
|
||||
buffer: &Buffer,
|
||||
|
@ -6380,10 +6388,10 @@ impl LspStore {
|
|||
diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> anyhow::Result<()> {
|
||||
self.merge_diagnostic_entries(server_id, abs_path, version, diagnostics, |_| false, cx)
|
||||
self.merge_diagnostic_entries(server_id, abs_path, version, diagnostics, |_, _| false, cx)
|
||||
}
|
||||
|
||||
pub fn merge_diagnostic_entries<F: Fn(&Diagnostic) -> bool + Clone>(
|
||||
pub fn merge_diagnostic_entries<F: Fn(&Diagnostic, &App) -> bool + Clone>(
|
||||
&mut self,
|
||||
server_id: LanguageServerId,
|
||||
abs_path: PathBuf,
|
||||
|
@ -6416,7 +6424,7 @@ impl LspStore {
|
|||
.get_diagnostics(server_id)
|
||||
.into_iter()
|
||||
.flat_map(|diag| {
|
||||
diag.iter().filter(|v| filter(&v.diagnostic)).map(|v| {
|
||||
diag.iter().filter(|v| filter(&v.diagnostic, cx)).map(|v| {
|
||||
let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
|
||||
let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
|
||||
DiagnosticEntry {
|
||||
|
@ -7021,27 +7029,38 @@ impl LspStore {
|
|||
envelope: TypedEnvelope<proto::LanguageServerIdForName>,
|
||||
mut cx: AsyncApp,
|
||||
) -> Result<proto::LanguageServerIdForNameResponse> {
|
||||
let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
|
||||
let name = &envelope.payload.name;
|
||||
lsp_store
|
||||
.update(&mut cx, |lsp_store, cx| {
|
||||
let buffer = lsp_store.buffer_store.read(cx).get_existing(buffer_id)?;
|
||||
let server_id = buffer.update(cx, |buffer, cx| {
|
||||
lsp_store
|
||||
.language_servers_for_local_buffer(buffer, cx)
|
||||
.find_map(|(adapter, server)| {
|
||||
if adapter.name.0.as_ref() == name {
|
||||
Some(server.server_id())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
});
|
||||
Ok(server_id)
|
||||
})?
|
||||
.map(|server_id| proto::LanguageServerIdForNameResponse {
|
||||
server_id: server_id.map(|id| id.to_proto()),
|
||||
})
|
||||
match envelope.payload.buffer_id {
|
||||
Some(buffer_id) => {
|
||||
let buffer_id = BufferId::new(buffer_id)?;
|
||||
lsp_store
|
||||
.update(&mut cx, |lsp_store, cx| {
|
||||
let buffer = lsp_store.buffer_store.read(cx).get_existing(buffer_id)?;
|
||||
let server_id = buffer.update(cx, |buffer, cx| {
|
||||
lsp_store
|
||||
.language_servers_for_local_buffer(buffer, cx)
|
||||
.find_map(|(adapter, server)| {
|
||||
if adapter.name.0.as_ref() == name {
|
||||
Some(server.server_id())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
});
|
||||
Ok(server_id)
|
||||
})?
|
||||
.map(|server_id| proto::LanguageServerIdForNameResponse {
|
||||
server_id: server_id.map(|id| id.to_proto()),
|
||||
})
|
||||
}
|
||||
None => lsp_store.update(&mut cx, |lsp_store, cx| {
|
||||
proto::LanguageServerIdForNameResponse {
|
||||
server_id: lsp_store
|
||||
.language_server_with_name(name, cx)
|
||||
.map(|id| id.to_proto()),
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_rename_project_entry(
|
||||
|
@ -7517,7 +7536,7 @@ impl LspStore {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_lsp_progress(
|
||||
pub fn on_lsp_progress(
|
||||
&mut self,
|
||||
progress: lsp::ProgressParams,
|
||||
language_server_id: LanguageServerId,
|
||||
|
@ -8550,12 +8569,12 @@ impl LspStore {
|
|||
language_server_id,
|
||||
params,
|
||||
disk_based_sources,
|
||||
|_| false,
|
||||
|_, _| false,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn merge_diagnostics<F: Fn(&Diagnostic) -> bool + Clone>(
|
||||
pub fn merge_diagnostics<F: Fn(&Diagnostic, &App) -> bool + Clone>(
|
||||
&mut self,
|
||||
language_server_id: LanguageServerId,
|
||||
mut params: lsp::PublishDiagnosticsParams,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue