ZIm/crates/recent_projects/src/ssh_config.rs
Kirill Bulatov 83afe56a61
Add a way to import ssh host names from the ssh config (#30926)
Closes https://github.com/zed-industries/zed/issues/20016

Use `"read_ssh_config": false` to disable the new behavior.

Release Notes:

- Added a way to import ssh host names from the ssh config

---------

Co-authored-by: Cole Miller <m@cole-miller.net>
2025-05-18 20:34:47 +00:00

96 lines
2.5 KiB
Rust

use std::collections::BTreeSet;
pub fn parse_ssh_config_hosts(config: &str) -> BTreeSet<String> {
let mut hosts = BTreeSet::new();
let mut needs_another_line = false;
for line in config.lines() {
let line = line.trim_start();
if let Some(line) = line.strip_prefix("Host") {
match line.chars().next() {
Some('\\') => {
needs_another_line = true;
}
Some('\n' | '\r') => {
needs_another_line = false;
}
Some(c) if c.is_whitespace() => {
parse_hosts_from(line, &mut hosts);
}
Some(_) | None => {
needs_another_line = false;
}
};
if needs_another_line {
parse_hosts_from(line, &mut hosts);
needs_another_line = line.trim_end().ends_with('\\');
} else {
needs_another_line = false;
}
} else if needs_another_line {
needs_another_line = line.trim_end().ends_with('\\');
parse_hosts_from(line, &mut hosts);
} else {
needs_another_line = false;
}
}
hosts
}
fn parse_hosts_from(line: &str, hosts: &mut BTreeSet<String>) {
hosts.extend(
line.split_whitespace()
.filter(|field| !field.starts_with("!"))
.filter(|field| !field.contains("*"))
.filter(|field| !field.is_empty())
.map(|field| field.to_owned()),
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_thank_you_bjorn3() {
let hosts = "
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
Host whatever.*
User another
Host !not_this
User not_me
Host something
HostName whatever.tld
Host linux bsd host3
User bjorn
Host rpi
user rpi
hostname rpi.local
Host \
somehost \
anotherhost
Hostname 192.168.3.3";
let expected_hosts = BTreeSet::from_iter([
"something".to_owned(),
"linux".to_owned(),
"host3".to_owned(),
"bsd".to_owned(),
"rpi".to_owned(),
"somehost".to_owned(),
"anotherhost".to_owned(),
]);
assert_eq!(expected_hosts, parse_ssh_config_hosts(hosts));
}
}