Skip to content

fix(cli): remove theme background fills from input box and user messages#5772

Merged
chiga0 merged 1 commit into
QwenLM:mainfrom
chiga0:fix/input-bg-color-error
Jun 23, 2026
Merged

fix(cli): remove theme background fills from input box and user messages#5772
chiga0 merged 1 commit into
QwenLM:mainfrom
chiga0:fix/input-bg-color-error

Conversation

@chiga0

@chiga0 chiga0 commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

The TUI paints no background of its own and relies on the terminal's own background. Two elements broke that and rendered as off-colour blocks that cannot be made consistent across terminals and themes, so this PR removes both.

Fixes #5771.

The two offenders

  1. Input box (BaseTextInput, since fix(cli): fill content area background on wrapped input lines #5568) flood-filled theme.background.primary. Even when the theme's light/dark bucket matched the terminal (the fix(cli): only paint theme background when it matches the terminal #5746 gate), the exact colour usually differed from the terminal's real background, so the prompt rendered as a distinct off-colour block — worst over SSH/remote where brightness detection is unreliable and defaults to dark.

  2. User-message half-line band (UserMessage, since fix(tui): Tighten message and tool spacing #4595) painted a subtleBandColor band behind each user message, gated on the same theme/terminal match. Because history is rendered through Ink <Static> (committed rows are never repainted) and the gate only fires when the active theme matches the terminal, the band appeared on some messages but not others across a theme switch — see below.

Why the band can't be consistent

themeBackgroundMatchesTerminal() only paints the band when the active theme's brightness matches the terminal. On a dark terminal: qwen-dark messages get the band, qwen-light messages don't. And <Static> means a theme switch never repaints already-committed messages, so a single screen can show banded and un-banded user messages side by side.

What changed

  • BaseTextInput.tsx: drop the backgroundColor fill on the input content area.
  • ConversationMessages.tsx: UserMessage no longer paints a band; it renders directly on the terminal background and falls back to marginTop={1} for separation (consistent across all themes).
  • theme-background.ts: remove the now-unused getInputBackgroundFill / themeBackgroundMatchesTerminal; replace getEffectiveInputBackground with getEffectiveTerminalBackground, which derives a brightness-representative colour purely from the terminal's detected dark/light type.
  • software-cursor.ts: the software cursor derives its contrast from getEffectiveTerminalBackground() so it stays visible now that no fill is painted.
  • color-utils.ts: remove the band's now-unused subtleBandColor / supportsTrueColor helpers (added by fix(tui): Tighten message and tool spacing #4595), plus the dead UserMessageProps.width prop and its call site in HistoryItemDisplay. The generic interpolateColor primitive is kept.

Tests

  • Rewrote theme-background.test.ts for getEffectiveTerminalBackground (terminal-derived, theme-independent).
  • Updated software-cursor.test.ts default-contrast cases to assert terminal-derived cursor contrast.
  • BaseTextInput / ConversationMessages / HistoryItemDisplay suites pass (they assert text content, not fills).

Trade-off

This removes the user-message half-line band introduced in #4595 along with its tighter spacing; user messages revert to a single marginTop line for separation. That is intentional: consistent, background-free rendering across all terminals/themes was preferred over a band that only renders in matching theme/terminal combinations.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the PR, @chiga0! 👋

The PR body doesn't follow the pull request template. A few required sections are missing:

  • ## What this PR does and ## Why it's needed — your ## Summary and ## Why cover the content, but please use the exact template headings so reviewers can scan quickly.
  • ## Reviewer Test Plan — this is the big one. It needs ### How to verify (steps a reviewer can follow), ### Evidence (Before & After) (screenshots or tmux output showing the color block before and after the fix), and ### Tested on (OS matrix). Since this is a visual/TUI change, before-and-after evidence is essential for reviewers to confirm the fix without running it themselves.
  • ## Risk & Scope — main risk, what's out of scope, any breaking changes.
  • ## Linked Issues — you mention "Fixes #5771" in the body (which is great), but please put it in the dedicated section.

Could you update the PR description to match the template? The content is already there — it mostly just needs reorganizing under the right headings, plus the test plan and evidence sections. Happy to take another look once that's done. 🙏

中文说明

感谢 PR,@chiga0!👋

PR 描述没有按照 pull request 模板 来写,缺少几个必填部分:

  • ## What this PR does## Why it's needed — 你的 ## Summary## Why 内容都有了,但请使用模板中的确切标题,方便审查者快速浏览。
  • ## Reviewer Test Plan — 这是最重要的部分。需要包含 ### How to verify(审查者可以跟随的步骤)、### Evidence (Before & After)(截图或 tmux 输出,展示修复前后的色块对比)和 ### Tested on(操作系统矩阵)。因为这是视觉/TUI 变更,前后对比证据对审查者确认修复效果至关重要。
  • ## Risk & Scope — 主要风险、不在范围内的内容、是否有破坏性变更。
  • ## Linked Issues — 你在正文提到了 "Fixes #5771"(很好),但请放在专门的章节里。

能否按照模板更新一下 PR 描述?内容基本都有了,主要是重新组织到正确的标题下,再加上测试计划和证据部分。更新后我会再看一次。🙏

Qwen Code · qwen3.7-max

@chiga0
chiga0 force-pushed the fix/input-bg-color-error branch from bd4d387 to 18e368a Compare June 23, 2026 11:59
@chiga0 chiga0 changed the title fix(cli): stop painting input box & user-message background fill fix(cli): drop input box & user-message background fills Jun 23, 2026
@chiga0 chiga0 changed the title fix(cli): drop input box & user-message background fills fix(cli): remove theme background fills from input box and user messages Jun 23, 2026
@chiga0
chiga0 requested a review from wenshao June 23, 2026 12:21

@chiga0 chiga0 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Overview

Final Verdict: LGTM — Clean, focused bug fix. The approach is correct: since the TUI never paints its own background, the two flood-fills (input box and user-message band) were inherently inconsistent across terminals and themes. Removing them and letting everything render on the terminal's own background is the right fix.

Cross-Validation

# Finding Reviewer My Assessment
C1 PR template format (missing ## What this PR does / ## Why it's needed sections) qwen-code-ci-bot Format issue, not code — the PR body has equivalent content under different headings (## Summary, ## What was wrong). Non-blocking for code quality.

No unique Critical, Major, or Minor findings from my independent review.

Additional Audit Coverage

Areas I independently verified beyond existing findings:

  • Cursor visibility: getEffectiveTerminalBackground() returns #000000 (dark) or #ffffff (light) based solely on terminal type. Software cursor derives contrast from this — light cursor on dark terminal, dark cursor on light terminal. Correct regardless of active theme.
  • UserMessage width prop: The simplified component no longer destructures width. Callers passing width are unaffected (extra props are ignored). The fallback marginTop={1} provides consistent visual separation without background dependency.
  • <Static> commit issue: The PR description correctly identifies that <Static> commits rows and never repaints, making the band inconsistent across theme switches. This is a fundamental limitation that cannot be worked around — removing the band is the only correct fix.
  • Custom/ANSI themes: getTerminalBackgroundType() returns 'dark' by default for unclassified themes. getEffectiveTerminalBackground() returns #000000 in this case — cursor gets light contrast. Safe default.
  • Test coverage: 3 tests for getEffectiveTerminalBackground (light terminal, dark terminal, theme-independent). 3 tests for software cursor contrast (dark terminal, light terminal, theme-agnostic). Comprehensive for the scope.
  • Net deletion (+53/-216): Confirms this is a simplification, not a replacement. No hidden behavior changes.

This review was generated by QoderWork AI

The TUI paints no background of its own and relies on the terminal's own
background. Two elements broke that and rendered as off-colour blocks that
could not be made consistent across terminals and themes:

- The input box (QwenLM#5568) flood-filled theme.background.primary. Even when
  the theme's light/dark bucket matched the terminal (the QwenLM#5746 gate), the
  exact colour usually differed from the terminal's real background, so the
  prompt rendered as a distinct block — worst over SSH/remote where
  brightness detection is unreliable and defaults to dark.

- The user-message half-line band (QwenLM#4595) painted a subtleBandColor band
  behind each user message, gated on the same theme/terminal match. Because
  history is rendered through Ink <Static> (committed rows are never
  repainted) and the gate only fires when the active theme matches the
  terminal, the band showed on some messages but not others across a theme
  switch — it cannot be made consistent.

Stop painting both so the input area and user messages blend into the
terminal background everywhere. User messages fall back to marginTop=1 for
separation. The software cursor now derives its contrast from the
terminal's detected brightness (getEffectiveTerminalBackground) so it stays
visible with no fill painted.

Also remove the band's now-unused helpers — subtleBandColor and
supportsTrueColor (added by QwenLM#4595) and the dead UserMessageProps.width prop.

Fixes QwenLM#5771.

Generated with AI

Co-authored-by: Qwen-Coder <[email protected]>
@chiga0
chiga0 force-pushed the fix/input-bg-color-error branch from 18e368a to edc70f6 Compare June 23, 2026 12:37

@chiga0 chiga0 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No review findings. Downgraded from Approve to Comment: self-PR; CI still running. Clean removal — all dead code (width prop, subtleBandColor, supportsTrueColor) properly cleaned up, tests pass, cross-file references fully updated.

— qwen3.7-max via Qwen Code /review

@@ -205,70 +199,19 @@ const ContinuationMarkdownMessage: React.FC<
);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Suggestion] The simplified UserMessage only destructures { text }, but UserMessageProps (line 32) still declares width?: number and HistoryItemDisplay.tsx:237 still passes width={contentWidth} — the prop is silently ignored. Consider removing width from the interface and updating the caller so TypeScript enforces a clean contract.

— qwen3.7-max via Qwen Code /review

@yiliang114

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No new review findings. Clean, focused simplification — removes two background fills that could never match the terminal consistently, consolidates the helper into a single terminal-derived function, and tests are updated accordingly. All 23 relevant tests pass. Downgraded from Approve to Comment: CI still running.

— qwen3.7-max via Qwen Code /review

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. The removal is the right fix — the two flood-fills were never going to be consistent across terminals/themes, and deriving cursor contrast from the terminal type instead of the never-painted theme background is correct.

Verified on the PR branch:

  • All five removed symbols (getInputBackgroundFill, themeBackgroundMatchesTerminal, getEffectiveInputBackground, subtleBandColor, supportsTrueColor) have no remaining references anywhere in the repo, and no orphaned imports (Lint is green).
  • The only Ink UserMessage call site (HistoryItemDisplay) drops width too; the other <UserMessage>/<UserMessageBubble> matches are unrelated components in other packages.
  • Ran the affected suites locally — 76 passing (theme-background, software-cursor, color-utils, ConversationMessages, BaseTextInput, HistoryItemDisplay).

Two non-blocking notes:

  • interpolateColor no longer has any non-test caller now that subtleBandColor is gone — kept as a generic primitive, which is fine, just flagging it's currently dead outside its own test.
  • +1 on the bot's ask for Before/After evidence. For a visual change like this, a quick before/after (the off-colour block vs. clean background) is what lets reviewers confirm without running it.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR, @chiga0!

Template: the CI bot already flagged the missing headings — I won't duplicate that. The substance is all here.

On direction: solid. This fixes a real visual bug — the input box and user-message band render as off-colour blocks that can never be made consistent across terminals and themes. Removing the fills and letting everything render on the terminal's own background is exactly the right approach. It aligns with the TUI's core design principle of not painting its own background. Claude Code's CHANGELOG shows similar theme/rendering fixes have been a recurring pain point there too.

On approach: focused and minimal — net -238 lines across 9 files. Every change traces directly to the stated goal: remove the two fills, clean up the now-dead utilities (subtleBandColor, supportsTrueColor, getInputBackgroundFill, themeBackgroundMatchesTerminal), update the software cursor to derive contrast from the terminal rather than the never-painted theme background. No scope creep, no drive-by refactors. The intentional trade-off (losing the tighter band spacing in favour of consistent marginTop=1) is well-reasoned.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板:CI bot 已经指出缺少的标题,不重复了。内容都在。

方向:正确。修复了一个真实的视觉 bug —— 输入框和用户消息背景色块在不同终端/主题下无法一致。移除填充色、让内容直接渲染在终端背景上,完全符合 TUI 不绘制自身背景的核心设计原则。Claude Code 的 CHANGELOG 中也有类似的主题/渲染修复记录。

方案:精简且聚焦 —— 净减少 238 行,9 个文件。所有改动都直接服务于目标:移除两处填充、清理已废弃的工具函数、更新软件光标对比度来源。无范围蔓延,无顺手重构。放弃紧凑间距换取跨终端一致性的取舍合理。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Clean subtraction. I read the diff against my independent proposal (which was: remove the two backgroundColor fills, simplify UserMessage to always use the fallback path, delete dead helpers, update cursor contrast to derive from terminal type). The PR matches it exactly.

No correctness issues. The cascading clean-up is thorough: getInputBackgroundFill and themeBackgroundMatchesTerminal removed from theme-background.ts; subtleBandColor and supportsTrueColor removed from color-utils.ts; the dead width prop on UserMessageProps and its call site in HistoryItemDisplay cleaned up; useIsScreenReaderEnabled import removed from ConversationMessages.tsx since only the band path used it. All dead code paths properly pruned.

One observation worth noting (not a blocker): getEffectiveTerminalBackground() now returns only #000000 or #ffffff — pure stand-ins for dark/light. This is fine for cursor contrast calculations, but if anything ever needs a more precise terminal background colour, this function would need extending. The naming and comments make the intent clear, so this is just a note for future readers.

Testing

Unit tests: all 36 tests pass across the three changed test files (theme-background.test.ts, software-cursor.test.ts, color-utils.test.ts). Test updates are correct — assertions now verify terminal-derived values rather than theme-derived ones.

Interactive TUI — Before (installed build, v0.19.1):

   ▄▄▄▄▄▄  ▄▄     ▄▄ ▄▄▄▄▄▄▄ ▄▄▄    ▄▄   ┌──────────────────────────────────────────────────────────┐
  ██╔═══██╗██║    ██║██╔════╝████╗  ██║  │ >_ Qwen Code (v0.19.1)                                   │
  ██║   ██║██║ █╗ ██║█████╗  ██╔██╗ ██║  │                                                          │
  ██║▄▄ ██║██║███╗██║██╔══╝  ██║╚██╗██║  │ API Key | qwen3.7-max (/model to change)                 │
  ╚██████╔╝╚███╔███╔╝███████╗██║ ╚████║  │ ~/work/qwen-code/qwen-code                               │
   ╚══▀▀═╝  ╚══╝╚══╝ ╚══════╝╚═╝  ╚═══╝  └──────────────────────────────────────────────────────────┘

  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  > say hello in one sentence
  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

The ▄▄▄/▀▀▀ half-line band around the user message is clearly visible — this is exactly the subtleBandColor fill the PR removes.

Interactive TUI — After (PR code): could not run interactively. The build fails on both main and the PR branch with a pre-existing ink/dom and ink/components/CursorContext module resolution error (TS2307) — this is environmental, not introduced by the PR. Pipe mode (-p) doesn't render the TUI, so the visual change can't be verified that way either.

The code change is straightforward enough that the visual outcome is predictable: removing backgroundColor from the <Box> and the band rendering from UserMessage means both areas will render directly on the terminal background. No more off-colour blocks, no more inconsistent bands across theme switches.

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

This is a clean, well-scoped bug fix. The motivation is real — I confirmed the off-colour band rendering in the installed build's interactive TUI. The approach is the simplest possible fix: remove the two problematic fills entirely and let the terminal's own background do the work. Net -238 lines, no new abstractions, no scope creep.

The code reads like it was written by someone who understood the full blast radius of the removal. Every dead code path — subtleBandColor, supportsTrueColor, getInputBackgroundFill, themeBackgroundMatchesTerminal, the width prop, the screen-reader import — is properly cleaned up. Tests are rewritten, not just patched. The getEffectiveTerminalBackground rename from getEffectiveInputBackground is a good semantic improvement.

The trade-off (losing the tighter band spacing) is intentional and well-documented. Consistency across terminals beats aesthetic tightness that only works some of the time.

I couldn't run the PR code interactively due to a pre-existing build environment issue (ink/dom module resolution), but the unit tests all pass and the code change is mechanical enough that the visual outcome is predictable.

The template format issue flagged by the CI bot is minor — the substance is all there. Once the author addresses the heading format, this is ready.

LGTM ✅

中文说明

这是一个干净、范围合理的 bug 修复。动机真实 —— 我在已安装版本的交互 TUI 中确认了偏色背景带的渲染问题。方案是最简路径:完全移除两处有问题的填充色,让终端自身背景承担渲染。净减少 238 行,无新抽象,无范围蔓延。

代码清理彻底:所有废弃代码路径(subtleBandColorsupportsTrueColorgetInputBackgroundFillthemeBackgroundMatchesTerminalwidth 属性、屏幕阅读器导入)均已正确清理。测试是重写而非打补丁。getEffectiveTerminalBackground 的命名改进也有意义。

放弃紧凑间距换取跨终端一致性是有意为之且有文档记录的权衡。

由于构建环境的已有问题(ink/dom 模块解析)未能运行 PR 代码的交互测试,但所有单元测试通过,且代码改动足够机械化,视觉结果可预测。

CI bot 指出的模板格式问题是小问题 —— 实质内容都在。作者修正标题格式后即可合并。

可以合并 ✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@chiga0
chiga0 merged commit 7a1b244 into QwenLM:main Jun 23, 2026
45 checks passed
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.

Input box & user-message background fills render as inconsistent off-colour blocks across terminals/themes

3 participants