lsp: Fix workspace diagnostics lag & add streaming support (#34022)
Closes https://github.com/zed-industries/zed/issues/33980 Closes https://github.com/zed-industries/zed/discussions/33979 - Switches to the debounce task pattern for diagnostic summary computations, which most importantly lets us do them only once when a large number of DiagnosticUpdated events are received at once. - Makes workspace diagnostic requests not time out if a partial result is received. - Makes diagnostics from workspace diagnostic partial results get merged. There might be some related areas where we're not fully complying with the LSP spec but they may be outside the scope of what this PR should include. Release Notes: - Added support for streaming LSP workspace diagnostics. - Fixed editor freeze from large LSP workspace diagnostic responses.
This commit is contained in:
@@ -80,6 +80,7 @@ pub(crate) struct ProjectDiagnosticsEditor {
|
||||
include_warnings: bool,
|
||||
update_excerpts_task: Option<Task<Result<()>>>,
|
||||
cargo_diagnostics_fetch: CargoDiagnosticsFetchState,
|
||||
diagnostic_summary_update: Task<()>,
|
||||
_subscription: Subscription,
|
||||
}
|
||||
|
||||
@@ -179,7 +180,16 @@ impl ProjectDiagnosticsEditor {
|
||||
path,
|
||||
} => {
|
||||
this.paths_to_update.insert(path.clone());
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
let project = project.clone();
|
||||
this.diagnostic_summary_update = cx.spawn(async move |this, cx| {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(30))
|
||||
.await;
|
||||
this.update(cx, |this, cx| {
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
})
|
||||
.log_err();
|
||||
});
|
||||
cx.emit(EditorEvent::TitleChanged);
|
||||
|
||||
if this.editor.focus_handle(cx).contains_focused(window, cx) || this.focus_handle.contains_focused(window, cx) {
|
||||
@@ -276,6 +286,7 @@ impl ProjectDiagnosticsEditor {
|
||||
cancel_task: None,
|
||||
diagnostic_sources: Arc::new(Vec::new()),
|
||||
},
|
||||
diagnostic_summary_update: Task::ready(()),
|
||||
_subscription: project_event_subscription,
|
||||
};
|
||||
this.update_all_diagnostics(true, window, cx);
|
||||
|
||||
@@ -9,6 +9,7 @@ use language::Diagnostic;
|
||||
use project::project_settings::{GoToDiagnosticSeverityFilter, ProjectSettings};
|
||||
use settings::Settings;
|
||||
use ui::{Button, ButtonLike, Color, Icon, IconName, Label, Tooltip, h_flex, prelude::*};
|
||||
use util::ResultExt;
|
||||
use workspace::{StatusItemView, ToolbarItemEvent, Workspace, item::ItemHandle};
|
||||
|
||||
use crate::{Deploy, IncludeWarnings, ProjectDiagnosticsEditor};
|
||||
@@ -20,6 +21,7 @@ pub struct DiagnosticIndicator {
|
||||
current_diagnostic: Option<Diagnostic>,
|
||||
_observe_active_editor: Option<Subscription>,
|
||||
diagnostics_update: Task<()>,
|
||||
diagnostic_summary_update: Task<()>,
|
||||
}
|
||||
|
||||
impl Render for DiagnosticIndicator {
|
||||
@@ -135,8 +137,16 @@ impl DiagnosticIndicator {
|
||||
}
|
||||
|
||||
project::Event::DiagnosticsUpdated { .. } => {
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
cx.notify();
|
||||
this.diagnostic_summary_update = cx.spawn(async move |this, cx| {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(30))
|
||||
.await;
|
||||
this.update(cx, |this, cx| {
|
||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||
cx.notify();
|
||||
})
|
||||
.log_err();
|
||||
});
|
||||
}
|
||||
|
||||
_ => {}
|
||||
@@ -150,6 +160,7 @@ impl DiagnosticIndicator {
|
||||
current_diagnostic: None,
|
||||
_observe_active_editor: None,
|
||||
diagnostics_update: Task::ready(()),
|
||||
diagnostic_summary_update: Task::ready(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user