Skip to content

feat(cli): width-aware item-list table (TASK-2030)#894

Merged
xarmian merged 1 commit into
mainfrom
feat/cli-width-aware-item-table
Jul 10, 2026
Merged

feat(cli): width-aware item-list table (TASK-2030)#894
xarmian merged 1 commit into
mainfrom
feat/cli-width-aware-item-table

Conversation

@xarmian

@xarmian xarmian commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Rewrites PrintItemTable in internal/cli/format.go to be terminal-width-aware and ANSI-safe. Refs TASK-2030 (PLAN-1985).

The old renderer used text/tabwriter, which counts ANSI color escape bytes as visible width — so on a TTY (where fatih/color emits codes) the header misaligned by ~12 columns. It also had no terminal-width awareness (long titles blew out the layout) and surfaced a useless BY (modifier) column while omitting STATUS/PRIORITY.

Changes

  • Manual, ANSI-safe rendering replaces tabwriter for this function. All width math goes through a new displayWidth(s) helper that strips SGR escapes (\x1b[…m, compiled once as a package var) and counts runes.
  • Terminal-width aware: probes term.GetSize(os.Stdout.Fd()), falling back to 120 columns when piped/non-TTY. Only the title is truncated (with ); the ref is never truncated.
  • New columns / layout (DR-1): REF/TITLE · STATUS · PRIORITY · COLLECTION · UPDATED. Drops the BY column. STATUS/PRIORITY are parsed from the item's fields JSON and rendered via the existing ColorizedStatus / PriorityColor helpers (dim when absent).
  • Testability refactor: PrintItemTable now just probes width and delegates to an unexported renderItemTable(w io.Writer, items, maxWidth) core, tested against a bytes.Buffer with a fixed width.
  • Exported signature func PrintItemTable(items []models.Item) is unchanged; callers (cmd_item.go) are untouched.

Notes / decisions

  • Per-rune width is approximated as 1 column (emoji/CJK double-width is a documented, pre-existing limitation) — no new dependency, per task spec.
  • Narrow-terminal overflow (below ~44 cols) is the specified "degrade gracefully" behavior: ref + short columns are never truncated; titleBudget is floored at 0 and the flexible header obeys the same budget as data rows.
  • Titles carrying raw SGR escapes are stripped before measuring/truncating, so a title can never be sliced mid-escape and the width budget stays exact.

Gates

  • go build ./... — PASS
  • go vet ./... — PASS
  • make lint (golangci-lint) — PASS (0 issues)
  • go test ./internal/cli/... ./cmd/pad/... — PASS

Codex review

Verdict: CLEAN (4 rounds). Caught and fixed: header-not-fitting-budget in the degraded narrow regime, and mid-escape title slicing for titles containing embedded ANSI. The two originally-flagged scope items (rune-width approximation; narrow-terminal overflow) are explicitly accepted per the task/DR-1.

TASK-2030 (PLAN-1985). Manual ANSI-safe renderer replaces tabwriter; terminal-width-aware title truncation; drops the modifier BY column.
@xarmian xarmian merged commit 4d1034a into main Jul 10, 2026
3 of 4 checks passed
@xarmian xarmian deleted the feat/cli-width-aware-item-table branch July 10, 2026 01:47
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