Skip to content

[go-fan] Go Module Review: charm.land/lipgloss/v2Β #42929

Description

@github-actions

🐹 Go Fan Report: Lip Gloss v2

Module Overview

charm.land/lipgloss/v2 is Charm's declarative, CSS-like terminal styling library β€” colors, borders, padding/alignment, layout composition, plus the table, tree, and list sub-packages. It's the backbone of every human-facing surface in gh-aw. We're on v2.0.4, the latest release (2026-06-12) πŸŽ‰

Current Usage in gh-aw

gh-aw uses Lip Gloss idiomatically and keeps it well-centralized in pkg/styles.

  • Files: 8 non-test files
  • Import Count: 113 lipgloss.* references
  • Key APIs Used: NewStyle (55Γ—), Color (40Γ—), Style, border constructors (RoundedBorder/NormalBorder/DoubleBorder/...), Fprintf, LightDark, JoinVertical, HasDarkBackground, plus the table and tree sub-packages.
Where it lives
  • pkg/styles/theme.go β€” single source of truth: custom adaptiveColor type + Dracula-inspired palette + ~40 pre-built styles.
  • pkg/styles/huh_theme.go β€” maps the palette onto huh forms via lipgloss.LightDark(isDark).
  • pkg/console/console.go β€” helpers; uses lipgloss/v2/table, JoinVertical, borders, TTY-gated applyStyle.
  • pkg/cli/status_command.go, pkg/cli/mcp_inspect.go β€” lipgloss/v2/tree with EnumeratorStyle/ItemStyle.
  • pkg/cli/compile_schedule_calendar.go β€” hand-rolled schedule heatmap.
  • pkg/logger/logger.go β€” namespace coloring + lipgloss.Fprintf.

Research Findings

The big v2 story is that the global renderer and automatic color-profile detection were removed in v2.0.0. In v2, Style.Render emits ANSI at the style's declared color (truecolor for hex values) unconditionally β€” it does not consult NO_COLOR, TERM, or the terminal's actual color depth. Degradation is now the caller's responsibility via the github.com/charmbracelet/colorprofile package (a colorprofile.Writer reads os.Environ() and downgrades/strips ANSI).

Recent Updates

Best Practices

  • Route styled output through colorprofile.NewWriter(w, os.Environ()) β€” the canonical v2 replacement for v1's implicit renderer.
  • Use lipgloss.LightDark(isDark) for light/dark mapping (already done in huh_theme.go).

Improvement Opportunities

πŸƒ Quick Wins

  • compile_schedule_calendar.go:203 returns the zero value lipgloss.Style{} for the non-TTY branch, while every other site uses lipgloss.NewStyle(). Identical output β€” swap for NewStyle() for uniformity.
  • pkg/logger/logger.go hand-builds a 12-entry colorPalette with duplicated colors; deriving it from a smaller base slice would prevent drift.

✨ Feature Opportunities

  • Honor NO_COLOR and degrade color depth via colorprofile.Writer. Today, coloring is gated only on isTTY(). Consequences: (1) a user with NO_COLOR=1 on a TTY still gets ANSI, and (2) 16-/256-color terminals receive raw truecolor sequences. colorprofile is already an indirect dependency (v0.4.3) β€” wrapping the stdout/stderr write path with colorprofile.NewWriter(w, os.Environ()) would honor NO_COLOR/CLICOLOR_FORCE and auto-degrade, localized to the write path rather than each style. This is the highest-value item. 🎯

πŸ“ Best Practice Alignment

  • The custom adaptiveColor (theme.go) and v2's LightDark (huh_theme.go) coexist. Both are valid β€” adaptiveColor defers the light/dark choice to render time via a global, which is a deliberate, reasonable design. A one-line comment cross-referencing the two would help future contributors pick the right one.
  • The Windows HasDarkBackground guard is well-reasoned and now doubly covered by the v2.0.3 upstream fix β€” no change needed.

πŸ”§ General Improvements

  • If colorprofile.Writer is adopted, the styled boxes (RenderTitleBox, RenderErrorBox) render first and are written after, so the change stays confined to the write path β€” no per-style edits required.

Recommendations

  1. (High) Adopt a colorprofile.Writer on the stdout/stderr write path to honor NO_COLOR/CLICOLOR_FORCE and degrade truecolor for limited terminals.
  2. (Low) Normalize lipgloss.Style{} β†’ lipgloss.NewStyle() in compile_schedule_calendar.go.
  3. (Low) Add a cross-reference comment between adaptiveColor and LightDark.

Next Steps

  • Prototype a colorprofile-wrapped writer in pkg/console and verify NO_COLOR=1 suppresses ANSI while TTY truecolor is unchanged.
  • No version bump needed β€” already on latest v2.0.4.

Generated by Go Fan 🐹
Module summary saved to: scratchpad/mods/lipgloss.md

Generated by 🐹 Go Fan Β· 163.8 AIC Β· βŒ– 13.1 AIC Β· ⊞ 7.4K Β· β—·

  • expires on Jul 3, 2026, 12:58 AM UTC-08:00

Metadata

Metadata

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions