From edf4bd34bf78f434c30b2da75abc47e3ef40ed0f Mon Sep 17 00:00:00 2001 From: DualFroz Date: Thu, 23 Jul 2026 07:25:08 +0200 Subject: [PATCH] fix: clipboard auto-detect had no macOS/Windows fallback, failed silently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit copy_auto only ever tried wl-copy/xclip, so on macOS or Windows it always returned false with no clipboard tool attempted. Added pbcopy/clip fallbacks per-OS. Also, the detail-pane 'y'/'u' handlers showed a status message only on success — a failed copy (no tool found) looked like nothing happened at all; both now report the outcome either way. --- src/detail/keys.rs | 12 ++++++++++-- src/util/clipboard.rs | 19 ++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/detail/keys.rs b/src/detail/keys.rs index 345a7ad..d9ccc5f 100644 --- a/src/detail/keys.rs +++ b/src/detail/keys.rs @@ -495,11 +495,19 @@ pub fn handle_key(code: KeyCode, st: &mut St) { KeyCode::Char('o') => { st.run_action = Some(106); } KeyCode::Char('y') => { let path = st.summary.path.to_string_lossy().to_string(); - if copy_to_clipboard(&path) { st.status_msg = Some("Path copied!".into()); } + st.status_msg = Some(if copy_to_clipboard(&path) { + "Path copied!".into() + } else { + format!("No clipboard tool found — path: {}", path) + }); } KeyCode::Char('u') => { if let Some(ref url) = st.remote_url_str.clone() { - if copy_to_clipboard(url) { st.status_msg = Some("URL copied!".into()); } + st.status_msg = Some(if copy_to_clipboard(url) { + "URL copied!".into() + } else { + format!("No clipboard tool found — URL: {}", url) + }); } } KeyCode::Char('g') => { diff --git a/src/util/clipboard.rs b/src/util/clipboard.rs index 2c0717f..616aac8 100644 --- a/src/util/clipboard.rs +++ b/src/util/clipboard.rs @@ -17,11 +17,24 @@ pub fn copy_to_clipboard(text: &str, cmd: &str) -> bool { child.wait().map(|s| s.success()).unwrap_or(false) } -/// Copy text by auto-detecting the available clipboard tool (wl-copy or xclip). +/// Copy text by auto-detecting the available clipboard tool: `wl-copy`/`xclip` +/// on Linux, `pbcopy` on macOS, `clip` on Windows. Tries every candidate for +/// the current OS in order and returns on the first one that actually +/// launches and exits successfully — callers should surface a status message +/// on `false` (nothing copied) rather than assume success, since on Linux +/// without either tool installed, or on an unexpected platform, this is a +/// real "no-op" outcome the user needs to know about. pub fn copy_auto(text: &str) -> bool { - for (cmd, args) in [("wl-copy", &[][..]), ("xclip", &["-selection", "clipboard"][..])] { + #[cfg(target_os = "macos")] + let candidates: &[(&str, &[&str])] = &[("pbcopy", &[])]; + #[cfg(target_os = "windows")] + let candidates: &[(&str, &[&str])] = &[("clip", &[])]; + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + let candidates: &[(&str, &[&str])] = &[("wl-copy", &[]), ("xclip", &["-selection", "clipboard"])]; + + for (cmd, args) in candidates { if let Ok(mut child) = std::process::Command::new(cmd) - .args(args).stdin(std::process::Stdio::piped()).spawn() { + .args(*args).stdin(std::process::Stdio::piped()).spawn() { if let Some(mut stdin) = child.stdin.take() { let _ = stdin.write_all(text.as_bytes()); } if child.wait().map(|s| s.success()).unwrap_or(false) { return true; } }