diff options
Diffstat (limited to 'src/platform/linux.rs')
| -rw-r--r-- | src/platform/linux.rs | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 3cf643e5..539c0d93 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -12,6 +12,30 @@ use super::{ pub fn raise_server_nofile_limit() {} +pub(crate) fn scrollback_editor_argv(path: &std::path::Path) -> std::io::Result<Vec<String>> { + let quoted_path = shell_quote(&path.display().to_string()); + let command = format!( + r#"scrollback_file={quoted_path}; eval "${{EDITOR:-vi}} \"\$scrollback_file\""; status=$?; rm -f "$scrollback_file"; exit $status"# + ); + Ok(vec!["/bin/sh".to_string(), "-c".to_string(), command]) +} + +fn shell_quote(value: &str) -> String { + if !value.is_empty() + && value.chars().all(|ch| { + ch.is_ascii_alphanumeric() + || matches!( + ch, + '@' | '%' | '_' | '+' | '=' | ':' | ',' | '.' | '/' | '-' + ) + }) + { + return value.to_string(); + } + + format!("'{}'", value.replace('\'', "'\\''")) +} + /// Collect the foreground terminal job for a given child PID. pub fn foreground_job(child_pid: u32) -> Option<ForegroundJob> { let tpgid = foreground_process_group_id(child_pid)?; @@ -794,4 +818,15 @@ mod tests { let _ = std::fs::remove_file(&path); assert_eq!(args, "--\n-danger\nbody\n"); } + + #[test] + fn scrollback_editor_argv_preserves_unix_editor_shell_semantics() { + let path = std::path::Path::new("/tmp/herdr scrollback.txt"); + let argv = scrollback_editor_argv(path).unwrap(); + + assert_eq!(argv[0], "/bin/sh"); + assert_eq!(argv[1], "-c"); + assert!(argv[2].contains("EDITOR:-vi")); + assert!(argv[2].contains("/tmp/herdr scrollback.txt")); + } } |
