feat(ui): adaptive colors, terminal width handling, and review fixes#23
Merged
josephgoksu merged 3 commits intomainfrom Mar 8, 2026
Merged
feat(ui): adaptive colors, terminal width handling, and review fixes#23josephgoksu merged 3 commits intomainfrom
josephgoksu merged 3 commits intomainfrom
Conversation
…inal width handling
…ling - Restore ANSI escape for spinner line clearing instead of hardcoded 80-char width - Add post-clamp overflow redistribution in table column sizing - Extract GetTerminalWidthFor(f *os.File) to support non-stdout streams - Fix badge foreground contrast for light-mode terminals (white -> black) - Remove unused ColorTableRowEven/ColorTableRowOdd declarations - Guard overhead formula against empty widths slice - Move Supported Models section up in README
- Badge foreground: Light:255 (white) for dark backgrounds, Dark:0 (black) for bright backgrounds - Replace ColorText with dedicated neutral gray for "note" badge background
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
lipgloss.Colorliterals tolipgloss.AdaptiveColorfor light/dark terminal supportGetTerminalWidth()GetTerminalWidthFor(*os.File)to support non-stdout streamsColorTableRowEven/ColorTableRowOdddeclarationsTest plan
go build ./internal/ui/passesgo test ./internal/ui/— 24 tests passGreptile Summary
This PR delivers a broad UI quality pass: migrating ~40 hardcoded
lipgloss.Colorliterals tolipgloss.AdaptiveColor, adding terminal-width-aware column shrinking in the table renderer, and addressing six review items from PR #22. The architecture is sound and the direction is correct — theTerminalColorinterface widening inPanelandscoreToColoris the right way to expose adaptive colors through public APIs.Key issues found:
CategoryBadge(light mode): The badge foreground is set tolipgloss.AdaptiveColor{Light: "0", Dark: "0"}— black in both modes. In light-mode terminals, most badge backgrounds are dark or medium-dark (e.g.,ColorBlue.Light = "27"= dark blue,ColorSuccess.Light = "28"= dark green,ColorWarning.Light = "172"= dark orange), making black text on those backgrounds essentially unreadable. The fix should use{Light: "255", Dark: "0"}— white on dark backgrounds in light mode, black on bright backgrounds in dark mode."note"badge is invisible in light mode:ColorText(whose purpose is text foreground) hasLight = "235"(#262626 = near-black). Using it as a badge background combined with a black"0"foreground creates near-zero contrast.ColorTextshould not be a badge background color at all.padRightuses byte-lengthlen(s)instead of visual width: Pre-existing, but this is now a sharper issue since the new proportional shrinking produces tight column widths where off-by-one misalignments become visible.explain.go: The newGetTerminalWidth()utility was not applied to the explanation wrap width — a minor missed opportunity from the same PR.Confidence Score: 3/5
{Light: "0", Dark: "0"}makes many badge types unreadable in light mode. The"note"badge (black on near-black) is the most severe case. These are user-visible regressions in the specific feature this PR claims to fix.internal/ui/styles.go— specifically theCategoryBadgefunction's foreground color and the"note"key's mapping toColorTextas a background.Important Files Changed
AdaptiveColor; removes unusedColorTableRowEven/Odd; addsColorPurple/ColorBarEmpty. Critical bug: badge foreground is always"0"(black) in both light and dark modes, andColorText.Light="235"(near-black) is misused as the "note" badge background — both causing near-zero contrast in light mode.GetTerminalWidth(), post-clamp overflow redistribution, andGetTerminalWidthFor(*os.File)for non-stdout streams. Logic is sound;padRightuses byte-lengthlen(s)which is a pre-existing issue surfaced more acutely with tight column sizing.lipgloss.Colorliterals with named constants andAdaptiveColorpairs;scoreToColorreturn type correctly updated tolipgloss.TerminalColor. Clean refactor with no functional issues.StyleBoldwith lipgloss (respectsNO_COLOR); addslipglossimport. Minor: hardcoded 76-char wrap width not updated to use newGetTerminalWidth().Panel.BorderColorandWithBorderColorparameter type fromlipgloss.Colortolipgloss.TerminalColorto acceptAdaptiveColorvalues. Straightforward, correct interface widening.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Table.ColumnWidths] --> B{MaxWidth > 0?} B -- Yes --> C[Apply per-column MaxWidth cap] B -- No --> D[GetTerminalWidth via os.Stdout] D --> E[Compute overhead: 1 + len-1 * 2] E --> F{total > available?} F -- No --> G[Return widths as-is] F -- Yes --> H[Proportional shrink with min floor = 4] H --> I{Post-clamp: postTotal > available?} I -- Yes --> J[Find widest column] J --> K{widest > 4?} K -- No --> L[Break: table may overflow] K -- Yes --> M[Shrink widest by excess, floor 4] M --> I I -- No --> G subgraph Color System N[lipgloss.AdaptiveColor] --> O{Terminal Background} O -- Light --> P[Light value] O -- Dark --> Q[Dark value] P --> R[CategoryBadge foreground = 0 black] Q --> R R --> S{Badge BG in Light mode} S -- ColorText 235 near-black --> T[⚠ Near-zero contrast] S -- ColorBlue 27 dark blue --> T S -- ColorSuccess 28 dark green --> T endComments Outside Diff (2)
internal/ui/table.go, line 154-158 (link)padRightuses byte length, not visual (rune) widthlen(s)returns byte count, not visual column width. For multi-byte Unicode characters (e.g., the"…"ellipsis added during truncation, or any non-ASCII cell content),len(s)will exceed the visual width, causingpadRightto return early and produce misaligned columns.Concrete example: after truncation,
valends in"…"(3 UTF-8 bytes, 1 visual column).len(val)=widths[i]+2, sopadRightcorrectly skips padding in that case — but this depends on accidentally correct math. For other multi-byte characters in original cell values (e.g., emoji), column alignment would break silently.Consider using
lipgloss.Width(s)oruniseg.StringWidth(s)for accurate visual width measurements. This is a pre-existing limitation surfaced more sharply now thatColumnWidthsperforms terminal-width-aware shrinking (making tight column sizing more common).Prompt To Fix With AI
internal/ui/explain.go, line 119 (link)Hardcoded 76-char wrap width not updated to use
GetTerminalWidth()This PR adds
GetTerminalWidth()specifically for terminal-width-aware layout, butRenderExplainExplanationstill wraps at a hardcoded 76 characters. On narrow terminals (<80 cols) this can cause text to overflow, and on wide terminals it wastes readable width.The
-4accounts for the" "(3-space) prefix applied to each line below.Prompt To Fix With AI
Last reviewed commit: 3a83f9b