fix: detect color support for xterm-* TERM values (xterm-color, xterm-kitty)#318
fix: detect color support for xterm-* TERM values (xterm-color, xterm-kitty)#318Sanjays2402 wants to merge 1 commit into
Conversation
…-kitty)
`ColorSupport.from_env()` matched the `xterm` TERM value with an exact
equality check (`value == 'xterm'`), so any decorated variant such as
`xterm-color`, `xterm-16color`, `xterm-kitty` or `xterm-ghostty` fell
through to `NONE` and rendered without any color at all.
This contradicted three things:
- the method's own docstring, which states "If they contain `xterm`, we
will enable 16 color support";
- the sibling branch immediately above, which already uses containment
(`'256' in value`); and
- `is_ansi_terminal()`, whose `ANSI_TERM_RE` matches `^xterm` as a
prefix, so `is_ansi_terminal('xterm-color')` was True while
`from_env()` reported no color support for the same terminal.
Switch the check to `'xterm' in value` so every `xterm-*` variant gets
at least 16-color support. The `256` branch runs first, so
`xterm-256color` still resolves to `XTERM_256`.
Add `test_color_support_from_env_term` asserting the mapping for bare
`xterm`, the previously-broken `xterm-*` variants, and the `256` cases.
It fails on the four variant cases before the fix and passes after.
There was a problem hiding this comment.
Code Review
This pull request updates the color support detection in progressbar/env.py to check if 'xterm' is contained within the environment variable value instead of performing an exact match, and adds corresponding unit tests in tests/test_color.py. The review feedback suggests making the 'xterm' check case-insensitive by using value.lower() and adding an uppercase test case to verify this behavior.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| elif '256' in value: | ||
| support = max(cls.XTERM_256, support) | ||
| elif value == 'xterm': | ||
| elif 'xterm' in value: |
There was a problem hiding this comment.
The environment variable check for 'xterm' is case-sensitive. Since terminal environment variables (like TERM or COLORTERM) can sometimes be set in uppercase or mixed case (e.g., XTERM, Xterm), it is safer to perform a case-insensitive check by lowercasing the value before checking.
| elif 'xterm' in value: | |
| elif 'xterm' in value.lower(): |
| ('xterm', env.ColorSupport.XTERM), | ||
| ('xterm-color', env.ColorSupport.XTERM), | ||
| ('xterm-16color', env.ColorSupport.XTERM), | ||
| ('xterm-kitty', env.ColorSupport.XTERM), | ||
| ('xterm-ghostty', env.ColorSupport.XTERM), |
There was a problem hiding this comment.
To ensure that case-insensitive terminal names (like XTERM) are correctly supported, we should add a test case with uppercase characters.
| ('xterm', env.ColorSupport.XTERM), | |
| ('xterm-color', env.ColorSupport.XTERM), | |
| ('xterm-16color', env.ColorSupport.XTERM), | |
| ('xterm-kitty', env.ColorSupport.XTERM), | |
| ('xterm-ghostty', env.ColorSupport.XTERM), | |
| ('xterm', env.ColorSupport.XTERM), | |
| ('XTERM', env.ColorSupport.XTERM), | |
| ('xterm-color', env.ColorSupport.XTERM), | |
| ('xterm-16color', env.ColorSupport.XTERM), | |
| ('xterm-kitty', env.ColorSupport.XTERM), | |
| ('xterm-ghostty', env.ColorSupport.XTERM), |
What
ColorSupport.from_env()only recognised the bareTERM=xtermvalue. Any decorated variant —xterm-color,xterm-16color,xterm-kitty,xterm-ghostty, … — fell through toColorSupport.NONEand the progress bar rendered without any color at all.Root cause
The
xtermbranch used an exact-equality check while its sibling256branch uses containment:This is inconsistent with three things in the same codebase:
xterm, we will enable 16 color support." (containment, not equality)'256' in value.is_ansi_terminal(), whoseANSI_TERM_RE = ^([xe]|bv)term…matchesxtermas a prefix. So the two public entry points disagreed:TERMis_ansi_terminal()from_env()beforefrom_env()afterxtermXTERMXTERMxterm-colorNONEXTERMxterm-16colorNONEXTERMxterm-kittyNONEXTERMxterm-ghosttyNONEXTERMxterm-256colorXTERM_256XTERM_256from_env()gates all color output —Color.ansi(interminal/base.py) returnsNonewhenCOLOR_SUPPORT is NONE— so this silently disabled color for a large class of extremely common real-world terminals.Fix
One-line change:
value == 'xterm'→'xterm' in value. The256branch is checked first, soxterm-256colorstill resolves toXTERM_256; only values that would otherwise have beenNONEare promoted toXTERM(16-color), matching the documented contract.Test
Added
test_color_support_from_env_term, which asserts the resolvedColorSupportfor barexterm, the previously-brokenxterm-*variants, and the256cases (so the ordering guarantee is locked in too).Proof it guards the bug (stash the source fix, run the test):
Full
tests/test_color.py+tests/test_utils.py= 100 passed (both orders), broader suite 463 passed, 12 skipped — no regressions.ruff checkandruff format --checkclean on both changed files.+27 / -1.