Fix tracking of in-progress disk-based diagnostics on indicator

Antonio Scandurra and Max Brunsfeld created

Co-Authored-By: Max Brunsfeld <max@zed.dev>

Change summary

crates/diagnostics/src/diagnostics.rs |  4 
crates/diagnostics/src/items.rs       | 21 ++++---
crates/project/src/project.rs         | 75 +++++++++++++++++-----------
3 files changed, 58 insertions(+), 42 deletions(-)

Detailed changes

crates/diagnostics/src/diagnostics.rs 🔗

@@ -1003,7 +1003,7 @@ mod tests {
 
         // Diagnostics are added for another earlier path.
         project.update(cx, |project, cx| {
-            project.disk_based_diagnostics_started(cx);
+            project.disk_based_diagnostics_started(0, cx);
             project
                 .update_diagnostic_entries(
                     0,
@@ -1103,7 +1103,7 @@ mod tests {
 
         // Diagnostics are added to the first path
         project.update(cx, |project, cx| {
-            project.disk_based_diagnostics_started(cx);
+            project.disk_based_diagnostics_started(0, cx);
             project
                 .update_diagnostic_entries(
                     0,

crates/diagnostics/src/items.rs 🔗

@@ -1,3 +1,4 @@
+use collections::HashSet;
 use editor::{Editor, GoToNextDiagnostic};
 use gpui::{
     elements::*, platform::CursorStyle, serde_json, Entity, ModelHandle, MutableAppContext,
@@ -12,7 +13,7 @@ pub struct DiagnosticIndicator {
     summary: project::DiagnosticSummary,
     active_editor: Option<WeakViewHandle<Editor>>,
     current_diagnostic: Option<Diagnostic>,
-    check_in_progress: bool,
+    in_progress_checks: HashSet<usize>,
     _observe_active_editor: Option<Subscription>,
 }
 
@@ -23,16 +24,13 @@ pub fn init(cx: &mut MutableAppContext) {
 impl DiagnosticIndicator {
     pub fn new(project: &ModelHandle<Project>, cx: &mut ViewContext<Self>) -> Self {
         cx.subscribe(project, |this, project, event, cx| match event {
-            project::Event::DiskBasedDiagnosticsUpdated => {
+            project::Event::DiskBasedDiagnosticsStarted { language_server_id } => {
+                this.in_progress_checks.insert(*language_server_id);
                 cx.notify();
             }
-            project::Event::DiskBasedDiagnosticsStarted => {
-                this.check_in_progress = true;
-                cx.notify();
-            }
-            project::Event::DiskBasedDiagnosticsFinished { .. } => {
+            project::Event::DiskBasedDiagnosticsFinished { language_server_id } => {
                 this.summary = project.read(cx).diagnostic_summary(cx);
-                this.check_in_progress = false;
+                this.in_progress_checks.remove(language_server_id);
                 cx.notify();
             }
             _ => {}
@@ -40,7 +38,10 @@ impl DiagnosticIndicator {
         .detach();
         Self {
             summary: project.read(cx).diagnostic_summary(cx),
-            check_in_progress: project.read(cx).is_running_disk_based_diagnostics(),
+            in_progress_checks: project
+                .read(cx)
+                .language_servers_running_disk_based_diagnostics()
+                .collect(),
             active_editor: None,
             current_diagnostic: None,
             _observe_active_editor: None,
@@ -85,7 +86,7 @@ impl View for DiagnosticIndicator {
         enum Summary {}
         enum Message {}
 
-        let in_progress = self.check_in_progress;
+        let in_progress = !self.in_progress_checks.is_empty();
         let mut element = Flex::row().with_child(
             MouseEventHandler::new::<Summary, _, _>(0, cx, |state, cx| {
                 let style = &cx

crates/project/src/project.rs 🔗

@@ -154,8 +154,9 @@ pub enum Event {
     ActiveEntryChanged(Option<ProjectEntryId>),
     WorktreeAdded,
     WorktreeRemoved(WorktreeId),
-    DiskBasedDiagnosticsStarted,
-    DiskBasedDiagnosticsUpdated,
+    DiskBasedDiagnosticsStarted {
+        language_server_id: usize,
+    },
     DiskBasedDiagnosticsFinished {
         language_server_id: usize,
     },
@@ -2126,7 +2127,7 @@ impl Project {
                 if Some(token.as_str()) == disk_based_diagnostics_progress_token {
                     language_server_status.pending_diagnostic_updates += 1;
                     if language_server_status.pending_diagnostic_updates == 1 {
-                        self.disk_based_diagnostics_started(cx);
+                        self.disk_based_diagnostics_started(server_id, cx);
                         self.broadcast_language_server_update(
                             server_id,
                             proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
@@ -3997,10 +3998,18 @@ impl Project {
         }
     }
 
-    pub fn is_running_disk_based_diagnostics(&self) -> bool {
+    pub fn language_servers_running_disk_based_diagnostics<'a>(
+        &'a self,
+    ) -> impl 'a + Iterator<Item = usize> {
         self.language_server_statuses
-            .values()
-            .any(|status| status.pending_diagnostic_updates > 0)
+            .iter()
+            .filter_map(|(id, status)| {
+                if status.pending_diagnostic_updates > 0 {
+                    Some(*id)
+                } else {
+                    None
+                }
+            })
     }
 
     pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
@@ -4025,16 +4034,12 @@ impl Project {
         })
     }
 
-    pub fn disk_based_diagnostics_started(&mut self, cx: &mut ModelContext<Self>) {
-        if self
-            .language_server_statuses
-            .values()
-            .map(|status| status.pending_diagnostic_updates)
-            .sum::<isize>()
-            == 1
-        {
-            cx.emit(Event::DiskBasedDiagnosticsStarted);
-        }
+    pub fn disk_based_diagnostics_started(
+        &mut self,
+        language_server_id: usize,
+        cx: &mut ModelContext<Self>,
+    ) {
+        cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id });
     }
 
     pub fn disk_based_diagnostics_finished(
@@ -4042,7 +4047,6 @@ impl Project {
         language_server_id: usize,
         cx: &mut ModelContext<Self>,
     ) {
-        cx.emit(Event::DiskBasedDiagnosticsUpdated);
         cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id });
     }
 
@@ -4446,7 +4450,7 @@ impl Project {
             }
             proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
                 this.update(&mut cx, |this, cx| {
-                    this.disk_based_diagnostics_started(cx);
+                    this.disk_based_diagnostics_started(language_server_id, cx);
                 })
             }
             proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
@@ -6208,7 +6212,9 @@ mod tests {
         fake_server.start_progress(progress_token).await;
         assert_eq!(
             events.next().await.unwrap(),
-            Event::DiskBasedDiagnosticsStarted
+            Event::DiskBasedDiagnosticsStarted {
+                language_server_id: 0,
+            }
         );
 
         fake_server.start_progress(progress_token).await;
@@ -6237,10 +6243,6 @@ mod tests {
 
         fake_server.end_progress(progress_token).await;
         fake_server.end_progress(progress_token).await;
-        assert_eq!(
-            events.next().await.unwrap(),
-            Event::DiskBasedDiagnosticsUpdated
-        );
         assert_eq!(
             events.next().await.unwrap(),
             Event::DiskBasedDiagnosticsFinished {
@@ -6344,22 +6346,35 @@ mod tests {
         fake_server.start_progress(progress_token).await;
         assert_eq!(
             events.next().await.unwrap(),
-            Event::DiskBasedDiagnosticsStarted
+            Event::DiskBasedDiagnosticsStarted {
+                language_server_id: 1
+            }
         );
+        project.read_with(cx, |project, _| {
+            assert_eq!(
+                project
+                    .language_servers_running_disk_based_diagnostics()
+                    .collect::<Vec<_>>(),
+                [1]
+            );
+        });
 
         // All diagnostics are considered done, despite the old server's diagnostic
         // task never completing.
         fake_server.end_progress(progress_token).await;
         assert_eq!(
             events.next().await.unwrap(),
-            Event::DiskBasedDiagnosticsUpdated
+            Event::DiskBasedDiagnosticsFinished {
+                language_server_id: 1
+            }
         );
-        assert!(matches!(
-            events.next().await.unwrap(),
-            Event::DiskBasedDiagnosticsFinished { .. }
-        ));
         project.read_with(cx, |project, _| {
-            assert!(!project.is_running_disk_based_diagnostics());
+            assert_eq!(
+                project
+                    .language_servers_running_disk_based_diagnostics()
+                    .collect::<Vec<_>>(),
+                [0; 0]
+            );
         });
     }