diff --git a/Cargo.lock b/Cargo.lock index 2791789c1c9717775dde263c44f18585c3727d1c..471a82d83f766b4a1b73e7c8442f05047430caea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,7 +1137,7 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09f7e37c0ed80b2a977691c47dae8625cfb21e205827106c64f7c588766b2e50" dependencies = [ - "async-lock 3.4.1", + "async-lock", "blocking", "futures-lite 2.6.0", ] @@ -1151,7 +1151,7 @@ dependencies = [ "async-channel 2.3.1", "async-executor", "async-io", - "async-lock 3.4.1", + "async-lock", "blocking", "futures-lite 2.6.0", "once_cell", @@ -1163,7 +1163,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" dependencies = [ - "async-lock 3.4.1", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", @@ -1175,15 +1175,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.1" @@ -1223,7 +1214,7 @@ checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel 2.3.1", "async-io", - "async-lock 3.4.1", + "async-lock", "async-signal", "async-task", "blocking", @@ -1252,7 +1243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ "async-io", - "async-lock 3.4.1", + "async-lock", "atomic-waker", "cfg-if", "futures-core", @@ -1273,7 +1264,7 @@ dependencies = [ "async-channel 1.9.0", "async-global-executor", "async-io", - "async-lock 3.4.1", + "async-lock", "async-process", "crossbeam-utils", "futures-channel", @@ -9045,7 +9036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -10745,7 +10736,7 @@ dependencies = [ "ashpd 0.12.0", "async-fs", "async-io", - "async-lock 3.4.1", + "async-lock", "blocking", "cbc", "cipher", @@ -14832,7 +14823,7 @@ dependencies = [ "async-executor", "async-fs", "async-io", - "async-lock 3.4.1", + "async-lock", "async-net", "async-process", "blocking", @@ -19877,7 +19868,6 @@ name = "worktree" version = "0.1.0" dependencies = [ "anyhow", - "async-lock 2.8.0", "clock", "collections", "fs", @@ -20173,7 +20163,7 @@ dependencies = [ "async-broadcast", "async-executor", "async-io", - "async-lock 3.4.1", + "async-lock", "async-process", "async-recursion", "async-task", diff --git a/Cargo.toml b/Cargo.toml index 56b8fd4026c3aa3e138ee252d72be8882e07e8c9..3e4d3d18483583dd592df38deac4ed7b4e6dfee8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -455,7 +455,6 @@ async-compat = "0.2.1" async-compression = { version = "0.4", features = ["gzip", "futures-io"] } async-dispatcher = "0.1" async-fs = "2.1" -async-lock = "2.1" async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553" } async-recursion = "1.0.0" async-tar = "0.5.0" diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index e5605d33f5c89143ccff72e836e86b89749e39c3..ede8d1c20d664ecaa5f26955de85a4dbc5313a5e 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -12509,7 +12509,6 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut TestAppContext) { ) .await; - cx.run_until_parked(); // Set up a buffer white some trailing whitespace and no trailing newline. cx.set_state( &[ diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index bb947bcb93e350990b899cc210cbab3537795a97..03cf78d74eb0e0ed8caf22c710acc131960e97c0 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -7,7 +7,6 @@ pub mod fs_watcher; use anyhow::{Context as _, Result, anyhow}; #[cfg(any(target_os = "linux", target_os = "freebsd"))] use ashpd::desktop::trash; -use futures::stream::iter; use gpui::App; use gpui::BackgroundExecutor; use gpui::Global; @@ -563,17 +562,12 @@ impl Fs for RealFs { async fn load(&self, path: &Path) -> Result { let path = path.to_path_buf(); - self.executor - .spawn(async move { Ok(std::fs::read_to_string(path)?) }) - .await + let text = smol::unblock(|| std::fs::read_to_string(path)).await?; + Ok(text) } - async fn load_bytes(&self, path: &Path) -> Result> { let path = path.to_path_buf(); - let bytes = self - .executor - .spawn(async move { std::fs::read(path) }) - .await?; + let bytes = smol::unblock(|| std::fs::read(path)).await?; Ok(bytes) } @@ -641,46 +635,30 @@ impl Fs for RealFs { if let Some(path) = path.parent() { self.create_dir(path).await?; } - let path = path.to_owned(); - let contents = content.to_owned(); - self.executor - .spawn(async move { - std::fs::write(path, contents)?; - Ok(()) - }) - .await + smol::fs::write(path, content).await?; + Ok(()) } async fn canonicalize(&self, path: &Path) -> Result { - let path = path.to_owned(); - self.executor - .spawn(async move { - std::fs::canonicalize(&path).with_context(|| format!("canonicalizing {path:?}")) - }) + Ok(smol::fs::canonicalize(path) .await + .with_context(|| format!("canonicalizing {path:?}"))?) } async fn is_file(&self, path: &Path) -> bool { - let path = path.to_owned(); - self.executor - .spawn(async move { std::fs::metadata(path).is_ok_and(|metadata| metadata.is_file()) }) + smol::fs::metadata(path) .await + .is_ok_and(|metadata| metadata.is_file()) } async fn is_dir(&self, path: &Path) -> bool { - let path = path.to_owned(); - self.executor - .spawn(async move { std::fs::metadata(path).is_ok_and(|metadata| metadata.is_dir()) }) + smol::fs::metadata(path) .await + .is_ok_and(|metadata| metadata.is_dir()) } async fn metadata(&self, path: &Path) -> Result> { - let path_buf = path.to_owned(); - let symlink_metadata = match self - .executor - .spawn(async move { std::fs::symlink_metadata(&path_buf) }) - .await - { + let symlink_metadata = match smol::fs::symlink_metadata(path).await { Ok(metadata) => metadata, Err(err) => { return match (err.kind(), err.raw_os_error()) { @@ -692,23 +670,17 @@ impl Fs for RealFs { }; let path_buf = path.to_path_buf(); - let path_exists = self - .executor - .spawn(async move { - path_buf - .try_exists() - .with_context(|| format!("checking existence for path {path_buf:?}")) - }) - .await?; + let path_exists = smol::unblock(move || { + path_buf + .try_exists() + .with_context(|| format!("checking existence for path {path_buf:?}")) + }) + .await?; let is_symlink = symlink_metadata.file_type().is_symlink(); let metadata = match (is_symlink, path_exists) { - (true, true) => { - let path_buf = path.to_path_buf(); - self.executor - .spawn(async move { std::fs::metadata(path_buf) }) - .await - .with_context(|| "accessing symlink for path {path}")? - } + (true, true) => smol::fs::metadata(path) + .await + .with_context(|| "accessing symlink for path {path}")?, _ => symlink_metadata, }; @@ -743,13 +715,7 @@ impl Fs for RealFs { &self, path: &Path, ) -> Result>>>> { - let path = path.to_owned(); - let result = iter( - self.executor - .spawn(async move { std::fs::read_dir(path) }) - .await?, - ) - .map(|entry| match entry { + let result = smol::fs::read_dir(path).await?.map(|entry| match entry { Ok(entry) => Ok(entry.path()), Err(error) => Err(anyhow!("failed to read dir entry {error:?}")), }); diff --git a/crates/worktree/Cargo.toml b/crates/worktree/Cargo.toml index 5bf60c02082ea375e87c875ed96853ff44059d3c..fdeca37b7ac73759fe9851f722985349e0a183b7 100644 --- a/crates/worktree/Cargo.toml +++ b/crates/worktree/Cargo.toml @@ -9,10 +9,6 @@ license = "GPL-3.0-or-later" path = "src/worktree.rs" doctest = false -[[bin]] -name = "bench_background_scan" -path = "bin/bench_background_scan.rs" - [lints] workspace = true @@ -28,7 +24,6 @@ test-support = [ [dependencies] anyhow.workspace = true -async-lock.workspace = true clock.workspace = true collections.workspace = true fs.workspace = true diff --git a/crates/worktree/bin/bench_background_scan.rs b/crates/worktree/bin/bench_background_scan.rs deleted file mode 100644 index 8f789fd61624448b701624f3259ed36051e6393f..0000000000000000000000000000000000000000 --- a/crates/worktree/bin/bench_background_scan.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::{ - path::Path, - sync::{Arc, atomic::AtomicUsize}, -}; - -use fs::RealFs; -use gpui::Application; -use settings::Settings; -use worktree::{Worktree, WorktreeSettings}; - -fn main() { - let Some(worktree_root_path) = std::env::args().nth(1) else { - println!( - "Missing path to worktree root\nUsage: bench_background_scan PATH_TO_WORKTREE_ROOT" - ); - return; - }; - let app = Application::headless(); - - app.run(|cx| { - settings::init(cx); - WorktreeSettings::register(cx); - let fs = Arc::new(RealFs::new(None, cx.background_executor().clone())); - - cx.spawn(async move |cx| { - let worktree = Worktree::local( - Path::new(&worktree_root_path), - true, - fs, - Arc::new(AtomicUsize::new(0)), - cx, - ) - .await - .expect("Worktree initialization to succeed"); - let did_finish_scan = worktree - .update(cx, |this, _| this.as_local().unwrap().scan_complete()) - .unwrap(); - let start = std::time::Instant::now(); - did_finish_scan.await; - println!("{:?}", start.elapsed()); - cx.update(|cx| { - cx.quit(); - }) - }) - .detach(); - }) -} diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 29b0e99492d5f23c61dd53b51f55e5990587eccd..0327c345a1ee90c51751fdc71fda668511b9fd16 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -64,7 +64,7 @@ use std::{ use sum_tree::{Bias, Dimensions, Edit, KeyedItem, SeekTarget, SumTree, Summary, TreeMap, TreeSet}; use text::{LineEnding, Rope}; use util::{ - ResultExt, debug_panic, maybe, + ResultExt, debug_panic, paths::{PathMatcher, PathStyle, SanitizedPath, home_dir}, rel_path::RelPath, }; @@ -226,7 +226,7 @@ impl Default for WorkDirectory { } } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct LocalSnapshot { snapshot: Snapshot, global_gitignore: Option>, @@ -239,7 +239,6 @@ pub struct LocalSnapshot { /// The file handle of the worktree root. `None` if the worktree is a directory. /// (so we can find it after it's been moved) root_file_handle: Option>, - executor: BackgroundExecutor, } struct BackgroundScannerState { @@ -322,6 +321,7 @@ impl DerefMut for LocalSnapshot { } } +#[derive(Debug)] enum ScanState { Started, Updated { @@ -402,7 +402,6 @@ impl Worktree { PathStyle::local(), ), root_file_handle, - executor: cx.background_executor().clone(), }; let worktree_id = snapshot.id(); @@ -1070,7 +1069,7 @@ impl LocalWorktree { scan_requests_rx, path_prefixes_to_scan_rx, next_entry_id, - state: async_lock::Mutex::new(BackgroundScannerState { + state: Mutex::new(BackgroundScannerState { prev_snapshot: snapshot.snapshot.clone(), snapshot, scanned_dirs: Default::default(), @@ -2442,7 +2441,7 @@ impl LocalSnapshot { fn insert_entry(&mut self, mut entry: Entry, fs: &dyn Fs) -> Entry { if entry.is_file() && entry.path.file_name() == Some(&GITIGNORE) { let abs_path = self.absolutize(&entry.path); - match self.executor.block(build_gitignore(&abs_path, fs)) { + match smol::block_on(build_gitignore(&abs_path, fs)) { Ok(ignore) => { self.ignores_by_parent_abs_path .insert(abs_path.parent().unwrap().into(), (Arc::new(ignore), true)); @@ -2493,12 +2492,7 @@ impl LocalSnapshot { inodes } - async fn ignore_stack_for_abs_path( - &self, - abs_path: &Path, - is_dir: bool, - fs: &dyn Fs, - ) -> IgnoreStack { + fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool, fs: &dyn Fs) -> IgnoreStack { let mut new_ignores = Vec::new(); let mut repo_root = None; for (index, ancestor) in abs_path.ancestors().enumerate() { @@ -2509,8 +2503,9 @@ impl LocalSnapshot { new_ignores.push((ancestor, None)); } } - - let metadata = fs.metadata(&ancestor.join(DOT_GIT)).await.ok().flatten(); + let metadata = smol::block_on(fs.metadata(&ancestor.join(DOT_GIT))) + .ok() + .flatten(); if metadata.is_some() { repo_root = Some(Arc::from(ancestor)); break; @@ -2656,7 +2651,7 @@ impl BackgroundScannerState { .any(|p| entry.path.starts_with(p)) } - async fn enqueue_scan_dir( + fn enqueue_scan_dir( &self, abs_path: Arc, entry: &Entry, @@ -2664,10 +2659,7 @@ impl BackgroundScannerState { fs: &dyn Fs, ) { let path = entry.path.clone(); - let ignore_stack = self - .snapshot - .ignore_stack_for_abs_path(&abs_path, true, fs) - .await; + let ignore_stack = self.snapshot.ignore_stack_for_abs_path(&abs_path, true, fs); let mut ancestor_inodes = self.snapshot.ancestor_inodes_for_path(&path); if !ancestor_inodes.contains(&entry.inode) { @@ -2705,17 +2697,11 @@ impl BackgroundScannerState { } } - async fn insert_entry( - &mut self, - mut entry: Entry, - fs: &dyn Fs, - watcher: &dyn Watcher, - ) -> Entry { + fn insert_entry(&mut self, mut entry: Entry, fs: &dyn Fs, watcher: &dyn Watcher) -> Entry { self.reuse_entry_id(&mut entry); let entry = self.snapshot.insert_entry(entry, fs); if entry.path.file_name() == Some(&DOT_GIT) { - self.insert_git_repository(entry.path.clone(), fs, watcher) - .await; + self.insert_git_repository(entry.path.clone(), fs, watcher); } #[cfg(test)] @@ -2846,7 +2832,7 @@ impl BackgroundScannerState { self.snapshot.check_invariants(false); } - async fn insert_git_repository( + fn insert_git_repository( &mut self, dot_git_path: Arc, fs: &dyn Fs, @@ -2887,11 +2873,10 @@ impl BackgroundScannerState { fs, watcher, ) - .await .log_err(); } - async fn insert_git_repository_for_path( + fn insert_git_repository_for_path( &mut self, work_directory: WorkDirectory, dot_git_abs_path: Arc, @@ -2913,7 +2898,7 @@ impl BackgroundScannerState { let work_directory_abs_path = self.snapshot.work_directory_abs_path(&work_directory); let (repository_dir_abs_path, common_dir_abs_path) = - discover_git_paths(&dot_git_abs_path, fs).await; + discover_git_paths(&dot_git_abs_path, fs); watcher .add(&common_dir_abs_path) .context("failed to add common directory to watcher") @@ -3557,7 +3542,7 @@ impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey { } struct BackgroundScanner { - state: async_lock::Mutex, + state: Mutex, fs: Arc, fs_case_sensitive: bool, status_updates_tx: UnboundedSender, @@ -3583,39 +3568,31 @@ impl BackgroundScanner { // If the worktree root does not contain a git repository, then find // the git repository in an ancestor directory. Find any gitignore files // in ancestor directories. - let root_abs_path = self.state.lock().await.snapshot.abs_path.clone(); + let root_abs_path = self.state.lock().snapshot.abs_path.clone(); let (ignores, repo) = discover_ancestor_git_repo(self.fs.clone(), &root_abs_path).await; self.state .lock() - .await .snapshot .ignores_by_parent_abs_path .extend(ignores); - let containing_git_repository = if let Some((ancestor_dot_git, work_directory)) = repo { - maybe!(async { - self.state - .lock() - .await - .insert_git_repository_for_path( - work_directory, - ancestor_dot_git.clone().into(), - self.fs.as_ref(), - self.watcher.as_ref(), - ) - .await - .log_err()?; - Some(ancestor_dot_git) - }) - .await - } else { - None - }; + let containing_git_repository = repo.and_then(|(ancestor_dot_git, work_directory)| { + self.state + .lock() + .insert_git_repository_for_path( + work_directory, + ancestor_dot_git.clone().into(), + self.fs.as_ref(), + self.watcher.as_ref(), + ) + .log_err()?; + Some(ancestor_dot_git) + }); log::trace!("containing git repository: {containing_git_repository:?}"); let mut global_gitignore_events = if let Some(global_gitignore_path) = &paths::global_gitignore_path() { - self.state.lock().await.snapshot.global_gitignore = + self.state.lock().snapshot.global_gitignore = if self.fs.is_file(&global_gitignore_path).await { build_gitignore(global_gitignore_path, self.fs.as_ref()) .await @@ -3629,34 +3606,31 @@ impl BackgroundScanner { .await .0 } else { - self.state.lock().await.snapshot.global_gitignore = None; + self.state.lock().snapshot.global_gitignore = None; Box::pin(futures::stream::empty()) }; let (scan_job_tx, scan_job_rx) = channel::unbounded(); { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.scan_id += 1; if let Some(mut root_entry) = state.snapshot.root_entry().cloned() { - let ignore_stack = state - .snapshot - .ignore_stack_for_abs_path(root_abs_path.as_path(), true, self.fs.as_ref()) - .await; + let ignore_stack = state.snapshot.ignore_stack_for_abs_path( + root_abs_path.as_path(), + true, + self.fs.as_ref(), + ); if ignore_stack.is_abs_path_ignored(root_abs_path.as_path(), true) { root_entry.is_ignored = true; - state - .insert_entry(root_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()) - .await; + state.insert_entry(root_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()); } if root_entry.is_dir() { - state - .enqueue_scan_dir( - root_abs_path.as_path().into(), - &root_entry, - &scan_job_tx, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + root_abs_path.as_path().into(), + &root_entry, + &scan_job_tx, + self.fs.as_ref(), + ); } } }; @@ -3665,11 +3639,11 @@ impl BackgroundScanner { drop(scan_job_tx); self.scan_dirs(true, scan_job_rx).await; { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.completed_scan_id = state.snapshot.scan_id; } - self.send_status_update(false, SmallVec::new()).await; + self.send_status_update(false, SmallVec::new()); // Process any any FS events that occurred while performing the initial scan. // For these events, update events cannot be as precise, because we didn't @@ -3714,7 +3688,7 @@ impl BackgroundScanner { if did_scan { let abs_path = { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.path_prefixes_to_scan.insert(request.path.clone()); state.snapshot.absolutize(&request.path) }; @@ -3723,7 +3697,7 @@ impl BackgroundScanner { self.process_events(vec![abs_path]).await; } } - self.send_status_update(false, request.done).await; + self.send_status_update(false, request.done); } paths = fs_events_rx.next().fuse() => { @@ -3752,7 +3726,7 @@ impl BackgroundScanner { request.relative_paths.sort_unstable(); self.forcibly_load_paths(&request.relative_paths).await; - let root_path = self.state.lock().await.snapshot.abs_path.clone(); + let root_path = self.state.lock().snapshot.abs_path.clone(); let root_canonical_path = self.fs.canonicalize(root_path.as_path()).await; let root_canonical_path = match &root_canonical_path { Ok(path) => SanitizedPath::new(path), @@ -3774,7 +3748,7 @@ impl BackgroundScanner { .collect::>(); { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let is_idle = state.snapshot.completed_scan_id == state.snapshot.scan_id; state.snapshot.scan_id += 1; if is_idle { @@ -3791,11 +3765,11 @@ impl BackgroundScanner { ) .await; - self.send_status_update(scanning, request.done).await + self.send_status_update(scanning, request.done) } async fn process_events(&self, mut abs_paths: Vec) { - let root_path = self.state.lock().await.snapshot.abs_path.clone(); + let root_path = self.state.lock().snapshot.abs_path.clone(); let root_canonical_path = self.fs.canonicalize(root_path.as_path()).await; let root_canonical_path = match &root_canonical_path { Ok(path) => SanitizedPath::new(path), @@ -3803,7 +3777,6 @@ impl BackgroundScanner { let new_path = self .state .lock() - .await .snapshot .root_file_handle .clone() @@ -3836,31 +3809,24 @@ impl BackgroundScanner { let mut dot_git_abs_paths = Vec::new(); abs_paths.sort_unstable(); abs_paths.dedup_by(|a, b| a.starts_with(b)); - { - let snapshot = &self.state.lock().await.snapshot; - abs_paths.retain(|abs_path| { + abs_paths.retain(|abs_path| { let abs_path = &SanitizedPath::new(abs_path); - + let snapshot = &self.state.lock().snapshot; { let mut is_git_related = false; - let dot_git_paths = self.executor.block(maybe!(async { - let mut path = None; - for ancestor in abs_path.as_path().ancestors() { - - if is_git_dir(ancestor, self.fs.as_ref()).await { + let dot_git_paths = abs_path.as_path().ancestors().find_map(|ancestor| { + if smol::block_on(is_git_dir(ancestor, self.fs.as_ref())) { let path_in_git_dir = abs_path .as_path() .strip_prefix(ancestor) .expect("stripping off the ancestor"); - path = Some((ancestor.to_owned(), path_in_git_dir.to_owned())); - break; - } + Some((ancestor.to_owned(), path_in_git_dir.to_owned())) + } else { + None } - path - - })); + }); if let Some((dot_git_abs_path, path_in_git_dir)) = dot_git_paths { if skipped_files_in_dot_git @@ -3933,12 +3899,12 @@ impl BackgroundScanner { true } }); - } + if relative_paths.is_empty() && dot_git_abs_paths.is_empty() { return; } - self.state.lock().await.snapshot.scan_id += 1; + self.state.lock().snapshot.scan_id += 1; let (scan_job_tx, scan_job_rx) = channel::unbounded(); log::debug!("received fs events {:?}", relative_paths); @@ -3952,29 +3918,29 @@ impl BackgroundScanner { .await; let affected_repo_roots = if !dot_git_abs_paths.is_empty() { - self.update_git_repositories(dot_git_abs_paths).await + self.update_git_repositories(dot_git_abs_paths) } else { Vec::new() }; { - let mut ignores_to_update = self.ignores_needing_update().await; + let mut ignores_to_update = self.ignores_needing_update(); ignores_to_update.extend(affected_repo_roots); - let ignores_to_update = self.order_ignores(ignores_to_update).await; - let snapshot = self.state.lock().await.snapshot.clone(); + let ignores_to_update = self.order_ignores(ignores_to_update); + let snapshot = self.state.lock().snapshot.clone(); self.update_ignore_statuses_for_paths(scan_job_tx, snapshot, ignores_to_update) .await; self.scan_dirs(false, scan_job_rx).await; } { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.completed_scan_id = state.snapshot.scan_id; for (_, entry) in mem::take(&mut state.removed_entries) { state.scanned_dirs.remove(&entry.id); } } - self.send_status_update(false, SmallVec::new()).await; + self.send_status_update(false, SmallVec::new()); } async fn update_global_gitignore(&self, abs_path: &Path) { @@ -3983,30 +3949,30 @@ impl BackgroundScanner { .log_err() .map(Arc::new); let (prev_snapshot, ignore_stack, abs_path) = { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.global_gitignore = ignore; let abs_path = state.snapshot.abs_path().clone(); - let ignore_stack = state - .snapshot - .ignore_stack_for_abs_path(&abs_path, true, self.fs.as_ref()) - .await; + let ignore_stack = + state + .snapshot + .ignore_stack_for_abs_path(&abs_path, true, self.fs.as_ref()); (state.snapshot.clone(), ignore_stack, abs_path) }; let (scan_job_tx, scan_job_rx) = channel::unbounded(); self.update_ignore_statuses_for_paths( scan_job_tx, prev_snapshot, - vec![(abs_path, ignore_stack)], + vec![(abs_path, ignore_stack)].into_iter(), ) .await; self.scan_dirs(false, scan_job_rx).await; - self.send_status_update(false, SmallVec::new()).await; + self.send_status_update(false, SmallVec::new()); } async fn forcibly_load_paths(&self, paths: &[Arc]) -> bool { let (scan_job_tx, scan_job_rx) = channel::unbounded(); { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let root_path = state.snapshot.abs_path.clone(); for path in paths { for ancestor in path.ancestors() { @@ -4014,14 +3980,12 @@ impl BackgroundScanner { && entry.kind == EntryKind::UnloadedDir { let abs_path = root_path.join(ancestor.as_std_path()); - state - .enqueue_scan_dir( - abs_path.into(), - entry, - &scan_job_tx, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + abs_path.into(), + entry, + &scan_job_tx, + self.fs.as_ref(), + ); state.paths_to_scan.insert(path.clone()); break; } @@ -4033,7 +3997,7 @@ impl BackgroundScanner { self.scan_dir(&job).await.log_err(); } - !mem::take(&mut self.state.lock().await.paths_to_scan).is_empty() + !mem::take(&mut self.state.lock().paths_to_scan).is_empty() } async fn scan_dirs( @@ -4081,7 +4045,7 @@ impl BackgroundScanner { ) { Ok(_) => { last_progress_update_count += 1; - self.send_status_update(true, SmallVec::new()).await; + self.send_status_update(true, SmallVec::new()); } Err(count) => { last_progress_update_count = count; @@ -4106,12 +4070,8 @@ impl BackgroundScanner { .await; } - async fn send_status_update( - &self, - scanning: bool, - barrier: SmallVec<[barrier::Sender; 1]>, - ) -> bool { - let mut state = self.state.lock().await; + fn send_status_update(&self, scanning: bool, barrier: SmallVec<[barrier::Sender; 1]>) -> bool { + let mut state = self.state.lock(); if state.changed_paths.is_empty() && scanning { return true; } @@ -4140,7 +4100,7 @@ impl BackgroundScanner { let root_abs_path; let root_char_bag; { - let snapshot = &self.state.lock().await.snapshot; + let snapshot = &self.state.lock().snapshot; if self.settings.is_path_excluded(&job.path) { log::error!("skipping excluded directory {:?}", job.path); return Ok(()); @@ -4193,14 +4153,12 @@ impl BackgroundScanner { }; if child_name == DOT_GIT { - let mut state = self.state.lock().await; - state - .insert_git_repository( - child_path.clone(), - self.fs.as_ref(), - self.watcher.as_ref(), - ) - .await; + let mut state = self.state.lock(); + state.insert_git_repository( + child_path.clone(), + self.fs.as_ref(), + self.watcher.as_ref(), + ); } else if child_name == GITIGNORE { match build_gitignore(&child_abs_path, self.fs.as_ref()).await { Ok(ignore) => { @@ -4220,7 +4178,7 @@ impl BackgroundScanner { if self.settings.is_path_excluded(&child_path) { log::debug!("skipping excluded child entry {child_path:?}"); - self.state.lock().await.remove_path(&child_path); + self.state.lock().remove_path(&child_path); continue; } @@ -4320,7 +4278,7 @@ impl BackgroundScanner { new_entries.push(child_entry); } - let mut state = self.state.lock().await; + let mut state = self.state.lock(); // Identify any subdirectories that should not be scanned. let mut job_ix = 0; @@ -4402,7 +4360,7 @@ impl BackgroundScanner { None }; - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let doing_recursive_update = scan_queue_tx.is_some(); // Remove any entries for paths that no longer exist or are being recursively @@ -4419,10 +4377,11 @@ impl BackgroundScanner { let abs_path: Arc = root_abs_path.join(path.as_std_path()).into(); match metadata { Ok(Some((metadata, canonical_path))) => { - let ignore_stack = state - .snapshot - .ignore_stack_for_abs_path(&abs_path, metadata.is_dir, self.fs.as_ref()) - .await; + let ignore_stack = state.snapshot.ignore_stack_for_abs_path( + &abs_path, + metadata.is_dir, + self.fs.as_ref(), + ); let is_external = !canonical_path.starts_with(&root_canonical_path); let mut fs_entry = Entry::new( path.clone(), @@ -4454,22 +4413,18 @@ impl BackgroundScanner { || (fs_entry.path.is_empty() && abs_path.file_name() == Some(OsStr::new(DOT_GIT))) { - state - .enqueue_scan_dir( - abs_path, - &fs_entry, - scan_queue_tx, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + abs_path, + &fs_entry, + scan_queue_tx, + self.fs.as_ref(), + ); } else { fs_entry.kind = EntryKind::UnloadedDir; } } - state - .insert_entry(fs_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()) - .await; + state.insert_entry(fs_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()); if path.is_empty() && let Some((ignores, repo)) = new_ancestor_repo.take() @@ -4484,7 +4439,6 @@ impl BackgroundScanner { self.fs.as_ref(), self.watcher.as_ref(), ) - .await .log_err(); } } @@ -4523,11 +4477,11 @@ impl BackgroundScanner { &self, scan_job_tx: Sender, prev_snapshot: LocalSnapshot, - ignores_to_update: Vec<(Arc, IgnoreStack)>, + mut ignores_to_update: impl Iterator, IgnoreStack)>, ) { let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded(); { - for (parent_abs_path, ignore_stack) in ignores_to_update { + while let Some((parent_abs_path, ignore_stack)) = ignores_to_update.next() { ignore_queue_tx .send_blocking(UpdateIgnoreStatusJob { abs_path: parent_abs_path, @@ -4568,11 +4522,11 @@ impl BackgroundScanner { .await; } - async fn ignores_needing_update(&self) -> Vec> { + fn ignores_needing_update(&self) -> Vec> { let mut ignores_to_update = Vec::new(); { - let snapshot = &mut self.state.lock().await.snapshot; + let snapshot = &mut self.state.lock().snapshot; let abs_path = snapshot.abs_path.clone(); snapshot .ignores_by_parent_abs_path @@ -4600,27 +4554,26 @@ impl BackgroundScanner { ignores_to_update } - async fn order_ignores(&self, mut ignores: Vec>) -> Vec<(Arc, IgnoreStack)> { + fn order_ignores( + &self, + mut ignores: Vec>, + ) -> impl use<> + Iterator, IgnoreStack)> { let fs = self.fs.clone(); - let snapshot = self.state.lock().await.snapshot.clone(); + let snapshot = self.state.lock().snapshot.clone(); ignores.sort_unstable(); let mut ignores_to_update = ignores.into_iter().peekable(); - - let mut result = vec![]; - while let Some(parent_abs_path) = ignores_to_update.next() { + std::iter::from_fn(move || { + let parent_abs_path = ignores_to_update.next()?; while ignores_to_update .peek() .map_or(false, |p| p.starts_with(&parent_abs_path)) { ignores_to_update.next().unwrap(); } - let ignore_stack = snapshot - .ignore_stack_for_abs_path(&parent_abs_path, true, fs.as_ref()) - .await; - result.push((parent_abs_path, ignore_stack)); - } - - result + let ignore_stack = + snapshot.ignore_stack_for_abs_path(&parent_abs_path, true, fs.as_ref()); + Some((parent_abs_path, ignore_stack)) + }) } async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &LocalSnapshot) { @@ -4652,7 +4605,7 @@ impl BackgroundScanner { return; }; - if let Ok(Some(metadata)) = self.fs.metadata(&job.abs_path.join(DOT_GIT)).await + if let Ok(Some(metadata)) = smol::block_on(self.fs.metadata(&job.abs_path.join(DOT_GIT))) && metadata.is_dir { ignore_stack.repo_root = Some(job.abs_path.clone()); @@ -4672,16 +4625,14 @@ impl BackgroundScanner { // Scan any directories that were previously ignored and weren't previously scanned. if was_ignored && !entry.is_ignored && entry.kind.is_unloaded() { - let state = self.state.lock().await; + let state = self.state.lock(); if state.should_scan_directory(&entry) { - state - .enqueue_scan_dir( - abs_path.clone(), - &entry, - &job.scan_queue, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + abs_path.clone(), + &entry, + &job.scan_queue, + self.fs.as_ref(), + ); } } @@ -4705,7 +4656,7 @@ impl BackgroundScanner { } } - let state = &mut self.state.lock().await; + let state = &mut self.state.lock(); for edit in &entries_by_path_edits { if let Edit::Insert(entry) = edit && let Err(ix) = state.changed_paths.binary_search(&entry.path) @@ -4721,9 +4672,9 @@ impl BackgroundScanner { state.snapshot.entries_by_id.edit(entries_by_id_edits, ()); } - async fn update_git_repositories(&self, dot_git_paths: Vec) -> Vec> { + fn update_git_repositories(&self, dot_git_paths: Vec) -> Vec> { log::trace!("reloading repositories: {dot_git_paths:?}"); - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let scan_id = state.snapshot.scan_id; let mut affected_repo_roots = Vec::new(); for dot_git_dir in dot_git_paths { @@ -4753,15 +4704,13 @@ impl BackgroundScanner { return Vec::new(); }; affected_repo_roots.push(dot_git_dir.parent().unwrap().into()); - state - .insert_git_repository( - RelPath::new(relative, PathStyle::local()) - .unwrap() - .into_arc(), - self.fs.as_ref(), - self.watcher.as_ref(), - ) - .await; + state.insert_git_repository( + RelPath::new(relative, PathStyle::local()) + .unwrap() + .into_arc(), + self.fs.as_ref(), + self.watcher.as_ref(), + ); } Some(local_repository) => { state.snapshot.git_repositories.update( @@ -4789,7 +4738,7 @@ impl BackgroundScanner { if exists_in_snapshot || matches!( - self.fs.metadata(&entry.common_dir_abs_path).await, + smol::block_on(self.fs.metadata(&entry.common_dir_abs_path)), Ok(Some(_)) ) { @@ -5548,13 +5497,11 @@ fn parse_gitfile(content: &str) -> anyhow::Result<&Path> { Ok(Path::new(path.trim())) } -async fn discover_git_paths(dot_git_abs_path: &Arc, fs: &dyn Fs) -> (Arc, Arc) { +fn discover_git_paths(dot_git_abs_path: &Arc, fs: &dyn Fs) -> (Arc, Arc) { let mut repository_dir_abs_path = dot_git_abs_path.clone(); let mut common_dir_abs_path = dot_git_abs_path.clone(); - if let Some(path) = fs - .load(dot_git_abs_path) - .await + if let Some(path) = smol::block_on(fs.load(dot_git_abs_path)) .ok() .as_ref() .and_then(|contents| parse_gitfile(contents).log_err()) @@ -5563,19 +5510,17 @@ async fn discover_git_paths(dot_git_abs_path: &Arc, fs: &dyn Fs) -> (Arc

>(), final_snapshot.entries(true, 0).collect::>(), - "wrong updates after snapshot {i}: {updates:#?}", + "wrong updates after snapshot {i}: {snapshot:#?} {updates:#?}", ); } }