diff --git a/rust/core/src/clients/local.rs b/rust/core/src/clients/local.rs index 3192906..eadbfed 100644 --- a/rust/core/src/clients/local.rs +++ b/rust/core/src/clients/local.rs @@ -17,34 +17,6 @@ pub fn default_shell() -> String { std::env::var("SHELL").ok().filter(|s| !s.is_empty()).unwrap_or_else(|| "/bin/sh".into()) } -fn is_utf8_locale(v: &str) -> bool { - let v = v.to_lowercase(); - v.contains("utf-8") || v.contains("utf8") -} - -/// TERM=xterm-256color and a UTF-8 character locale, keeping the user's environment otherwise. -pub fn local_shell_env(env: &mut Vec<(String, String)>) { - let set = |env: &mut Vec<(String, String)>, k: &str, v: &str| { - env.retain(|(ek, _)| ek != k); - env.push((k.into(), v.into())); - }; - set(env, "TERM", "xterm-256color"); - let get = |k: &str| env.iter().find(|(ek, _)| ek == k).map(|(_, v)| v.clone()); - let effective = get("LC_ALL").or_else(|| get("LC_CTYPE")).or_else(|| get("LANG")); - if effective.as_deref().is_some_and(is_utf8_locale) { - return; - } - let locale = if cfg!(target_os = "macos") { "en_US.UTF-8" } else { "C.UTF-8" }; - let key = if get("LC_ALL").is_some() { - "LC_ALL" - } else if get("LC_CTYPE").is_some() || get("LANG").is_some() { - "LC_CTYPE" - } else { - "LANG" - }; - set(env, key, locale); -} - struct Running { master: Box, writer: Box, @@ -77,11 +49,12 @@ impl LocalShell { .openpty(PtySize { rows: st.3, cols: st.2, pixel_width: 0, pixel_height: 0 }) .map_err(|e| format!("failed to start shell {:?}: {e}", self.shell))?; let mut cmd = CommandBuilder::new(&self.shell); - let mut env: Vec<(String, String)> = std::env::vars().collect(); - local_shell_env(&mut env); cmd.env_clear(); - for (k, v) in env { - cmd.env(k, v); + let env = crate::terminalenv::local_shell_env(std::env::vars().map(|(k, v)| format!("{k}={v}")).collect()); + for kv in env { + if let Some((k, v)) = kv.split_once('=') { + cmd.env(k, v); + } } cmd.cwd(&st.1); let mut child = pair.slave.spawn_command(cmd).map_err(|e| format!("failed to start shell {:?}: {e}", self.shell))?; @@ -215,12 +188,4 @@ mod tests { } assert_eq!(sh.working_directory(), PathBuf::from("/")); } - - #[test] - fn env_gets_term_and_utf8() { - let mut e = vec![("LANG".to_string(), "C".to_string())]; - local_shell_env(&mut e); - assert!(e.contains(&("TERM".into(), "xterm-256color".into()))); - assert!(e.iter().any(|(k, v)| k == "LC_CTYPE" && v.ends_with("UTF-8"))); - } } diff --git a/rust/core/src/clients/ssh.rs b/rust/core/src/clients/ssh.rs index addc97a..f5b5e4f 100644 --- a/rust/core/src/clients/ssh.rs +++ b/rust/core/src/clients/ssh.rs @@ -158,16 +158,6 @@ async fn connect_agent() -> Result { } } -/// Profile env vars plus a UTF-8 LC_CTYPE when the profile sets no locale (Go's SSHEnvVars). -fn ssh_env_vars(env: &std::collections::BTreeMap) -> std::collections::BTreeMap { - let mut out: std::collections::BTreeMap = - env.iter().filter(|(k, _)| !k.trim().is_empty()).map(|(k, v)| (k.trim().to_string(), v.clone())).collect(); - if !["LC_ALL", "LC_CTYPE", "LANG"].iter().any(|k| out.contains_key(*k)) { - out.insert("LC_CTYPE".into(), if cfg!(target_os = "macos") { "en_US.UTF-8" } else { "C.UTF-8" }.into()); - } - out -} - fn is_totp_prompt(q: &str) -> bool { let q = q.to_lowercase(); [ @@ -496,7 +486,7 @@ impl SshClient { let handle = Arc::new(handle); let ch = handle.channel_open_session().await.map_err(|e| format!("failed to create SSH session: {e}"))?; - for (k, v) in ssh_env_vars(&sc.env_vars) { + for (k, v) in crate::terminalenv::ssh_env_vars(&sc.env_vars) { let _ = ch.set_env(false, k, v).await; } let term = if sc.terminal_type.is_empty() { "xterm-256color" } else { &sc.terminal_type };