Don't emit event when LSP reports consecutive empty diagnostics

This is related to #849: in that pull request we avoided *storing*
empty diagnostics, but we'd still report an event when receiving
consecutive empty diagnostics. So if the project diagnostics editor
was open, it could happen that opening a buffer would cause the
language server to report zero diagnostics. We would therefore close
the buffer because there were no diagnostics, but doing so would cause
the LSP to report another event with zero diagnostics. This would repeat
forever, causing Zed to use a lot of CPU and the UI not to refresh properly.

With this commit we will simply avoid emitting a `DiagnosticsUpdated` event
altogether if no diagnostics were present before *and* the LSP is reporting
a `PublishDiagnostics` event with no diagnostics in it.
This commit is contained in:
Antonio Scandurra 2022-04-20 15:02:38 +02:00
parent c2fa7b9bf9
commit 8ef6b1d8a9
2 changed files with 54 additions and 25 deletions

View file

@ -564,33 +564,37 @@ impl LocalWorktree {
worktree_path: Arc<Path>,
diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
_: &mut ModelContext<Worktree>,
) -> Result<()> {
let summary = DiagnosticSummary::new(&diagnostics);
if summary.is_empty() {
) -> Result<bool> {
self.diagnostics.remove(&worktree_path);
let old_summary = self
.diagnostic_summaries
.remove(&PathKey(worktree_path.clone()))
.unwrap_or_default();
let new_summary = DiagnosticSummary::new(&diagnostics);
if !new_summary.is_empty() {
self.diagnostic_summaries
.remove(&PathKey(worktree_path.clone()));
self.diagnostics.remove(&worktree_path);
} else {
self.diagnostic_summaries
.insert(PathKey(worktree_path.clone()), summary.clone());
.insert(PathKey(worktree_path.clone()), new_summary);
self.diagnostics.insert(worktree_path.clone(), diagnostics);
}
if let Some(share) = self.share.as_ref() {
self.client
.send(proto::UpdateDiagnosticSummary {
project_id: share.project_id,
worktree_id: self.id().to_proto(),
summary: Some(proto::DiagnosticSummary {
path: worktree_path.to_string_lossy().to_string(),
error_count: summary.error_count as u32,
warning_count: summary.warning_count as u32,
}),
})
.log_err();
let updated = !old_summary.is_empty() || !new_summary.is_empty();
if updated {
if let Some(share) = self.share.as_ref() {
self.client
.send(proto::UpdateDiagnosticSummary {
project_id: share.project_id,
worktree_id: self.id().to_proto(),
summary: Some(proto::DiagnosticSummary {
path: worktree_path.to_string_lossy().to_string(),
error_count: new_summary.error_count as u32,
warning_count: new_summary.warning_count as u32,
}),
})
.log_err();
}
}
Ok(())
Ok(updated)
}
pub fn scan_complete(&self) -> impl Future<Output = ()> {