Skip terminal probes in fork popup child

This commit is contained in:
Rakan El Khalil
2026-03-22 00:15:09 -07:00
parent c17c8433f8
commit f5c15fa5ce
3 changed files with 107 additions and 23 deletions

View File

@@ -23,6 +23,8 @@ use crate::custom_terminal::Frame;
use crate::insert_history::insert_history_lines;
use crate::render::renderable::Renderable;
use crate::terminal_palette::PARENT_BG_RGB_ENV_VAR;
use crate::terminal_palette::PARENT_FG_RGB_ENV_VAR;
use crate::terminal_palette::SKIP_DEFAULT_COLOR_PROBE_ENV_VAR;
use crate::tui;
use crate::tui::TuiEvent;
use crate::vt100_backend::VT100Backend;
@@ -295,12 +297,15 @@ fn append_config_override(args: &mut Vec<String>, key: &str, value: impl std::fm
args.push(format!("{key}={value}"));
}
fn parent_bg_rgb_env_value(bg: (u8, u8, u8)) -> String {
let (red, green, blue) = bg;
fn rgb_env_value(rgb: (u8, u8, u8)) -> String {
let (red, green, blue) = rgb;
format!("{red},{green},{blue}")
}
fn child_overlay_env(mut env: HashMap<String, String>) -> HashMap<String, String> {
fn child_overlay_env(
mut env: HashMap<String, String>,
enhanced_keys_supported: bool,
) -> HashMap<String, String> {
for key in [
"TMUX",
"TMUX_PANE",
@@ -310,11 +315,19 @@ fn child_overlay_env(mut env: HashMap<String, String>) -> HashMap<String, String
] {
env.remove(key);
}
env.insert(
crate::tui::PARENT_ENHANCED_KEYS_SUPPORTED_ENV_VAR.to_string(),
if enhanced_keys_supported { "1" } else { "0" }.to_string(),
);
env.insert(
SKIP_DEFAULT_COLOR_PROBE_ENV_VAR.to_string(),
"1".to_string(),
);
if let Some(fg) = crate::terminal_palette::default_fg() {
env.insert(PARENT_FG_RGB_ENV_VAR.to_string(), rgb_env_value(fg));
}
if let Some(bg) = crate::terminal_palette::default_bg() {
env.insert(
PARENT_BG_RGB_ENV_VAR.to_string(),
parent_bg_rgb_env_value(bg),
);
env.insert(PARENT_BG_RGB_ENV_VAR.to_string(), rgb_env_value(bg));
}
env
}
@@ -344,7 +357,10 @@ impl App {
let popup = stacked_popup_rect(area, existing_popups);
let terminal_size = popup_terminal_size(popup);
let program = std::env::current_exe()?.to_string_lossy().into_owned();
let env = child_overlay_env(std::env::vars().collect::<HashMap<_, _>>());
let env = child_overlay_env(
std::env::vars().collect::<HashMap<_, _>>(),
tui.enhanced_keys_supported(),
);
let args = self.build_fork_session_overlay_args(thread_id);
let terminal = ForkSessionTerminal::spawn(
&program,
@@ -1103,14 +1119,17 @@ mod tests {
#[test]
fn child_overlay_env_strips_terminal_multiplexer_markers() {
let env = child_overlay_env(HashMap::from([
("PATH".to_string(), "/usr/bin".to_string()),
("TMUX".to_string(), "1".to_string()),
("TMUX_PANE".to_string(), "%1".to_string()),
("ZELLIJ".to_string(), "1".to_string()),
("ZELLIJ_SESSION_NAME".to_string(), "codex".to_string()),
("ZELLIJ_VERSION".to_string(), "0.44.0".to_string()),
]));
let env = child_overlay_env(
HashMap::from([
("PATH".to_string(), "/usr/bin".to_string()),
("TMUX".to_string(), "1".to_string()),
("TMUX_PANE".to_string(), "%1".to_string()),
("ZELLIJ".to_string(), "1".to_string()),
("ZELLIJ_SESSION_NAME".to_string(), "codex".to_string()),
("ZELLIJ_VERSION".to_string(), "0.44.0".to_string()),
]),
/*enhanced_keys_supported*/ true,
);
assert_eq!(env.get("PATH"), Some(&"/usr/bin".to_string()));
assert_eq!(env.get("TMUX"), None);
@@ -1118,11 +1137,19 @@ mod tests {
assert_eq!(env.get("ZELLIJ"), None);
assert_eq!(env.get("ZELLIJ_SESSION_NAME"), None);
assert_eq!(env.get("ZELLIJ_VERSION"), None);
assert_eq!(
env.get(crate::tui::PARENT_ENHANCED_KEYS_SUPPORTED_ENV_VAR),
Some(&"1".to_string())
);
assert_eq!(
env.get(SKIP_DEFAULT_COLOR_PROBE_ENV_VAR),
Some(&"1".to_string())
);
}
#[test]
fn parent_bg_rgb_env_value_formats_rgb_triplet() {
assert_eq!(parent_bg_rgb_env_value((12, 34, 56)), "12,34,56");
fn rgb_env_value_formats_rgb_triplet() {
assert_eq!(rgb_env_value((12, 34, 56)), "12,34,56");
}
#[test]

View File

@@ -6,6 +6,8 @@ use std::sync::atomic::Ordering;
static DEFAULT_PALETTE_VERSION: AtomicU64 = AtomicU64::new(0);
pub(crate) const PARENT_BG_RGB_ENV_VAR: &str = "CODEX_TUI_PARENT_BG_RGB";
pub(crate) const PARENT_FG_RGB_ENV_VAR: &str = "CODEX_TUI_PARENT_FG_RGB";
pub(crate) const SKIP_DEFAULT_COLOR_PROBE_ENV_VAR: &str = "CODEX_TUI_SKIP_DEFAULT_COLOR_PROBE";
fn bump_palette_version() {
DEFAULT_PALETTE_VERSION.fetch_add(1, Ordering::Relaxed);
@@ -72,7 +74,7 @@ pub fn default_colors() -> Option<DefaultColors> {
}
pub fn default_fg() -> Option<(u8, u8, u8)> {
default_colors().map(|c| c.fg)
env_default_fg().or_else(|| default_colors().map(|c| c.fg))
}
pub fn default_bg() -> Option<(u8, u8, u8)> {
@@ -87,11 +89,29 @@ pub fn palette_version() -> u64 {
DEFAULT_PALETTE_VERSION.load(Ordering::Relaxed)
}
fn env_default_bg() -> Option<(u8, u8, u8)> {
parse_bg_rgb_env(&env::var(PARENT_BG_RGB_ENV_VAR).ok()?)
fn should_skip_default_color_probe() -> bool {
matches!(
env::var(SKIP_DEFAULT_COLOR_PROBE_ENV_VAR).ok().as_deref(),
Some("1" | "true" | "TRUE" | "True")
)
}
fn parse_bg_rgb_env(value: &str) -> Option<(u8, u8, u8)> {
fn inherited_default_colors() -> Option<DefaultColors> {
Some(DefaultColors {
fg: env_default_fg()?,
bg: env_default_bg()?,
})
}
fn env_default_fg() -> Option<(u8, u8, u8)> {
parse_rgb_env(&env::var(PARENT_FG_RGB_ENV_VAR).ok()?)
}
fn env_default_bg() -> Option<(u8, u8, u8)> {
parse_rgb_env(&env::var(PARENT_BG_RGB_ENV_VAR).ok()?)
}
fn parse_rgb_env(value: &str) -> Option<(u8, u8, u8)> {
let mut parts = value.split(',');
let red = parts.next()?.trim().parse().ok()?;
let green = parts.next()?.trim().parse().ok()?;
@@ -149,11 +169,31 @@ mod imp {
pub(super) fn default_colors() -> Option<DefaultColors> {
let cache = default_colors_cache();
let mut cache = cache.lock().ok()?;
if let Some(colors) = super::inherited_default_colors() {
cache.attempted = true;
cache.value = Some(colors);
return Some(colors);
}
if super::should_skip_default_color_probe() {
cache.attempted = true;
cache.value = None;
return None;
}
cache.get_or_init_with(|| query_default_colors().unwrap_or_default())
}
pub(super) fn requery_default_colors() {
if let Ok(mut cache) = default_colors_cache().lock() {
if let Some(colors) = super::inherited_default_colors() {
cache.attempted = true;
cache.value = Some(colors);
return;
}
if super::should_skip_default_color_probe() {
cache.attempted = true;
cache.value = None;
return;
}
// Don't try to refresh if the cache is already attempted and failed.
if cache.attempted && cache.value.is_none() {
return;

View File

@@ -61,6 +61,8 @@ pub(crate) const TARGET_FRAME_INTERVAL: Duration = frame_rate_limiter::MIN_FRAME
/// A type alias for the terminal type used in this application
pub type Terminal = CustomTerminal<CrosstermBackend<Stdout>>;
pub(crate) const PARENT_ENHANCED_KEYS_SUPPORTED_ENV_VAR: &str =
"CODEX_TUI_PARENT_ENHANCED_KEYS_SUPPORTED";
pub fn set_modes() -> Result<()> {
execute!(stdout(), EnableBracketedPaste)?;
@@ -227,6 +229,17 @@ pub fn init() -> Result<Terminal> {
Ok(tui)
}
fn inherited_enhanced_keys_supported() -> Option<bool> {
match std::env::var(PARENT_ENHANCED_KEYS_SUPPORTED_ENV_VAR)
.ok()?
.as_str()
{
"1" | "true" | "TRUE" | "True" => Some(true),
"0" | "false" | "FALSE" | "False" => Some(false),
_ => None,
}
}
fn set_panic_hook() {
let hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
@@ -270,7 +283,11 @@ impl Tui {
// Detect keyboard enhancement support before any EventStream is created so the
// crossterm poller can acquire its lock without contention.
let enhanced_keys_supported = supports_keyboard_enhancement().unwrap_or(false);
let enhanced_keys_supported = if let Some(supported) = inherited_enhanced_keys_supported() {
supported
} else {
supports_keyboard_enhancement().unwrap_or(false)
};
// Cache this to avoid contention with the event reader.
supports_color::on_cached(supports_color::Stream::Stdout);
let _ = crate::terminal_palette::default_colors();