diff --git a/crates/ide-host/src/ops/fs.rs b/crates/ide-host/src/ops/fs.rs index 7c56cd3a3..0277dfc44 100644 --- a/crates/ide-host/src/ops/fs.rs +++ b/crates/ide-host/src/ops/fs.rs @@ -73,24 +73,28 @@ pub async fn copy_merge( /// Files of a deleted folder snapshotted in Local History. const DELETE_SNAPSHOT_LIMIT: usize = 2000; -pub fn read_dir(host: &Host, window: &str, path: PathBuf) -> IdeResult> { - let excludes = host - .project(window) - .map(|p| { - let globs = p.exclude_globs(); - // `read_dir` matches relative to the enclosing repository: re-anchor - // project-root patterns (`/build`) when the project is a repo subfolder. - let repo = p.root.ancestors().find(|d| d.join(".git").exists()); - match repo.and_then(|r| p.root.strip_prefix(r).ok()).filter(|rel| !rel.as_os_str().is_empty()) { - Some(rel) => { - let rel = rel.to_string_lossy().replace('\\', "/"); - globs.into_iter().map(|g| if g.starts_with('/') { format!("/{rel}{g}") } else { g }).collect() +/// Runs on the blocking pool: on a network share (`\\wsl.localhost`) every stat is slow. +pub async fn read_dir(host: &Host, window: &str, path: PathBuf) -> IdeResult> { + let project = host.project(window); + host.blocking(move || { + let excludes = project + .map(|p| { + let globs = p.exclude_globs(); + // `read_dir` matches relative to the enclosing repository: re-anchor + // project-root patterns (`/build`) when the project is a repo subfolder. + let repo = p.root.ancestors().find(|d| d.join(".git").exists()); + match repo.and_then(|r| p.root.strip_prefix(r).ok()).filter(|rel| !rel.as_os_str().is_empty()) { + Some(rel) => { + let rel = rel.to_string_lossy().replace('\\', "/"); + globs.into_iter().map(|g| if g.starts_with('/') { format!("/{rel}{g}") } else { g }).collect() + } + None => globs, } - None => globs, - } - }) - .unwrap_or_default(); - ide_vfs::read_dir(&path, &excludes) + }) + .unwrap_or_default(); + ide_vfs::read_dir(&path, &excludes) + }) + .await } /// Creates an empty file; inside a project, honours the EditorConfig diff --git a/crates/ide-host/src/rpc.rs b/crates/ide-host/src/rpc.rs index fb0cc28e9..2ab5bd7f6 100644 --- a/crates/ide-host/src/rpc.rs +++ b/crates/ide-host/src/rpc.rs @@ -178,7 +178,7 @@ impl Dispatcher { Ok(()) }) .add("cancel_task", |c| async move { Ok(ide_core::task::cancel(c.arg::("id")?)) }) - .add("fs_read_dir", |c| async move { ops::fs::read_dir(&c.host, &c.window, c.arg("path")?) }) + .add("fs_read_dir", |c| async move { ops::fs::read_dir(&c.host, &c.window, c.arg("path")?).await }) .add("fs_entry_kind", |c| async move { ops::fs::entry_kind(&c.host, c.arg("path")?).await }) .add("fs_create_file", |c| async move { ops::fs::create_file(&c.host, &c.window, c.arg("path")?) }) .add("fs_create_file_bytes", |c| async move { diff --git a/src-tauri/src/commands/fs.rs b/src-tauri/src/commands/fs.rs index efa29a9b5..2e41aebfa 100644 --- a/src-tauri/src/commands/fs.rs +++ b/src-tauri/src/commands/fs.rs @@ -39,8 +39,8 @@ pub async fn fs_copy_merge( #[tauri::command] #[specta::specta] -pub fn fs_read_dir(window: Window, state: State<'_, AppState>, path: PathBuf) -> IdeResult> { - fs::read_dir(&state.host, window.label(), path) +pub async fn fs_read_dir(window: Window, state: State<'_, AppState>, path: PathBuf) -> IdeResult> { + fs::read_dir(&state.host, window.label(), path).await } /// Creates an empty file; inside a project, honours the EditorConfig