feat(tui): add terminal-transparent theme (#2230)#2276
Conversation
…'s colors Adds a new selectable theme `terminal` (alongside System / Whale / Whale Light / Grayscale / Catppuccin / Tokyo Night / Dracula / Gruvbox) that paints every surface with `Color::Reset` instead of any RGB so the host terminal's own background, foreground, and palette show through. The existing `system` theme only chose between two RGB themes (Whale dark or Whale Light) based on COLORFGBG / macOS appearance — useful, but it still painted brand-colored RGB surfaces. Users with custom terminal themes (Solarized, Nord, transparent backgrounds, custom Ghostty/iTerm schemes) had no way to make the TUI respect their terminal palette. Implementation: - New `TERMINAL_UI_THEME` const where every `*_bg` and most text slots are `Color::Reset`, and accents (mode_agent/yolo/plan, status_working, status_warning) use ANSI named colors so they also inherit the user's terminal palette rather than DeepSeek brand RGB. - `ThemeId::Terminal` plumbed through `from_name` / `name` / `display_name` / `tagline` / `ui_theme` / `SELECTABLE_THEMES`, and registered in `normalize_theme_name` with aliases `term`, `transparent`, `follow-terminal`, `inherit` so existing user-friendly config strings just work. - `theme_remap_active(Terminal) → true` so the existing per-cell remap in `ColorCompatBackend` rewrites every hard-coded palette constant (`DEEPSEEK_INK`, `DEEPSEEK_SLATE`, `BORDER_COLOR`, `TEXT_BODY`, …) to `Color::Reset`. Without this, the many render sites that reach for the named palette constants directly would still paint brand RGB. - `theme_green` / `theme_red` return `Color::Green` / `Color::Red` for Terminal so diff "+"/"−" stay green/red but follow the user's terminal palette. - `theme_diff_added_bg` / `theme_diff_deleted_bg` return `Color::Reset` for Terminal — diff highlight is conveyed by foreground color only. - The new theme is the second entry in `SELECTABLE_THEMES` (right after System) so it surfaces prominently in the `/theme` picker. theme_picker tests: the new theme is inserted in row 2 of `SELECTABLE_THEMES`, which shifts the indices three existing tests relied on — `arrow_down_previews_next_theme`, `enter_commits_with_persist_true`, and `digit_jumps_to_row` — so those expectations are updated to match the new ordering. No production behavior change in those tests, just index arithmetic. Default (`theme = "system"`) is unchanged; existing users see no difference. Users who want full terminal pass-through opt in via `/theme` or `theme = "terminal"` in settings.toml.
Adopt Gemini code-assist review on PR #1831: - mode_plan: Yellow -> Magenta. Plan chip now contrasts with status_warning (still Yellow) so the two never visually collide in the status row. - status_ready: Reset -> DarkGray. Ready chip now reads as a distinct subdued accent instead of blending into body text (which also resolves to Reset on this theme). No surface change otherwise -- backgrounds and body text still use Color::Reset to inherit the host terminal's color scheme.
There was a problem hiding this comment.
Code Review
This pull request introduces a new "Terminal" theme (TERMINAL_UI_THEME) that allows the TUI to fully inherit the host terminal's color scheme using transparent backgrounds and ANSI named colors. The feedback suggests improving the theme's usability and visual hierarchy by avoiding Color::Reset for selections, borders, and muted text variants, recommending standard ANSI colors like Color::DarkGray or Color::Gray instead to ensure readability and contrast.
| panel_bg: Color::Reset, | ||
| elevated_bg: Color::Reset, | ||
| composer_bg: Color::Reset, | ||
| selection_bg: Color::Reset, |
There was a problem hiding this comment.
Using Color::Reset for selection_bg means that selected text or list items will have the same background color as the default terminal background. This makes selections (such as text highlighted for copying or selected menu items) completely invisible or extremely difficult to distinguish.
Consider using a standard ANSI color like Color::DarkGray or Color::Gray for selection_bg to ensure selections are visually distinct while still respecting the user's terminal palette.
| selection_bg: Color::Reset, | |
| selection_bg: Color::DarkGray, |
| text_dim: Color::Reset, | ||
| text_hint: Color::Reset, | ||
| text_muted: Color::Reset, | ||
| text_body: Color::Reset, | ||
| text_soft: Color::Reset, |
There was a problem hiding this comment.
Setting text_dim, text_hint, text_muted, and text_soft all to Color::Reset collapses the entire text hierarchy of the TUI. Since text_body is also Color::Reset, all text (including timestamps, muted secondary info, hints, and main body text) will render in the exact same default terminal foreground color, making the interface much harder to scan.
To preserve the visual hierarchy while inheriting the terminal's color scheme, consider using standard ANSI grayscale colors like Color::DarkGray for dim/hint text and Color::Gray for muted/soft text.
| text_dim: Color::Reset, | |
| text_hint: Color::Reset, | |
| text_muted: Color::Reset, | |
| text_body: Color::Reset, | |
| text_soft: Color::Reset, | |
| text_dim: Color::DarkGray, | |
| text_hint: Color::DarkGray, | |
| text_muted: Color::Gray, | |
| text_body: Color::Reset, | |
| text_soft: Color::Reset, |
| text_muted: Color::Reset, | ||
| text_body: Color::Reset, | ||
| text_soft: Color::Reset, | ||
| border: Color::Reset, |
There was a problem hiding this comment.
Using Color::Reset for border renders all panel and modal borders in the default terminal foreground color (same as body text). This can make borders visually loud and distracting.
Consider using Color::DarkGray or Color::Gray for border to keep the layout clean and unobtrusive while still inheriting the terminal's palette.
| border: Color::Reset, | |
| border: Color::DarkGray, |
| text_muted: Color::Reset, | ||
| text_body: Color::Reset, | ||
| text_soft: Color::Reset, | ||
| border: Color::Reset, |
There was a problem hiding this comment.
Invisible selection with
Color::Reset selection background
selection_bg: Color::Reset means the highlighted item in any list/picker looks identical to un-highlighted items — both use the terminal's default background. A user navigating the theme picker or any other selectable list while on the Terminal theme will have no visual cue about what is currently selected. Even a named ANSI color (Color::Blue, Color::DarkGray) would preserve the terminal-transparent aesthetic while keeping selections legible.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| assert_eq!(normalize_theme_name("system"), Some("system")); | ||
| assert_eq!(normalize_theme_name("default"), Some("system")); | ||
| assert_eq!(normalize_theme_name("whale"), Some("dark")); | ||
| assert_eq!(normalize_theme_name("transparent"), Some("terminal")); | ||
| assert_eq!(normalize_theme_name("inherit"), Some("terminal")); | ||
| assert_eq!(normalize_theme_name("black-white"), Some("grayscale")); | ||
| assert_eq!(normalize_theme_name("mono"), Some("grayscale")); | ||
| assert_eq!(normalize_theme_name("solarized"), None); |
There was a problem hiding this comment.
Stale test name after appending terminal-alias assertions
Terminal alias assertions (transparent, inherit) were added to a test named theme_names_normalize_common_grayscale_aliases. The name no longer describes what the test actually covers, making it harder to locate the right test when a future alias change breaks it. Consider renaming it or splitting it into a dedicated theme_names_normalize_terminal_aliases test.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| pub fn normalize_theme_name(value: &str) -> Option<&'static str> { | ||
| match value.trim().to_ascii_lowercase().as_str() { | ||
| "" | "auto" | "system" | "default" => Some("system"), | ||
| "terminal" | "term" | "transparent" | "follow-terminal" | "inherit" => Some("terminal"), |
|
Independent review (Devin): Theme correctly uses Color::Reset for all surfaces to inherit terminal background. ANSI accents preserve user's terminal palette. Good remap pipeline integration. Critical issue: selection_bg: Color::Reset makes list selections invisible - users can't see active item in theme picker or any selectable list. Test coverage looks good for terminal theme behavior. No conflicts with current main. v0.8.48: No conflicts (PR adds to SELECTABLE_THEMES, doesn't touch Windows logging). |
|
Theme cluster coordination — this PR is one of 4 in flight that all add to
All 4 hard-conflict at the Cross-pinging the cluster: @AiurArtanis @HUQIANTAO @malsony — same coordination note on each PR. |
Summary
terminaltheme with transparent surfaces and ANSI accents so Windows Terminal background images and transparent palettes can show throughterm,transparent,follow-terminal, andinheritsystembehavior unchanged; users opt in through/themeor settingsRefs #2230.
Harvested from PR #1831 by @Sskift; original authored commits are preserved, with current-main cleanup and tests added here.
Verification
Greptile Summary
This PR adds a
terminaltheme that lets the host terminal's color scheme show through by usingColor::Resetfor all background and most foreground slots, with ANSI named colors for accents. It hooks into the existing community-theme remap pipeline (theme_remap_active,adapt_fg_for_theme,adapt_bg_for_theme) and setsmode: PaletteMode::Darkon the theme constant to prevent the legacy dark↔light Stage-2 remap from overwriting theColor::Resetoutputs.TERMINAL_UI_THEMEis added topalette.rswithColor::Resetsurfaces and ANSI-named accents;ThemeId::Terminalis wired into all existing match arms and five aliases are registered innormalize_theme_name.theme_picker.rstests are updated to account for Terminal's insertion at picker index 1: arrow-down preview, Enter-commit key-count, and digit-jump row number are all correctly adjusted.Confidence Score: 3/5
The theme logic and remap pipeline integration look correct, but the transparent selection background will make selected items invisible in any list or picker when this theme is active.
The core architecture is sound and well-commented. The main concern is selection_bg: Color::Reset — with no visible selection highlight, a user navigating a list (including the theme picker itself) cannot tell which row is active. This affects every selectable widget while the theme is in use.
crates/tui/src/palette.rs — specifically the selection_bg slot in TERMINAL_UI_THEME and the test coverage gaps for the term and follow-terminal aliases.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Cell draw] --> B{theme_remap_active?} B -- "No (System/Whale/WhaleLight)" --> D[Stage 2: dark↔light remap] B -- "Yes (Terminal/Catppuccin/etc.)" --> C["Stage 1: adapt_fg/bg_for_theme\n(dark-palette constants → UiTheme slots)"] C --> C1{"ThemeId::Terminal?"} C1 -- "Yes" --> C2["bg constants → Color::Reset\nfg constants → Color::Reset\naccents → ANSI named colors"] C1 -- "No" --> C3["Map to community preset RGB slots"] C2 --> D C3 --> D D --> D1{"palette_mode\n(= ui_theme.mode)"} D1 -- "Dark (Terminal always Dark)" --> E[Stage 3: depth downsampling] D1 -- "Light" --> D2[adapt light-palette overrides] D2 --> E E --> F[Emit to crossterm]Reviews (1): Last reviewed commit: "test(tui): cover terminal theme palette ..." | Re-trigger Greptile