Skip to content

Comments

feat(tui): add theme-aware diff backgrounds with capability-graded palettes#12581

Merged
etraut-openai merged 6 commits intoopenai:mainfrom
fcoury:feat/enhance-syntax-highlighting
Feb 24, 2026
Merged

feat(tui): add theme-aware diff backgrounds with capability-graded palettes#12581
etraut-openai merged 6 commits intoopenai:mainfrom
fcoury:feat/enhance-syntax-highlighting

Conversation

@fcoury
Copy link
Contributor

@fcoury fcoury commented Feb 23, 2026

Problem

Diff lines used only foreground colors (green/red) with no background tinting, making them hard to scan. The gutter (line numbers) also had no theme awareness — dimmed text was fine on dark terminals but unreadable on light ones.

Mental model

Each diff line now has four styled layers: gutter (line number), sign (+/-), content (text), and line background (full terminal width). A DiffTheme enum (Dark / Light) is selected once per render by probing the terminal's queried background via default_bg(). A companion DiffColorLevel enum (TrueColor / Ansi256 / Ansi16) is derived from stdout_color_level() and gates which palette is used. All style helpers dispatch on (theme, DiffLineType, color_level) to pick the right colors.

Theme Picker Wide Theme Picker Narrow
image image
Dark BG - 16 colors Dark BG - 256 colors Dark BG - True Colors
dark-16colors dark-256colors dark-truecolor
Light BG - 16 colors Light BG - 256 colors Light BG - True Colors
light-16colors light-256colors light-truecolor

Non-goals

  • No runtime theme switching beyond what default_bg() already provides.
  • No change to syntax highlighting theme selection or the highlight module.

Tradeoffs

  • Three fixed palettes (truecolor RGB, 256-color indexed, 16-color named) are maintained rather than using best_color nearest-match. This is deliberate: supports_color::on_cached(Stream::Stdout) can misreport capabilities once crossterm enters the alternate screen, so hand-picked palette entries give better visual results than automatic quantization.
  • Delete lines in the syntax-highlighted path get Modifier::DIM to visually recede compared to insert lines. This trades some readability of deleted code for scan-ability of additions.
  • The theme picker's diff preview sets preserve_side_content_bg: true on ListSelectionView so diff background tints survive into the side panel. Other popups keep the default (false) to preserve their reset-background look.

Architecture

  • Color constants are module-level const items grouped by palette tier: DARK_TC_* / LIGHT_TC_* (truecolor RGB tuples), DARK_256_* / LIGHT_256_* (xterm indexed), with named Color variants used for the 16-color tier.
  • DiffTheme is a private enum; diff_theme() probes the terminal and diff_theme_for_bg() is the testable pure-function version.
  • DiffColorLevel is a private enum derived from StdoutColorLevel via diff_color_level().
  • Palette helpers (add_line_bg, del_line_bg, light_gutter_fg, light_add_num_bg, light_del_num_bg) each take (DiffTheme, DiffColorLevel) or just DiffColorLevel and return a Color.
  • Style helpers (style_line_bg_for, style_gutter_for, style_sign_add, style_sign_del, style_add, style_del) each take (DiffLineType, DiffTheme, DiffColorLevel) or (DiffTheme, DiffColorLevel) and return a Style.
  • push_wrapped_diff_line_inner_with_theme_and_color_level is the innermost renderer, accepting both theme and color level so tests can exercise any combination without depending on the terminal.
  • Line-level background is applied via RtLine::from(...).style(line_bg) so the tint extends across the full terminal width, not just the text content.
  • Theme picker integration: ListSelectionView gained a preserve_side_content_bg flag. When true, the side panel skips force_bg_to_terminal_bg, letting diff preview backgrounds render faithfully.

Observability

No new logging. Theme selection is deterministic from default_bg(), which is already queried and cached at TUI startup.

Tests

  1. DiffTheme is determined per render_change call — if default_bg() changes mid-render (e.g. requery_default_colors() fires), different file chunks could render with different themes. Low risk in practice since re-query only happens on explicit user action.
  2. 16-color tier uses named Color variants (Color::Green, Color::Red, etc.) which the terminal maps to its own palette. On unusual terminal themes these could clash with the background. Acceptable since 16-color terminals already have unpredictable color rendering.
  3. Light-theme style_add / style_del set bg but no fg — on light terminals, non-syntax-highlighted content uses the terminal's default foreground against a pastel background. If the terminal's default fg happens to be very light, contrast could suffer. This is an edge case since light-terminal users typically have dark default fg.
  4. preserve_side_content_bg is a general-purpose flag but only used by the theme picker — if other popups start using side content with intentional backgrounds they'll need to opt in explicitly. Not a real risk today, just a note for future callers.

Add subtle RGB background tints on diff lines that adapt to terminal
background lightness. Dark terminals get #212922 (green) for additions
and #3C170F (red) for removals; light terminals get GitHub-style
pastel tints with contrasting gutter backgrounds. Use Color::Rgb
directly instead of best_color to avoid supports_color detection
issues in the TUI alternate screen. Refactor diff styling into a
DiffTheme enum with per-kind style helpers for line backgrounds,
gutter, sign characters, and content.
Copilot AI review requested due to automatic review settings February 23, 2026 15:30
Copy link
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.

Pull request overview

Adds theme-aware diff rendering in the TUI by selecting a light/dark palette from the terminal background and applying full-width background tints plus improved gutter/sign styling for diff lines.

Changes:

  • Introduces a DiffTheme (Light/Dark) derived from default_bg() and is_light().
  • Adds RGB palette constants and style helpers to drive gutter/sign/content/background styling per (theme, DiffLineType).
  • Applies line-level background styling via RtLine::style() and adds unit tests for light/dark styling and wrapped lines.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add `preserve_side_content_bg` to `SelectionViewParams` and gate the
side-panel background reset in `ListSelectionView` behind that flag.
This keeps existing popup behavior unchanged by default.

Enable the flag for `theme_picker` so preview rows rendered via
`push_wrapped_diff_line*` keep their add/delete background fills, matching
recent theme-aware diff rendering updates.
Use fixed add/delete palette pairs per terminal color capability in diff
rendering and theme picker previews. The renderer now chooses explicit
colors for truecolor, 256-color, and 16-color modes instead of
nearest-color quantization for these backgrounds.

This keeps insertion and deletion backgrounds visually distinct in
256-color terminals (including tmux/xterm-256color sessions) and keeps
preview styling aligned with live diff rendering.
@fcoury fcoury changed the title feat(tui): add theme-aware background colors to diff lines feat(tui): add theme-aware diff backgrounds with capability-graded palettes Feb 23, 2026
@fcoury
Copy link
Contributor Author

fcoury commented Feb 23, 2026

@codex review

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d05106691f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Collaborator

@etraut-openai etraut-openai left a comment

Choose a reason for hiding this comment

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

I like this solution.

The code lgtm. Codex left one code review comment that looks potentially legit. Please review and optionally fix that before merging.

@fcoury
Copy link
Contributor Author

fcoury commented Feb 23, 2026

The code lgtm. Codex left one code review comment that looks potentially legit. Please review and optionally fix that before merging.

I am on it.

@fcoury
Copy link
Contributor Author

fcoury commented Feb 23, 2026

@codex review

@chatgpt-codex-connector
Copy link
Contributor

Codex Review: Didn't find any major issues. Nice work!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@etraut-openai etraut-openai merged commit 061d1d3 into openai:main Feb 24, 2026
27 of 33 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Feb 24, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants