Skip to content

Phase 7: color by status and fit output to the terminal - #23

Open
loganthomas wants to merge 4 commits into
devfrom
phase-7-color
Open

loganthomas wants to merge 4 commits into
devfrom
phase-7-color

Conversation

@loganthomas

@loganthomas loganthomas commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Human output now uses color to mark status, and adapts to narrow terminals. Anything not going to a terminal stays byte-identical to before.

Color, status only. doctor's ok/warn/fail/info (green/yellow/red/dim), a dim cause: line and bold fix: label, locked/prunable tree states, pool slot states (free green, stale yellow, unprovisioned dim), a stale base in wt status, and a red wt: error prefix. Basic 16 ANSI colors, so the terminal theme decides the shades.

ui.color is now honored. It was parsed and validated but unused. auto defers to colorprofile for TTY/TERM/CLICOLOR_FORCE, but NO_COLOR is checked directly to the spec: colorprofile ignores it on non-terminals (so CLICOLOR_FORCE would win) and only counts boolean values. A broken global config reads as auto here, so color is never why a command fails.

Narrow terminals. Path columns in ls and status are middle-truncated (/Users/me/sr…-branch-name), but only when that makes the table fit; a table that overflows anyway keeps its full paths rather than losing characters for nothing. Doctor text wraps with a hanging indent. render.Align now measures display cells, so colored and plain cells align.

Table layout. ls and status get a dim header row and the path as the last column, with home shown as ~:

BRANCH         STATE         TOOLS  HEAD       AGE  PATH
main           clean         -      82506bc30  4d   ~/src/acme
feature/login  dirty,locked  stale  a08fe1242  2h   ~/src/acme.trees/feature-login

STATE is clean/dirty (one git status per tree, in parallel) plus git's locked/prunable; AGE is the HEAD commit's age (one git show for all heads); TOOLS shows whether the refresh hook is current, and appears only with a refresh_if_changed gate.

One listing command. wt pool ls is folded into wt ls: in pool mode, wt ls shows the trees outside the pool and every slot, provisioned or not, in one table:

TREE    LEASE    BRANCH       STATE  HEAD       AGE  NOTE      PATH
acme    -        main         clean  82506bc30  -    -         ~/src/acme
slot-1  claimed  feature/pay  dirty  a08fe1242  3h   pid 4242  ~/src/acme.trees/slot-1
slot-2  free     -            clean  878e4ca68  -    -         ~/src/acme.trees/slot-2

AGE is claim age there. wt status reuses the same slot table; wt pool keeps resize. JSON gains dirty, committed_at, tools, and on slot trees slot and lease (ls), and path, head, dirty, tools on status slots, each omitted when false or empty per the existing contract. --porcelain is unchanged. Error messages that pointed at wt pool ls now point at wt ls.

Tests. Golden files for ls, status, and doctor at color-80, plain-80 (also the NO_COLOR output), and plain-40; useColor cases for always/never/NO_COLOR/CLICOLOR_FORCE; FitColumn unit tests in a new file. Existing tests: formatter call sites gained their new arguments; the ls header changed two ls_test expectations (row count, one exact line), four script regexes follow the new column order, and the twelve exec wt pool ls lines now run wt ls. Each still asserts the same facts.

Also:

  • wt doctor's exit message said fixes were "listed above", which is wrong under --json (introduced in Phase 7: every error message names its fix #22, unreleased).
  • doctor's submodule and hooks-path causes no longer end in (R5)/(R7).
  • x/ansi and colorprofile are now direct imports. Both are lipgloss's own sub-packages and already in the build through huh, so no new module is added.

The help-text audit is the next PR.

"listed above" was wrong when the fixes are in the JSON payload.
Status-only color (doctor ok/warn/fail, tree and slot states, the
error prefix) behind ui.color, which until now was parsed but unused.
NO_COLOR is checked to the spec's letter, since colorprofile ignores
it on pipes. Narrow terminals middle-truncate path columns (only when
that makes the table fit) and wrap doctor text with a hanging indent.
render.Align measures display cells, so colored cells still align.
Non-terminal output is byte-identical to before. Also drops the R5/R7
plan IDs from doctor's user-facing text.
A dim header row; clean/dirty, HEAD, and age columns; a TOOLS column
(fresh/stale refresh gate) when refresh_if_changed is configured; the
path last with home shown as ~. Dirty state is one parallel git status
per tree, commit times one git show for all heads. LEASE leads the
slot table. JSON gains dirty, committed_at, tools (ls) and path, head,
dirty, tools (slots), each omitted when false or empty.
In pool mode wt ls now shows every tree and every slot in one table
(TREE LEASE BRANCH STATE [TOOLS] HEAD AGE NOTE PATH), so there is one
listing command in both modes. ls --json tags slot trees with slot and
lease; --porcelain is unchanged. Slot STATE uses the same clean/dirty,
locked, prunable spelling as default mode. Path truncation now stops at
24 cells: a slightly long row reads better than a mangled short path.
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.

1 participant