Store diagnostic summaries on worktrees

Max Brunsfeld created

Change summary

crates/diagnostics/src/diagnostics.rs |  2 
crates/project/src/project.rs         | 40 ++++++++++++++++++++++++++--
crates/project/src/worktree.rs        | 19 +++++++++----
3 files changed, 50 insertions(+), 11 deletions(-)

Detailed changes

crates/diagnostics/src/diagnostics.rs 🔗

@@ -15,7 +15,7 @@ impl ProjectDiagnostics {
         cx: &mut ViewContext<Self>,
     ) -> Self {
         let mut buffer = cx.add_model(|cx| MultiBuffer::new(project.read(cx).replica_id(cx)));
-        for diagnostic_summary in project.read(cx).diagnostic_summaries(cx) {
+        for (project_path, diagnostic_summary) in project.read(cx).diagnostic_summaries(cx) {
             //
         }
 

crates/project/src/project.rs 🔗

@@ -8,7 +8,8 @@ use clock::ReplicaId;
 use futures::Future;
 use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
 use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
-use language::LanguageRegistry;
+use language::{DiagnosticEntry, LanguageRegistry};
+use lsp::DiagnosticSeverity;
 use std::{
     path::Path,
     sync::{atomic::AtomicBool, Arc},
@@ -39,14 +40,39 @@ pub struct ProjectPath {
     pub path: Arc<Path>,
 }
 
+#[derive(Clone)]
 pub struct DiagnosticSummary {
-    pub project_path: ProjectPath,
     pub error_count: usize,
     pub warning_count: usize,
     pub info_count: usize,
     pub hint_count: usize,
 }
 
+impl DiagnosticSummary {
+    fn new<T>(diagnostics: &[DiagnosticEntry<T>]) -> Self {
+        let mut this = Self {
+            error_count: 0,
+            warning_count: 0,
+            info_count: 0,
+            hint_count: 0,
+        };
+
+        for entry in diagnostics {
+            if entry.diagnostic.is_primary {
+                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,
+                    _ => {}
+                }
+            }
+        }
+
+        this
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct ProjectEntry {
     pub worktree_id: usize,
@@ -176,8 +202,14 @@ impl Project {
     pub fn diagnostic_summaries<'a>(
         &'a self,
         cx: &'a AppContext,
-    ) -> impl Iterator<Item = DiagnosticSummary> {
-        std::iter::empty()
+    ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
+        self.worktrees.iter().flat_map(move |worktree| {
+            let worktree_id = worktree.id();
+            worktree
+                .read(cx)
+                .diagnostic_summaries()
+                .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
+        })
     }
 
     pub fn active_entry(&self) -> Option<ProjectEntry> {

crates/project/src/worktree.rs 🔗

@@ -472,9 +472,13 @@ impl Worktree {
 
     pub fn diagnostic_summaries<'a>(
         &'a self,
-        cx: &'a AppContext,
-    ) -> impl Iterator<Item = DiagnosticSummary> {
-        std::iter::empty()
+    ) -> impl Iterator<Item = (Arc<Path>, DiagnosticSummary)> + 'a {
+        match self {
+            Worktree::Local(worktree) => &worktree.diagnostic_summaries,
+            Worktree::Remote(worktree) => &worktree.diagnostic_summaries,
+        }
+        .iter()
+        .map(|(path, summary)| (path.clone(), summary.clone()))
     }
 
     pub fn loading_buffers<'a>(&'a mut self) -> &'a mut LoadingBuffers {
@@ -879,16 +883,19 @@ impl Worktree {
                     let (remote_id, operation) = buffer.update(cx, |buffer, cx| {
                         (
                             buffer.remote_id(),
-                            buffer.update_diagnostics(params.version, diagnostics, cx),
+                            buffer.update_diagnostics(params.version, diagnostics.clone(), cx),
                         )
                     });
                     self.send_buffer_update(remote_id, operation?, cx);
-                    return Ok(());
+                    break;
                 }
             }
         }
 
-        this.diagnostics.insert(worktree_path, diagnostics);
+        let this = self.as_local_mut().unwrap();
+        this.diagnostic_summaries
+            .insert(worktree_path.clone(), DiagnosticSummary::new(&diagnostics));
+        this.diagnostics.insert(worktree_path.clone(), diagnostics);
         Ok(())
     }