use crate::rules::Dialect;
pub fn zsh() -> Result<(), &'static str> {
let shell = std::env::var("SHELL").unwrap_or_default();
let name = shell.rsplit(['/', '\\']).next().unwrap_or("");
match name {
"zsh" => Ok(()),
"bash" | "sh" | "dash" | "ksh" | "mksh" | "ash" => {
Err("the tool's shell is bash, which passes an unmatched glob through as text")
}
"fish" | "" => {
if cfg!(target_os = "macos") {
Ok(())
} else {
Err("the tool's shell is not known to be zsh")
}
}
_ => Err("the tool's shell is not known to be zsh"),
}
}
pub fn dialect() -> Dialect {
dialect_of(
&std::env::var("SHELL").unwrap_or_default(),
cfg!(target_os = "macos"),
)
}
pub fn dialect_of(shell: &str, macos: bool) -> Dialect {
match shell.rsplit(['/', '\\']).next().unwrap_or("") {
"zsh" => Dialect::Zsh,
"bash" => Dialect::Bash,
"fish" | "" if macos => Dialect::Zsh,
_ => Dialect::Unknown,
}
}
pub fn has_glob(text: &str) -> bool {
if text.contains('*') || text.contains('?') {
return true;
}
matches!((text.find('['), text.rfind(']')), (Some(open), Some(close)) if open < close)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_shell_path_names_its_dialect() {
assert_eq!(dialect_of("/bin/zsh", false), Dialect::Zsh);
assert_eq!(dialect_of("/usr/local/bin/bash", false), Dialect::Bash);
assert_eq!(dialect_of("C:\\\\Git\\\\bin\\\\bash", false), Dialect::Bash);
}
#[test]
fn fish_and_empty_are_zsh_on_macos_only() {
assert_eq!(dialect_of("/usr/local/bin/fish", true), Dialect::Zsh);
assert_eq!(dialect_of("", true), Dialect::Zsh);
assert_eq!(dialect_of("/usr/local/bin/fish", false), Dialect::Unknown);
assert_eq!(dialect_of("", false), Dialect::Unknown);
}
#[test]
fn other_shells_are_unknown() {
for sh in ["/bin/sh", "/bin/dash", "/bin/ksh", "/bin/mksh", "/bin/ash"] {
assert_eq!(dialect_of(sh, false), Dialect::Unknown, "{sh}");
}
}
}