From 0f521ce289c36565ee1681d38168b62bd4eeaf5f Mon Sep 17 00:00:00 2001 From: kronberger-droid Date: Thu, 17 Sep 2026 18:57:07 +0200 Subject: [PATCH] refactor(engine): take the TERM=dumb answer from the painter The engine read `TERM` on every paint while the painter answers from a flag cached at construction and on resize, so after a mid-session change the colors and the skipped escapes could disagree. ANSI coloring now follows that cache too, thus it no longer tracks `TERM` between resizes. Follow-up to #1183. --- src/engine.rs | 10 ++++------ src/painting/painter.rs | 6 ++++++ src/prompt/default.rs | 5 +++-- src/utils/environment.rs | 19 ++++++------------- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 8b82a4ae1..69d504843 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -35,10 +35,7 @@ use { kitty::KittyProtocolGuard, semantic_prompt::{Osc133ClickEventsMarkers, SemanticPromptMarkers}, }, - utils::{ - environment::{term_supports_ansi, var_os}, - text_manipulation, - }, + utils::text_manipulation, AbbrExpandContext, AutoPairAction, AutoPairContext, AutoPairs, Direction, EditCommand, ExampleHighlighter, Highlighter, LineBuffer, Menu, MenuEvent, MouseButton, Prompt, PromptHistorySearch, ReedlineMenu, Signal, UndoBehavior, ValidationResult, Validator, @@ -555,9 +552,10 @@ impl Reedline { /// /// ANSI coloring requires both the Reedline configuration to enable it and /// terminal support; `TERM=dumb` takes precedence over `with_ansi_colors(true)`. + /// The painter holds the terminal policy, so the colors and the escapes it + /// skips cannot disagree. fn effective_ansi_coloring(&self) -> bool { - let term = var_os("TERM"); - self.use_ansi_coloring && term_supports_ansi(term.as_deref()) + self.use_ansi_coloring && !self.painter.term_is_dumb() } /// A builder which enables or disables the use of ansi coloring in the prompt diff --git a/src/painting/painter.rs b/src/painting/painter.rs index 8b60dffdd..601913f24 100644 --- a/src/painting/painter.rs +++ b/src/painting/painter.rs @@ -481,6 +481,12 @@ impl Painter { } } + /// Whether the terminal declared itself `TERM=dumb`, as of construction + /// or the last resize. + pub(crate) fn term_is_dumb(&self) -> bool { + self.term_is_dumb + } + /// Computes the right prompt position when the terminal can position it. fn compute_right_prompt( &self, diff --git a/src/prompt/default.rs b/src/prompt/default.rs index 7be07e890..bab4f87d0 100644 --- a/src/prompt/default.rs +++ b/src/prompt/default.rs @@ -10,6 +10,7 @@ //! visual, helix's select) would otherwise have nowhere to sit. use crate::prompt::base::PromptHelixMode; +use crate::utils::environment::var_os; use crate::{Prompt, PromptEditMode, PromptHistorySearch, PromptHistorySearchStatus, PromptViMode}; use { @@ -148,8 +149,8 @@ fn get_working_dir() -> Result { let cwd = env::current_dir()?; // `USERPROFILE` on Windows, `HOME` elsewhere. Avoids `env::home_dir()`, // which is buggy on Windows before 1.85 (above our 1.63 MSRV). - let home = crate::utils::environment::var_os("USERPROFILE") - .or_else(|| crate::utils::environment::var_os("HOME")) + let home = var_os("USERPROFILE") + .or_else(|| var_os("HOME")) .map(std::path::PathBuf::from); Ok(format_working_dir(&cwd, home.as_deref())) } diff --git a/src/utils/environment.rs b/src/utils/environment.rs index ee4ebb1f2..eaeaac7a7 100644 --- a/src/utils/environment.rs +++ b/src/utils/environment.rs @@ -14,29 +14,22 @@ pub(crate) fn term_is_dumb(term: Option<&OsStr>) -> bool { term == Some(OsStr::new("dumb")) } -/// Whether ANSI coloring is appropriate for the declared terminal. -/// -/// An unset or non-dumb `TERM` preserves the configured Reedline behavior. -pub(crate) fn term_supports_ansi(term: Option<&OsStr>) -> bool { - !term_is_dumb(term) -} - #[cfg(test)] mod tests { use super::*; #[test] - fn term_dumb_does_not_support_ansi() { - assert!(!term_supports_ansi(Some(OsStr::new("dumb")))); + fn term_dumb_is_dumb() { + assert!(term_is_dumb(Some(OsStr::new("dumb")))); } #[test] - fn regular_term_supports_ansi() { - assert!(term_supports_ansi(Some(OsStr::new("xterm-256color")))); + fn regular_term_is_not_dumb() { + assert!(!term_is_dumb(Some(OsStr::new("xterm-256color")))); } #[test] - fn unset_term_does_not_disable_ansi() { - assert!(term_supports_ansi(None)); + fn unset_term_is_not_dumb() { + assert!(!term_is_dumb(None)); } }