Compare commits

...

1 Commits

Author SHA1 Message Date
zhao-oai
7ffd1d00be Fix macOS image drag-and-drop detection 2025-10-26 15:44:36 -07:00

View File

@@ -185,14 +185,79 @@ pub fn normalize_pasted_path(pasted: &str) -> Option<PathBuf> {
}
// shell-escaped single path → unescaped
let parts: Vec<String> = shlex::Shlex::new(pasted).collect();
if parts.len() == 1 {
return parts.into_iter().next().map(PathBuf::from);
let mut shlex = shlex::Shlex::new(pasted);
let parts: Vec<String> = shlex.by_ref().collect();
match parts.len() {
0 => {}
1 => return parts.into_iter().next().map(PathBuf::from),
_ => {}
}
if is_probably_posix_shell_escaped_path(pasted) {
let unescaped = unescape_posix_backslashes(pasted);
return Some(PathBuf::from(unescaped));
}
None
}
fn is_probably_posix_shell_escaped_path(pasted: &str) -> bool {
pasted.contains('/')
&& pasted.contains('\\')
&& !pasted.contains('"')
&& !pasted.contains('\'')
&& !has_unescaped_ascii_whitespace(pasted)
}
fn has_unescaped_ascii_whitespace(pasted: &str) -> bool {
let mut escaped = false;
let mut in_single_quote = false;
let mut in_double_quote = false;
for ch in pasted.chars() {
if escaped {
escaped = false;
continue;
}
match ch {
'\\' if !in_single_quote => {
escaped = true;
}
'\'' if !in_double_quote => {
in_single_quote = !in_single_quote;
}
'"' if !in_single_quote => {
in_double_quote = !in_double_quote;
}
' ' | '\t' if !in_single_quote && !in_double_quote => {
return true;
}
_ => {}
}
}
false
}
fn unescape_posix_backslashes(pasted: &str) -> String {
let mut out = String::with_capacity(pasted.len());
let mut escaped = false;
for ch in pasted.chars() {
if escaped {
out.push(ch);
escaped = false;
continue;
}
if ch == '\\' {
escaped = true;
continue;
}
out.push(ch);
}
if escaped {
out.push('\\');
}
out
}
/// Infer an image format for the provided path based on its extension.
pub fn pasted_image_format(path: &Path) -> EncodedImageFormat {
match path
@@ -255,6 +320,34 @@ mod pasted_paths_tests {
assert!(result.is_none());
}
#[cfg(not(windows))]
#[test]
fn normalize_dragged_macos_screenshot_path() {
let input = "/Users/zhao/Downloads/Screenshot\\ 2025-09-25\\ at\\ 10.47.39\u{202F}AM.png ";
let result = normalize_pasted_path(input).expect("should parse Finder screenshot path");
assert_eq!(
result,
PathBuf::from("/Users/zhao/Downloads/Screenshot 2025-09-25 at 10.47.39\u{202F}AM.png")
);
}
#[cfg(not(windows))]
#[test]
fn normalize_dragged_macos_temporary_screenshot_path() {
let input = concat!(
"/var/folders/mr/tt5wpmvs1w5b0td1bj93t0800000gp/T/TemporaryItems/",
"NSIRD_screencaptureui_SBcoDE/Screenshot\\ 2025-10-26\\ at\\ 2.10.40\u{202F}PM.png "
);
let result = normalize_pasted_path(input).expect("should parse temporary screenshot path");
assert_eq!(
result,
PathBuf::from(concat!(
"/var/folders/mr/tt5wpmvs1w5b0td1bj93t0800000gp/T/TemporaryItems/",
"NSIRD_screencaptureui_SBcoDE/Screenshot 2025-10-26 at 2.10.40\u{202F}PM.png"
))
);
}
#[test]
fn pasted_image_format_png_jpeg_unknown() {
assert_eq!(