fix: set a stable terminal identity for panes
This commit is contained in:
parent
4b482f37a1
commit
e9a3e3784c
65
src/pane.rs
65
src/pane.rs
|
|
@ -30,6 +30,17 @@ pub use self::{
|
|||
};
|
||||
|
||||
const RELEASE_REACQUIRE_SUPPRESSION: std::time::Duration = std::time::Duration::from_secs(1);
|
||||
const PANE_TERM: &str = "xterm-256color";
|
||||
const PANE_COLORTERM: &str = "truecolor";
|
||||
|
||||
fn apply_pane_terminal_env(cmd: &mut CommandBuilder) {
|
||||
// Each pane is rendered by herdr's own terminal layer, not the outer terminal
|
||||
// that launched the app. Advertising the inherited TERM leaks the host terminal
|
||||
// identity into shells and across SSH, which breaks redraw and cursor movement
|
||||
// when the remote side lacks matching terminfo entries.
|
||||
cmd.env("TERM", PANE_TERM);
|
||||
cmd.env("COLORTERM", PANE_COLORTERM);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct PendingAgentRelease {
|
||||
|
|
@ -246,6 +257,7 @@ impl PaneRuntime {
|
|||
let mut cmd = CommandBuilder::new(&shell);
|
||||
cmd.cwd(cwd);
|
||||
cmd.env(crate::HERDR_ENV_VAR, crate::HERDR_ENV_VALUE);
|
||||
apply_pane_terminal_env(&mut cmd);
|
||||
crate::integration::apply_pane_env(&mut cmd, pane_id);
|
||||
Self::spawn_command_builder(
|
||||
pane_id,
|
||||
|
|
@ -279,6 +291,7 @@ impl PaneRuntime {
|
|||
cmd.arg(command);
|
||||
cmd.cwd(cwd);
|
||||
cmd.env(crate::HERDR_ENV_VAR, crate::HERDR_ENV_VALUE);
|
||||
apply_pane_terminal_env(&mut cmd);
|
||||
crate::integration::apply_pane_env(&mut cmd, pane_id);
|
||||
for (key, value) in extra_env {
|
||||
cmd.env(key, value);
|
||||
|
|
@ -859,6 +872,58 @@ impl PaneRuntime {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn capture_shell_output(command: &str, extra_env: &[(&str, &str)]) -> String {
|
||||
let pair = native_pty_system()
|
||||
.openpty(PtySize {
|
||||
rows: 24,
|
||||
cols: 80,
|
||||
pixel_width: 0,
|
||||
pixel_height: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let output_path = std::env::temp_dir().join(format!(
|
||||
"herdr-pane-term-test-{}-{}.txt",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos()
|
||||
));
|
||||
let mut cmd = CommandBuilder::new("/bin/sh");
|
||||
cmd.arg("-c");
|
||||
cmd.arg(format!("{command} > '{}'", output_path.display()));
|
||||
cmd.cwd(std::env::current_dir().unwrap());
|
||||
cmd.env("TERM", "xterm-ghostty");
|
||||
cmd.env("COLORTERM", "falsecolor");
|
||||
apply_pane_terminal_env(&mut cmd);
|
||||
for (key, value) in extra_env {
|
||||
cmd.env(key, value);
|
||||
}
|
||||
|
||||
let mut child = pair.slave.spawn_command(cmd).unwrap();
|
||||
let status = child.wait().unwrap();
|
||||
assert!(status.success(), "shell command failed: {status:?}");
|
||||
|
||||
let output = std::fs::read_to_string(&output_path).unwrap();
|
||||
let _ = std::fs::remove_file(output_path);
|
||||
output
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_terminal_identity_overrides_outer_terminal_env() {
|
||||
let output = capture_shell_output("printf '%s\\n%s\\n' \"$TERM\" \"$COLORTERM\"", &[]);
|
||||
assert_eq!(output, "xterm-256color\ntruecolor\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_terminal_identity_allows_explicit_override() {
|
||||
let output = capture_shell_output(
|
||||
"printf '%s\\n%s\\n' \"$TERM\" \"$COLORTERM\"",
|
||||
&[("TERM", "vt100"), ("COLORTERM", "24bit")],
|
||||
);
|
||||
assert_eq!(output, "vt100\n24bit\n");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn focus_events_are_forwarded_when_enabled() {
|
||||
let (tx, mut rx) = mpsc::channel(4);
|
||||
|
|
|
|||
Loading…
Reference in New Issue