Skip to main content

Mountain/IPC/WindServiceHandlers/FileSystem/Native/
FileReaddirNative.rs

1//! Wire method `file:readdir`. Returns `[[name, fileType]]` matching
2//! VS Code's `ReadDirResult` (`FileType`: File=1, Directory=2,
3//! SymbolicLink=64 - combined via bitflags upstream, but the readdir
4//! callers only care about the per-entry value).
5
6use serde_json::{Value, json};
7
8use crate::{IPC::WindServiceHandlers::Utilities::PathExtraction::Fn as extract_path_from_arg, dev_log};
9
10pub async fn Fn(Arguments:Vec<Value>) -> Result<Value, String> {
11	let Path = extract_path_from_arg(Arguments.get(0).ok_or("Missing directory path")?)?;
12
13	// Emit at the default-visible `vfs` level instead of
14	// `vfs-verbose`: readdir fires at most once per folder expand
15	// (unlike stat which fires per probe), and it is the primary
16	// observable for "is the Explorer view calling through to
17	// Mountain?" diagnostics. The handler itself stays cheap.
18	dev_log!("vfs", "readdir: {}", Path);
19
20	let mut Entries = tokio::fs::read_dir(&Path).await.map_err(|E| {
21		if E.kind() == std::io::ErrorKind::NotFound {
22			format!("readdir: {} resource not found ({})", Path, E)
23		} else {
24			format!("Failed to readdir: {} ({})", Path, E)
25		}
26	})?;
27
28	let mut Result = Vec::new();
29
30	while let Some(Entry) = Entries.next_entry().await.map_err(|E| E.to_string())? {
31		let Name = Entry.file_name().to_string_lossy().to_string();
32
33		let FileType = Entry.file_type().await.map_err(|E| E.to_string())?;
34
35		let TypeValue = if FileType.is_symlink() {
36			64
37		} else if FileType.is_dir() {
38			2
39		} else {
40			1
41		};
42
43		Result.push(json!([Name, TypeValue]));
44	}
45
46	Ok(json!(Result))
47}