///|
fn path_separator() -> String {
if @platform.is_windows() {
";"
} else {
":"
}
}
///|
fn has_separator(name : String) -> Bool {
name.contains("/") || name.contains("\\")
}
///|
async fn regular(path : String) -> Bool {
(@fs.kind(path) catch { _ => Unknown }) == Regular
}
///|
async fn candidates(name : String) -> Array[String] {
if has_separator(name) {
return if regular(name) { [name] } else { [] }
}
let path = @env.get_env_var("PATH").unwrap_or("")
let result : Array[String] = []
for directory in path.split(path_separator()) {
let root = directory.to_owned()
let base = if root == "" { "." } else { root }
let candidate = @path.Path(base).join(Path(name)).to_string()
if regular(candidate) {
result.push(candidate)
}
}
result
}
///|
async fn main {
let parsed = @cli.parse(@env.args()[1:], [
@cli.flag("all", short='a'),
@cli.flag("silent", short='s'),
@cli.flag("help"),
@cli.flag("version"),
]) catch {
@cli.CliError(option~, message~, ..) => {
@stdio.stderr.write("which: \{message}: '\{option}'\n")
@sys.exit(2)
return
}
}
if parsed.contains("help") {
@stdio.stdout.write(
"Usage: which [-as] NAME...\nResolve command names against PATH using regular-file presence.\n",
)
return
}
if parsed.contains("version") {
@stdio.stdout.write("which (cli) \{command_version}\n")
return
}
if parsed.operands.is_empty() {
@stdio.stderr.write("which: missing command name\n")
@sys.exit(2)
return
}
let mut missing = false
for name in parsed.operands {
let matches = candidates(name)
if matches.is_empty() {
missing = true
if !parsed.contains("silent") {
@stdio.stderr.write("\{name} not found\n")
}
continue
}
if !parsed.contains("silent") {
if parsed.contains("all") {
for match_path in matches {
@stdio.stdout.write(match_path + "\n")
}
} else {
@stdio.stdout.write(matches[0] + "\n")
}
}
}
if missing {
@sys.exit(1)
}
}