use std::io::{self, Write};
use std::path::PathBuf;
use crate::index::Index;
use crate::path_util::path_bytes;
use crate::Config;
use super::{
explicit_path_specs, matches_any_explicit_path, matches_optional_glob, path_depth,
CompiledGlobs,
};
pub(crate) fn cmd_files(config: Config, cli: &crate::cli::args::Cli) -> i32 {
let globs = cli.combined_globs();
if let Err((spec, msg)) = super::validate_globs(&globs) {
eprintln!("st: invalid glob '{spec}': {msg}");
return 2;
}
let compiled_globs = CompiledGlobs::build(&globs);
let index = match Index::open(config.clone()) {
Ok(idx) => idx,
Err(e) => {
eprintln!("st: {e}");
return 2;
}
};
let needs_async_catchup =
crate::cli::catchup::run_bounded_auto_update(&index, &config, cli.quiet);
let snapshot = index.snapshot();
let stdout = io::stdout();
let mut out = stdout.lock();
let sep = if cli.null { b'\0' } else { b'\n' };
let mut path_args: Vec<PathBuf> = Vec::new();
if let Some(pat) = &cli.pattern {
path_args.push(PathBuf::from(pat));
}
path_args.extend(cli.paths.iter().cloned());
let specs = explicit_path_specs(config.repo_root.as_path(), &path_args);
let mut paths: Vec<_> = snapshot
.path_index
.visible_paths()
.filter(|(_, path)| {
matches_any_explicit_path(path, &specs)
&& matches_optional_glob(path, &cli.file_type, &cli.type_not, &compiled_globs)
})
.map(|(_, path)| path.to_path_buf())
.collect();
if let Some(depth) = cli.max_depth {
if specs.is_empty() {
paths.retain(|p| path_depth(p) <= depth);
} else {
paths.retain(|p| {
let spec_depth = specs
.iter()
.filter(|spec| {
spec.rel_path.as_os_str().is_empty() || p.starts_with(&spec.rel_path)
})
.map(|spec| spec.rel_path.components().count())
.max()
.unwrap_or(0);
path_depth(p).saturating_sub(spec_depth) <= depth
});
}
}
paths.sort_unstable();
let mut exit_code = 0;
for path in &paths {
let result = out
.write_all(path_bytes(path).as_ref())
.and_then(|_| out.write_all(&[sep]));
if let Err(err) = result {
if err.kind() != io::ErrorKind::BrokenPipe {
eprintln!("st: {err}");
exit_code = 2;
}
break;
}
}
if needs_async_catchup {
crate::cli::catchup::maybe_spawn_async_catchup(&config);
}
exit_code
}