Skip to content

feat(tui): add terminal-transparent theme (#2230)#2276

Open
Hmbown wants to merge 3 commits into
mainfrom
fix/2230-terminal-theme
Open

feat(tui): add terminal-transparent theme (#2230)#2276
Hmbown wants to merge 3 commits into
mainfrom
fix/2230-terminal-theme

Conversation

@Hmbown
Copy link
Copy Markdown
Owner

@Hmbown Hmbown commented May 27, 2026

Summary

  • add selectable terminal theme with transparent surfaces and ANSI accents so Windows Terminal background images and transparent palettes can show through
  • add aliases: term, transparent, follow-terminal, and inherit
  • keep the default system behavior unchanged; users opt in through /theme or settings
  • update the stale feat(tui): add "Terminal" theme #1831 work for the current palette schema and add coverage for Terminal remapping

Refs #2230.
Harvested from PR #1831 by @Sskift; original authored commits are preserved, with current-main cleanup and tests added here.

Verification

  • cargo test -p codewhale-tui terminal_theme_resets_surfaces_and_remaps_direct_palette_constants -- --nocapture
  • cargo test -p codewhale-tui theme_picker -- --nocapture
  • cargo test -p codewhale-tui theme_names_normalize_common_grayscale_aliases -- --nocapture
  • cargo test -p codewhale-tui theme_qa -- --nocapture
  • cargo check -p codewhale-tui --all-features --locked
  • cargo fmt --all -- --check
  • git diff --check

Greptile Summary

This PR adds a terminal theme that lets the host terminal's color scheme show through by using Color::Reset for 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 sets mode: PaletteMode::Dark on the theme constant to prevent the legacy dark↔light Stage-2 remap from overwriting the Color::Reset outputs.

  • TERMINAL_UI_THEME is added to palette.rs with Color::Reset surfaces and ANSI-named accents; ThemeId::Terminal is wired into all existing match arms and five aliases are registered in normalize_theme_name.
  • theme_picker.rs tests 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

Filename Overview
crates/tui/src/palette.rs Adds TERMINAL_UI_THEME constant, ThemeId::Terminal variant, aliases, and hooks into the community-theme remap pipeline; selection_bg is Color::Reset which makes the selection highlight invisible
crates/tui/src/tui/theme_picker.rs Updates picker tests to account for Terminal being inserted at index 1; navigation counts and digit-jump row numbers are correctly adjusted

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]
Loading

Fix All in Devin

Reviews (1): Last reviewed commit: "test(tui): cover terminal theme palette ..." | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

liushiao and others added 3 commits May 27, 2026 05:58
…'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.
Copilot AI review requested due to automatic review settings May 27, 2026 11:07
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread crates/tui/src/palette.rs
panel_bg: Color::Reset,
elevated_bg: Color::Reset,
composer_bg: Color::Reset,
selection_bg: Color::Reset,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
selection_bg: Color::Reset,
selection_bg: Color::DarkGray,

Comment thread crates/tui/src/palette.rs
Comment on lines +847 to +851
text_dim: Color::Reset,
text_hint: Color::Reset,
text_muted: Color::Reset,
text_body: Color::Reset,
text_soft: Color::Reset,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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,

Comment thread crates/tui/src/palette.rs
text_muted: Color::Reset,
text_body: Color::Reset,
text_soft: Color::Reset,
border: Color::Reset,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
border: Color::Reset,
border: Color::DarkGray,

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Comment thread crates/tui/src/palette.rs
text_muted: Color::Reset,
text_body: Color::Reset,
text_soft: Color::Reset,
border: Color::Reset,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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!

Fix in Devin

Comment thread crates/tui/src/palette.rs
Comment on lines 1840 to 1847
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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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!

Fix in Devin

Comment thread crates/tui/src/palette.rs
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"),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 term and follow-terminal aliases lack test coverage

The existing test only exercises transparent and inherit. The term and follow-terminal aliases introduced in the same match arm have no assertions, so a future typo or refactor could silently break them.

Fix in Devin

@Hmbown
Copy link
Copy Markdown
Owner Author

Hmbown commented May 27, 2026

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).
Sibling PRs: Will conflict with #2267 (Claude), #2270 (Solarized), #2129 (Matrix) - all append to SELECTABLE_THEMES.

@Hmbown
Copy link
Copy Markdown
Owner Author

Hmbown commented May 27, 2026

Theme cluster coordination — this PR is one of 4 in flight that all add to palette.rs::SELECTABLE_THEMES:

All 4 hard-conflict at the SELECTABLE_THEMES slice and normalize_theme_name arms. Plan: first-merged wins as-is; the other three each get a small rebase. Your theme carries forward unchanged.

Cross-pinging the cluster: @AiurArtanis @HUQIANTAO @malsony — same coordination note on each PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants