@@ -421,7 +421,8 @@ mod tests {
let workspace = app.add_model(|ctx| Workspace::new(vec![tmp_dir.path().into()], ctx));
let (window_id, workspace_view) =
app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx));
- app.finish_pending_tasks().await; // Open and populate worktree.
+ app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx))
+ .await;
app.dispatch_action(
window_id,
vec![workspace_view.id()],
@@ -444,7 +445,6 @@ mod tests {
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string());
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "n".to_string());
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "a".to_string());
- app.finish_pending_tasks().await; // Complete path search.
// let view_state = finder.state(&app);
// assert!(view_state.matches.len() > 1);
@@ -94,6 +94,19 @@ impl Workspace {
&self.worktrees
}
+ pub fn worktree_scans_complete(&self, ctx: &AppContext) -> impl Future<Output = ()> + 'static {
+ let futures = self
+ .worktrees
+ .iter()
+ .map(|worktree| worktree.read(ctx).scan_complete())
+ .collect::<Vec<_>>();
+ async move {
+ for future in futures {
+ future.await;
+ }
+ }
+ }
+
pub fn contains_paths(&self, paths: &[PathBuf], app: &AppContext) -> bool {
paths.iter().all(|path| self.contains_path(&path, app))
}
@@ -235,7 +248,8 @@ mod tests {
}));
let workspace = app.add_model(|ctx| Workspace::new(vec![dir.path().into()], ctx));
- app.finish_pending_tasks().await; // Open and populate worktree.
+ app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx))
+ .await;
// Get the first file entry.
let tree = app.read(|ctx| workspace.read(ctx).worktrees.iter().next().unwrap().clone());
@@ -6,17 +6,20 @@ use crate::{
sum_tree::{self, Edit, SumTree},
};
use anyhow::{anyhow, Result};
+use futures_core::future::BoxFuture;
pub use fuzzy::match_paths;
use fuzzy::PathEntry;
use gpui::{scoped_pool, AppContext, Entity, ModelContext, ModelHandle, Task};
use ignore::dir::{Ignore, IgnoreBuilder};
use parking_lot::Mutex;
+use postage::{oneshot, prelude::Stream, sink::Sink};
use smol::{channel::Sender, Timer};
-use std::future::Future;
use std::{
ffi::OsStr,
fmt, fs,
+ future::Future,
io::{self, Read, Write},
+ mem,
ops::{AddAssign, Deref},
os::unix::fs::MetadataExt,
path::{Path, PathBuf},
@@ -36,6 +39,7 @@ enum ScanState {
pub struct Worktree {
snapshot: Snapshot,
scanner: Arc<BackgroundScanner>,
+ scan_listeners: Mutex<Vec<postage::oneshot::Sender<()>>>,
scan_state: ScanState,
poll_scheduled: bool,
}
@@ -59,7 +63,8 @@ impl Worktree {
let tree = Self {
snapshot,
scanner,
- scan_state: ScanState::Idle,
+ scan_listeners: Default::default(),
+ scan_state: ScanState::Scanning,
poll_scheduled: false,
};
@@ -72,6 +77,18 @@ impl Worktree {
tree
}
+ pub fn scan_complete(&self) -> BoxFuture<'static, ()> {
+ if self.is_scanning() {
+ let (tx, mut rx) = oneshot::channel::<()>();
+ self.scan_listeners.lock().push(tx);
+ Box::pin(async move {
+ rx.recv().await;
+ })
+ } else {
+ Box::pin(async {})
+ }
+ }
+
fn observe_scan_state(&mut self, scan_state: ScanState, ctx: &mut ModelContext<Self>) {
self.scan_state = scan_state;
self.poll_entries(ctx);
@@ -88,6 +105,18 @@ impl Worktree {
})
.detach();
self.poll_scheduled = true;
+ } else {
+ let mut listeners = Vec::new();
+ mem::swap(self.scan_listeners.lock().as_mut(), &mut listeners);
+ ctx.spawn(
+ async move {
+ for mut tx in listeners {
+ tx.send(()).await.ok();
+ }
+ },
+ |_, _, _| {},
+ )
+ .detach();
}
}
@@ -906,9 +935,11 @@ mod tests {
unix::fs::symlink(&dir.path().join("root"), &root_link_path).unwrap();
let tree = app.add_model(|ctx| Worktree::new(root_link_path, ctx));
- assert_condition(1, 300, || app.read(|ctx| tree.read(ctx).file_count() == 4)).await;
+
+ app.read(|ctx| tree.read(ctx).scan_complete()).await;
app.read(|ctx| {
let tree = tree.read(ctx);
+ assert_eq!(tree.file_count(), 4);
let results = match_paths(
Some(tree.snapshot()).iter(),
"bna",