use std::fs;
use std::path::PathBuf;
fn config_path() -> PathBuf {
dirs::home_dir().unwrap_or_default().join(".ssh/config")
}
pub fn hostname_of(alias: &str) -> String {
let Ok(text) = fs::read_to_string(config_path()) else {
return alias.to_string();
};
let mut here = false;
for raw in text.lines() {
let line = raw.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let Some(i) = line.find(|c: char| c.is_whitespace() || c == '=') else {
continue;
};
let key = line[..i].trim_end_matches('=');
let value = line[i + 1..].trim_start_matches(['=', ' ', '\t']).trim();
if key.eq_ignore_ascii_case("host") {
here = value.split_whitespace().any(|a| a == alias);
} else if here && key.eq_ignore_ascii_case("hostname") {
return value.to_string();
}
}
alias.to_string()
}
pub fn is_same_machine(alias: &str, host: &str) -> bool {
if alias.is_empty() || host.is_empty() {
return false;
}
let target = hostname_of(alias);
alias.eq_ignore_ascii_case(host) || target.eq_ignore_ascii_case(host)
}
pub fn aliases() -> Vec<String> {
let Ok(text) = fs::read_to_string(config_path()) else {
return Vec::new();
};
let mut out: Vec<String> = Vec::new();
for raw in text.lines() {
let line = raw.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let Some(i) = line.find(|c: char| c.is_whitespace() || c == '=') else {
continue;
};
let key = line[..i].trim_end_matches('=');
if !key.eq_ignore_ascii_case("host") {
continue;
}
let value = line[i + 1..].trim_start_matches(['=', ' ', '\t']);
for alias in value.split_whitespace() {
if alias.contains(['*', '?', '!']) || out.iter().any(|a| a == alias) {
continue;
}
out.push(alias.to_string());
}
}
out
}