Expand local home paths for file copy
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s

This commit is contained in:
DuProcess
2026-07-16 23:06:43 -04:00
parent 218fe414be
commit 30952aa488
+44 -4
View File
@@ -164,21 +164,21 @@ pub fn encode_frame(payload: &[u8]) -> Result<Vec<u8>> {
pub fn parse_copy_endpoint(raw: &str) -> CopyEndpoint {
if looks_like_windows_path(raw) {
return CopyEndpoint::Local(PathBuf::from(raw));
return CopyEndpoint::Local(local_copy_path(raw));
}
if let Some((host, path)) = parse_bracketed_remote_endpoint(raw) {
return CopyEndpoint::Remote { host, path };
}
if raw.starts_with('[') {
return CopyEndpoint::Local(PathBuf::from(raw));
return CopyEndpoint::Local(local_copy_path(raw));
}
let Some(index) = raw.find(':') else {
return CopyEndpoint::Local(PathBuf::from(raw));
return CopyEndpoint::Local(local_copy_path(raw));
};
let host = &raw[..index];
let path = &raw[index + 1..];
if host.is_empty() || host.contains('/') || host.contains('\\') {
return CopyEndpoint::Local(PathBuf::from(raw));
return CopyEndpoint::Local(local_copy_path(raw));
}
CopyEndpoint::Remote {
host: host.to_string(),
@@ -266,6 +266,23 @@ fn looks_like_windows_path(raw: &str) -> bool {
bytes.len() >= 2 && bytes[0].is_ascii_alphabetic() && bytes[1] == b':'
}
fn local_copy_path(raw: &str) -> PathBuf {
let rest = if raw == "~" {
Some("")
} else {
raw.strip_prefix("~/").or_else(|| raw.strip_prefix("~\\"))
};
if let Some(rest) = rest
&& let Some(home) = dirs::home_dir()
{
if rest.is_empty() {
return home;
}
return home.join(rest);
}
PathBuf::from(raw)
}
#[cfg(test)]
mod tests {
use super::*;
@@ -346,4 +363,27 @@ mod tests {
CopyEndpoint::Local(PathBuf::from("[::1]"))
);
}
#[test]
fn copy_endpoint_expands_local_home_paths() {
let Some(home) = dirs::home_dir() else {
return;
};
assert_eq!(parse_copy_endpoint("~"), CopyEndpoint::Local(home.clone()));
assert_eq!(
parse_copy_endpoint("~/Downloads/file.txt"),
CopyEndpoint::Local(home.join("Downloads/file.txt"))
);
assert_eq!(
parse_copy_endpoint("~\\Downloads\\file.txt"),
CopyEndpoint::Local(home.join("Downloads\\file.txt"))
);
assert_eq!(
parse_copy_endpoint("host:~/Downloads/file.txt"),
CopyEndpoint::Remote {
host: "host".to_string(),
path: "~/Downloads/file.txt".to_string()
}
);
}
}