Remove summaries that don't contain any errors or warnings

When opening a buffer, some language servers might start reporting
diagnostics. When closing a buffer, they might report that no diagnostics
are present for that buffer. Previously, we would keep an empty summary entry
which would cause us to open a buffer in the project diagnostics view, only to
drop it because it contained no diagnostics. However, the act of opening it
caused the language server to asynchronously report non-empty diagnostics.
We would therefore handle this as an update, but the previous closing of the
buffer would cause the language server to report empty diagnostics again. This
would cause the project diagnostics view to thrash infinitely between these two
states, pegging the CPU and constantly refreshing the UI.

With this commit we won't maintain empty summary entries for files that contain
no diagnostics, which fixes the above issue.

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-04-19 15:30:46 +02:00
parent 1cd23df4d8
commit ef784cf21e
5 changed files with 43 additions and 29 deletions

View File

@ -2363,6 +2363,25 @@ mod tests {
]
);
});
// Simulate a language server reporting no errors for a file.
fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
lsp::PublishDiagnosticsParams {
uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
version: None,
diagnostics: vec![],
},
);
project_a
.condition(cx_a, |project, cx| {
project.diagnostic_summaries(cx).collect::<Vec<_>>() == &[]
})
.await;
project_b
.condition(cx_b, |project, cx| {
project.diagnostic_summaries(cx).collect::<Vec<_>>() == &[]
})
.await;
}
#[gpui::test(iterations = 10)]

View File

@ -158,8 +158,6 @@ pub struct ProjectPath {
pub struct DiagnosticSummary {
pub error_count: usize,
pub warning_count: usize,
pub info_count: usize,
pub hint_count: usize,
}
#[derive(Debug)]
@ -195,8 +193,6 @@ impl DiagnosticSummary {
let mut this = Self {
error_count: 0,
warning_count: 0,
info_count: 0,
hint_count: 0,
};
for entry in diagnostics {
@ -204,8 +200,6 @@ impl DiagnosticSummary {
match entry.diagnostic.severity {
DiagnosticSeverity::ERROR => this.error_count += 1,
DiagnosticSeverity::WARNING => this.warning_count += 1,
DiagnosticSeverity::INFORMATION => this.info_count += 1,
DiagnosticSeverity::HINT => this.hint_count += 1,
_ => {}
}
}
@ -214,13 +208,15 @@ impl DiagnosticSummary {
this
}
pub fn is_empty(&self) -> bool {
self.error_count == 0 && self.warning_count == 0
}
pub fn to_proto(&self, path: &Path) -> proto::DiagnosticSummary {
proto::DiagnosticSummary {
path: path.to_string_lossy().to_string(),
error_count: self.error_count as u32,
warning_count: self.warning_count as u32,
info_count: self.info_count as u32,
hint_count: self.hint_count as u32,
}
}
}
@ -3497,8 +3493,6 @@ impl Project {
for (_, path_summary) in self.diagnostic_summaries(cx) {
summary.error_count += path_summary.error_count;
summary.warning_count += path_summary.warning_count;
summary.info_count += path_summary.info_count;
summary.hint_count += path_summary.hint_count;
}
summary
}

View File

@ -233,8 +233,6 @@ impl Worktree {
DiagnosticSummary {
error_count: summary.error_count as usize,
warning_count: summary.warning_count as usize,
info_count: summary.info_count as usize,
hint_count: summary.hint_count as usize,
},
)
}),
@ -568,9 +566,15 @@ impl LocalWorktree {
_: &mut ModelContext<Worktree>,
) -> Result<()> {
let summary = DiagnosticSummary::new(&diagnostics);
self.diagnostic_summaries
.insert(PathKey(worktree_path.clone()), summary.clone());
self.diagnostics.insert(worktree_path.clone(), diagnostics);
if 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());
self.diagnostics.insert(worktree_path.clone(), diagnostics);
}
if let Some(share) = self.share.as_ref() {
self.client
@ -581,8 +585,6 @@ impl LocalWorktree {
path: worktree_path.to_string_lossy().to_string(),
error_count: summary.error_count as u32,
warning_count: summary.warning_count as u32,
info_count: summary.info_count as u32,
hint_count: summary.hint_count as u32,
}),
})
.log_err();
@ -846,15 +848,16 @@ impl RemoteWorktree {
path: Arc<Path>,
summary: &proto::DiagnosticSummary,
) {
self.diagnostic_summaries.insert(
PathKey(path.clone()),
DiagnosticSummary {
error_count: summary.error_count as usize,
warning_count: summary.warning_count as usize,
info_count: summary.info_count as usize,
hint_count: summary.hint_count as usize,
},
);
let summary = DiagnosticSummary {
error_count: summary.error_count as usize,
warning_count: summary.warning_count as usize,
};
if summary.is_empty() {
self.diagnostic_summaries.remove(&PathKey(path.clone()));
} else {
self.diagnostic_summaries
.insert(PathKey(path.clone()), summary);
}
}
}

View File

@ -453,8 +453,6 @@ message DiagnosticSummary {
string path = 1;
uint32 error_count = 2;
uint32 warning_count = 3;
uint32 info_count = 4;
uint32 hint_count = 5;
}
message UpdateLanguageServer {

View File

@ -5,4 +5,4 @@ pub mod proto;
pub use conn::Connection;
pub use peer::*;
pub const PROTOCOL_VERSION: u32 = 13;
pub const PROTOCOL_VERSION: u32 = 14;