sysutils: add tree utility

This commit is contained in:
2025-08-15 08:38:38 +03:00
parent c1b62aef1d
commit cb4c0bc4b0
3 changed files with 95 additions and 0 deletions
+4
View File
@@ -81,6 +81,10 @@ path = "src/echo.rs"
name = "ls"
path = "src/ls.rs"
[[bin]]
name = "tree"
path = "src/tree.rs"
[[bin]]
name = "mv"
path = "src/mv.rs"
+90
View File
@@ -0,0 +1,90 @@
use std::{
fs, io,
path::{Path, PathBuf},
process::ExitCode,
};
use clap::Parser;
fn list<P: AsRef<Path>>(path: P, depth: usize, last_mask: u64) -> io::Result<()> {
fn indent(depth: usize, mask: u64) {
for i in 0..depth + 1 {
if i < depth {
if (1 << i) & mask == 0 {
print!("");
} else {
print!(" ");
}
} else if (1 << i) & mask == 0 {
print!("├─");
} else {
print!("└─");
}
}
}
let mut entries = vec![];
let dir = fs::read_dir(path)?;
for entry in dir {
let Ok((ty, entry)) = entry.and_then(|e| Ok((e.file_type()?, e))) else {
entries.push(None);
continue;
};
let name = entry.file_name().into_string().unwrap();
if name == "." || name == ".." {
continue;
}
entries.push(Some((name, entry.path(), ty.is_dir())));
}
entries.sort_by(|a, b| {
let (Some((a, _, _)), Some((b, _, _))) = (a.as_ref(), b.as_ref()) else {
return Ord::cmp(&a.is_none(), &b.is_none());
};
Ord::cmp(a, b)
});
let len = entries.len();
for (i, entry) in entries.into_iter().enumerate() {
let last_bit = ((i == len - 1) as u64) << depth;
indent(depth, last_mask | last_bit);
let Some((name, path, dir)) = entry else {
println!("<error>");
continue;
};
println!("{name}");
if dir {
list(path, depth + 1, last_mask | last_bit).ok();
}
}
Ok(())
}
#[derive(Debug, Parser)]
struct Args {
path: Option<PathBuf>,
}
fn run<P: AsRef<Path>>(path: P) -> io::Result<()> {
list(path, 0, 0)
}
fn main() -> ExitCode {
let args = Args::parse();
let path = args.path.unwrap_or_else(|| PathBuf::from("."));
match run(&path) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("{}: {}", path.display(), error);
ExitCode::FAILURE
}
}
}
+1
View File
@@ -58,6 +58,7 @@ const PROGRAMS: &[(&str, &str)] = &[
("sysmon", "bin/sysmon"),
("top", "bin/top"),
("touch", "bin/touch"),
("tree", "bin/tree"),
("tst", "bin/tst"),
("view", "bin/view"),
// netutils