Display a "Checking..." message when running disk-based diagnostics

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-01-07 15:03:19 +01:00
parent e39be35e17
commit cf62d26ed8
6 changed files with 195 additions and 55 deletions

View file

@ -33,6 +33,7 @@ pub struct Project {
client_state: ProjectClientState,
collaborators: HashMap<PeerId, Collaborator>,
subscriptions: Vec<client::Subscription>,
pending_disk_based_diagnostics: isize,
}
enum ProjectClientState {
@ -60,7 +61,9 @@ pub struct Collaborator {
pub enum Event {
ActiveEntryChanged(Option<ProjectEntry>),
WorktreeRemoved(WorktreeId),
DiskBasedDiagnosticsStarted,
DiskBasedDiagnosticsUpdated { worktree_id: WorktreeId },
DiskBasedDiagnosticsFinished,
DiagnosticsUpdated(ProjectPath),
}
@ -187,6 +190,7 @@ impl Project {
client,
user_store,
fs,
pending_disk_based_diagnostics: 0,
}
})
}
@ -259,6 +263,11 @@ impl Project {
cx,
Self::handle_update_diagnostic_summary,
),
client.subscribe_to_entity(
remote_id,
cx,
Self::handle_disk_based_diagnostics_updating,
),
client.subscribe_to_entity(
remote_id,
cx,
@ -273,6 +282,7 @@ impl Project {
remote_id,
replica_id,
},
pending_disk_based_diagnostics: 0,
};
for worktree in worktrees {
this.add_worktree(worktree, cx);
@ -506,17 +516,29 @@ impl Project {
fn add_worktree(&mut self, worktree: ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
cx.subscribe(&worktree, |_, worktree, event, cx| match event {
cx.subscribe(&worktree, move |this, worktree, event, cx| match event {
worktree::Event::DiagnosticsUpdated(path) => {
cx.emit(Event::DiagnosticsUpdated(ProjectPath {
worktree_id: worktree.read(cx).id(),
path: path.clone(),
}));
}
worktree::Event::DiskBasedDiagnosticsUpdating => {
if this.pending_disk_based_diagnostics == 0 {
cx.emit(Event::DiskBasedDiagnosticsStarted);
}
this.pending_disk_based_diagnostics += 1;
}
worktree::Event::DiskBasedDiagnosticsUpdated => {
this.pending_disk_based_diagnostics -= 1;
cx.emit(Event::DiskBasedDiagnosticsUpdated {
worktree_id: worktree.read(cx).id(),
});
if this.pending_disk_based_diagnostics == 0 {
if this.pending_disk_based_diagnostics == 0 {
cx.emit(Event::DiskBasedDiagnosticsFinished);
}
}
}
})
.detach();
@ -539,6 +561,10 @@ impl Project {
}
}
pub fn is_running_disk_based_diagnostics(&self) -> bool {
self.pending_disk_based_diagnostics > 0
}
pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
let mut summary = DiagnosticSummary::default();
for (_, path_summary) in self.diagnostic_summaries(cx) {
@ -716,6 +742,24 @@ impl Project {
Ok(())
}
fn handle_disk_based_diagnostics_updating(
&mut self,
envelope: TypedEnvelope<proto::DiskBasedDiagnosticsUpdating>,
_: Arc<Client>,
cx: &mut ModelContext<Self>,
) -> Result<()> {
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
if let Some(worktree) = self.worktree_for_id(worktree_id, cx) {
worktree.update(cx, |worktree, cx| {
worktree
.as_remote()
.unwrap()
.disk_based_diagnostics_updating(cx);
});
}
Ok(())
}
fn handle_disk_based_diagnostics_updated(
&mut self,
envelope: TypedEnvelope<proto::DiskBasedDiagnosticsUpdated>,

View file

@ -67,6 +67,7 @@ pub enum Worktree {
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Event {
DiskBasedDiagnosticsUpdating,
DiskBasedDiagnosticsUpdated,
DiagnosticsUpdated(Arc<Path>),
}
@ -1133,6 +1134,11 @@ impl LocalWorktree {
.log_err()
.flatten()
{
enum DiagnosticProgress {
Updating,
Updated,
}
let disk_based_sources = language
.disk_based_diagnostic_sources()
.cloned()
@ -1155,10 +1161,21 @@ impl LocalWorktree {
while let Ok(diagnostics) = diagnostics_rx.recv().await {
if let Some(handle) = cx.read(|cx| this.upgrade(cx)) {
handle.update(&mut cx, |this, cx| {
if !has_disk_based_diagnostic_progress_token {
smol::block_on(
disk_based_diagnostics_done_tx
.send(DiagnosticProgress::Updating),
)
.ok();
}
this.update_diagnostics(diagnostics, &disk_based_sources, cx)
.log_err();
if !has_disk_based_diagnostic_progress_token {
smol::block_on(disk_based_diagnostics_done_tx.send(())).ok();
smol::block_on(
disk_based_diagnostics_done_tx
.send(DiagnosticProgress::Updated),
)
.ok();
}
})
} else {
@ -1181,13 +1198,23 @@ impl LocalWorktree {
match params.value {
lsp::ProgressParamsValue::WorkDone(progress) => match progress {
lsp::WorkDoneProgress::Begin(_) => {
if pending_disk_based_diagnostics == 0 {
smol::block_on(
disk_based_diagnostics_done_tx
.send(DiagnosticProgress::Updating),
)
.ok();
}
pending_disk_based_diagnostics += 1;
}
lsp::WorkDoneProgress::End(_) => {
pending_disk_based_diagnostics -= 1;
if pending_disk_based_diagnostics == 0 {
smol::block_on(disk_based_diagnostics_done_tx.send(()))
.ok();
smol::block_on(
disk_based_diagnostics_done_tx
.send(DiagnosticProgress::Updated),
)
.ok();
}
}
_ => {}
@ -1198,21 +1225,41 @@ impl LocalWorktree {
.detach();
let rpc = self.client.clone();
cx.spawn_weak(|this, mut cx| async move {
while let Ok(()) = disk_based_diagnostics_done_rx.recv().await {
while let Ok(progress) = disk_based_diagnostics_done_rx.recv().await {
if let Some(handle) = cx.read(|cx| this.upgrade(cx)) {
let message = handle.update(&mut cx, |this, cx| {
cx.emit(Event::DiskBasedDiagnosticsUpdated);
let this = this.as_local().unwrap();
this.share
.as_ref()
.map(|share| proto::DiskBasedDiagnosticsUpdated {
project_id: share.project_id,
worktree_id: this.id().to_proto(),
})
});
match progress {
DiagnosticProgress::Updating => {
let message = handle.update(&mut cx, |this, cx| {
cx.emit(Event::DiskBasedDiagnosticsUpdating);
let this = this.as_local().unwrap();
this.share.as_ref().map(|share| {
proto::DiskBasedDiagnosticsUpdating {
project_id: share.project_id,
worktree_id: this.id().to_proto(),
}
})
});
if let Some(message) = message {
rpc.send(message).await.log_err();
if let Some(message) = message {
rpc.send(message).await.log_err();
}
}
DiagnosticProgress::Updated => {
let message = handle.update(&mut cx, |this, cx| {
cx.emit(Event::DiskBasedDiagnosticsUpdated);
let this = this.as_local().unwrap();
this.share.as_ref().map(|share| {
proto::DiskBasedDiagnosticsUpdated {
project_id: share.project_id,
worktree_id: this.id().to_proto(),
}
})
});
if let Some(message) = message {
rpc.send(message).await.log_err();
}
}
}
} else {
break;
@ -1691,6 +1738,10 @@ impl RemoteWorktree {
}
}
pub fn disk_based_diagnostics_updating(&self, cx: &mut ModelContext<Worktree>) {
cx.emit(Event::DiskBasedDiagnosticsUpdating);
}
pub fn disk_based_diagnostics_updated(&self, cx: &mut ModelContext<Worktree>) {
cx.emit(Event::DiskBasedDiagnosticsUpdated);
}
@ -3848,6 +3899,11 @@ mod tests {
let mut events = subscribe(&tree, &mut cx);
fake_server.start_progress(&progress_token).await;
assert_eq!(
events.next().await.unwrap(),
Event::DiskBasedDiagnosticsUpdating
);
fake_server.start_progress(&progress_token).await;
fake_server.end_progress(&progress_token).await;
fake_server.start_progress(&progress_token).await;
@ -3864,18 +3920,17 @@ mod tests {
}],
})
.await;
let event = events.next().await.unwrap();
assert_eq!(
event,
events.next().await.unwrap(),
Event::DiagnosticsUpdated(Arc::from(Path::new("a.rs")))
);
fake_server.end_progress(&progress_token).await;
fake_server.end_progress(&progress_token).await;
let event = events.next().await.unwrap();
assert_eq!(event, Event::DiskBasedDiagnosticsUpdated);
assert_eq!(
events.next().await.unwrap(),
Event::DiskBasedDiagnosticsUpdated
);
let buffer = tree
.update(&mut cx, |tree, cx| tree.open_buffer("a.rs", cx))