diff options
| author | Golden-Pigeon <goldenpigeon2000@gmail.com> | 2026-05-22 02:39:02 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-22 02:43:30 +0300 |
| commit | 1daf54ecbf960c42d612ed4ad2764045a606fb30 (patch) | |
| tree | c6ee19c7e8032ac77f5c00bc17bc6a1bd93d2272 /src/client | |
| parent | 0148c1379b76c5c0a9d05588c07dcb06ec32f93f (diff) | |
feat: show named session command hints
refs #199
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/mod.rs | 115 |
1 files changed, 114 insertions, 1 deletions
diff --git a/src/client/mod.rs b/src/client/mod.rs index 11273061..1ac05201 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -154,7 +154,11 @@ impl std::fmt::Display for ClientError { write!(f, "\nRun `{reattach_command}` to reattach")?; } else { write!(f, "detached from server")?; - write!(f, "\nRun `herdr` to reattach")?; + write!( + f, + "\nRun `{}` to reattach", + crate::session::local_attach_command() + )?; } } _ => { @@ -1125,6 +1129,65 @@ fn init_logging() { #[cfg(test)] mod tests { use super::*; + use std::ffi::OsString; + use std::sync::{Mutex, OnceLock}; + + fn env_lock() -> &'static Mutex<()> { + static LOCK: OnceLock<Mutex<()>> = OnceLock::new(); + LOCK.get_or_init(|| Mutex::new(())) + } + + fn restore_env_var(key: &str, value: Option<OsString>) { + if let Some(value) = value { + std::env::set_var(key, value); + } else { + std::env::remove_var(key); + } + } + + struct EnvVarGuard { + key: &'static str, + previous: Option<OsString>, + } + + impl EnvVarGuard { + fn set(key: &'static str, value: &str) -> Self { + let previous = std::env::var_os(key); + std::env::set_var(key, value); + Self { key, previous } + } + } + + impl Drop for EnvVarGuard { + fn drop(&mut self) { + restore_env_var(self.key, self.previous.clone()); + } + } + + struct EnvVarsRemovedGuard { + previous: Vec<(&'static str, Option<OsString>)>, + } + + impl EnvVarsRemovedGuard { + fn new(keys: &[&'static str]) -> Self { + let previous: Vec<_> = keys + .iter() + .map(|key| (*key, std::env::var_os(key))) + .collect(); + for key in keys { + std::env::remove_var(key); + } + Self { previous } + } + } + + impl Drop for EnvVarsRemovedGuard { + fn drop(&mut self) { + for (key, value) in self.previous.clone() { + restore_env_var(key, value); + } + } + } #[test] fn clipboard_image_paste_bridge_triggers_on_ctrl_v_and_empty_paste() { @@ -1296,6 +1359,56 @@ mod tests { } #[test] + fn client_error_display_detached_default_session_reattach_hint() { + let _guard = env_lock().lock().unwrap(); + let _env = EnvVarsRemovedGuard::new(&[ + crate::remote::REATTACH_COMMAND_ENV_VAR, + crate::session::SESSION_ENV_VAR, + ]); + let err = ClientError::ServerShutdown { + reason: Some("detached".into()), + }; + let msg = err.to_string(); + assert!( + msg.contains("Run `herdr` to reattach"), + "should suggest default reattach command: {msg}" + ); + } + + #[test] + fn client_error_display_detached_named_session_reattach_hint() { + let _guard = env_lock().lock().unwrap(); + let _remote_env = EnvVarsRemovedGuard::new(&[crate::remote::REATTACH_COMMAND_ENV_VAR]); + let _session_env = EnvVarGuard::set(crate::session::SESSION_ENV_VAR, "work"); + let err = ClientError::ServerShutdown { + reason: Some("detached".into()), + }; + let msg = err.to_string(); + assert!( + msg.contains("Run `herdr session attach work` to reattach"), + "should suggest named session reattach command: {msg}" + ); + } + + #[test] + fn client_error_display_detached_remote_reattach_hint_takes_precedence() { + let _guard = env_lock().lock().unwrap(); + let _remote_env = EnvVarGuard::set( + crate::remote::REATTACH_COMMAND_ENV_VAR, + "herdr --remote host --session work", + ); + let _session_env = EnvVarGuard::set(crate::session::SESSION_ENV_VAR, "work"); + let err = ClientError::ServerShutdown { + reason: Some("detached".into()), + }; + let msg = err.to_string(); + assert!( + msg.contains("Run `herdr --remote host --session work` to reattach"), + "should prefer remote reattach command: {msg}" + ); + } + + #[test] fn client_error_display_connection_lost() { let err = ClientError::ConnectionLost(io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe")); |
