fix(pty): always set TERM/COLORTERM for spawned shells
A GUI/launchd-spawned daemon has no TERM in its environment, so child shells
inherited none and tput/zsh/ncurses failed ('tput: No value for $TERM').
The PTY now defaults TERM=xterm-256color and COLORTERM=truecolor (matching
xterm.js) unless the caller already provides them. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,16 @@ impl PtyHandle {
|
|||||||
cmd.arg(a);
|
cmd.arg(a);
|
||||||
}
|
}
|
||||||
cmd.cwd(&spec.cwd);
|
cmd.cwd(&spec.cwd);
|
||||||
|
// Guarantee a terminal environment even when the daemon was launched
|
||||||
|
// without one (GUI/launchd have no TERM, which breaks tput/zsh/ncurses).
|
||||||
|
// xterm.js renders an xterm-256color/truecolor terminal. Caller-provided
|
||||||
|
// values in spec.env win.
|
||||||
|
if !spec.env.iter().any(|(k, _)| k == "TERM") {
|
||||||
|
cmd.env("TERM", "xterm-256color");
|
||||||
|
}
|
||||||
|
if !spec.env.iter().any(|(k, _)| k == "COLORTERM") {
|
||||||
|
cmd.env("COLORTERM", "truecolor");
|
||||||
|
}
|
||||||
for (k, v) in &spec.env {
|
for (k, v) in &spec.env {
|
||||||
cmd.env(k, v);
|
cmd.env(k, v);
|
||||||
}
|
}
|
||||||
@@ -125,6 +135,19 @@ mod tests {
|
|||||||
assert!(text.contains("SPACESH_OK"), "got: {text:?}");
|
assert!(text.contains("SPACESH_OK"), "got: {text:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn term_is_set_even_without_inherited_env() {
|
||||||
|
// Clear TERM in the parent to emulate a GUI/launchd-spawned daemon.
|
||||||
|
std::env::remove_var("TERM");
|
||||||
|
let mut handle = PtyHandle::spawn(shell_spec("printf %s \"$TERM\"")).unwrap();
|
||||||
|
let mut collected = Vec::new();
|
||||||
|
while let Some(chunk) = handle.output.recv().await {
|
||||||
|
collected.extend_from_slice(&chunk);
|
||||||
|
}
|
||||||
|
let text = String::from_utf8_lossy(&collected);
|
||||||
|
assert!(text.contains("xterm-256color"), "got: {text:?}");
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn resize_does_not_error() {
|
async fn resize_does_not_error() {
|
||||||
let handle = PtyHandle::spawn(shell_spec("sleep 0.2")).unwrap();
|
let handle = PtyHandle::spawn(shell_spec("sleep 0.2")).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user