Completes #898 and fixes#1076.
Markdown on the seven surfaces left out of #1070, so `--format markdown` is now
honestly global and the flag help collapses to "table, json, markdown":
- `item comments`, `item deps`, `project activity`, `attachment list`,
`library list`, `role list`, `workspace members`.
Two of those are not tabular, and markdown follows the terminal shape rather
than forcing a table onto them:
- `item comments` keeps the attribution-line-then-body form, and the body is
emitted VERBATIM. A comment body is authored as markdown; escaping it would
turn its lists and code fences into literal text. Only the attribution line,
which we construct, is sanitized.
- `item deps` keeps its two sections as `## Blocks` / `## Blocked by` lists.
Colour carried the direction in the terminal (yellow out, red in); headings
carry it here.
New shared spine: `cli.RenderMarkdownTable(w, headers, rows)`. Every cell is
escaped, and ragged rows are padded or truncated to the header width so a short
or long row can't shift the column count and break the table. Wiring a surface
is now naming columns and mapping rows.
#1076 — ANSI stripping covered only SGR (`ESC[…m`), so non-SGR CSI sequences,
OSC-8 hyperlinks, and stray C0 controls survived, both in the table width maths
and in markdown output whose doc comment promised escape-free text. Replaced
`sgrPattern` with `ansiPattern` + `stripANSI` covering OSC, CSI, two-character
Fe escapes, and stray C0/DEL, with TAB/LF/CR deliberately preserved for callers
that normalize them. `displayWidth` now uses it too: a control sequence is
zero-width, so counting it was a column-alignment bug of the same family.
Tests: 12 stripping cases, 4 table-helper cases (including ragged rows), 4
renderer cases for the two non-tabular surfaces, and the routing test extended
to 8 subtests — one per surface, driven through cobra against an httptest
server. Also covers the two gaps named in #1076: `item starred` and the scoped
`item list <collection>` path. Each new guard was proven by mutating the source
and watching it fail, not just by passing.
Gates: go build ./... PASS; go vet PASS; gofmt clean; golangci-lint 0 issues.
Both touched packages show the same 6+2 pre-existing Windows failures as clean
main under an identical sandboxed run.
All three requested changes from @xarmian's review of #1070, plus both nits.
1. Escape backslashes before pipes in escapeMarkdownCell. A title containing
"\|" became "\|", which GFM reads as an escaped backslash followed by a LIVE
pipe, so the row still gained a column. Backslash-first turns it into "\\|".
Confirmed the bug with a failing test before fixing it.
2. Sanitize the group headings. Extracted SanitizeMarkdownText (SGR strip +
newline collapse) and ran the collection icon and name through it, so a
newline in a collection name can no longer inject a second "## " heading.
Sanitizing happens per part, before joining, because it trims and would
otherwise eat the separating space. Pipes are deliberately not escaped
outside a table.
3. Tightened the --format help to the precise enumeration:
"markdown on: item list/starred, collection list, item show, project changelog"
per option (a) on #898.
Nits:
- `item starred --format markdown` on an empty result now says "No starred
items." rather than the shared renderer's "No items found."; the empty check
moved above the format branch so both paths agree.
- Added format_markdown_routing_test.go: three end-to-end tests driving
`item list` and `collection list` through cobra against an httptest server,
asserting the markdown branch is actually reached and that the table and
markdown paths don't leak into each other. Proven by disabling the markdown
branch and watching the test fail. Follows the item_open_test.go pattern, with
USERPROFILE set alongside HOME since os.UserHomeDir reads USERPROFILE on
Windows — worth noting, as tests that set only HOME are why part of the
credential-store suite fails there.
Gates: go build ./... PASS; go vet PASS; gofmt clean; golangci-lint 0 issues;
all markdown tests PASS. Both touched packages show the same 6+2 pre-existing
Windows failures as clean main under an identical sandboxed run.
Implements `--format markdown` on the list commands that lacked it, so the
format is honestly global rather than honestly-partial (#898, the option (a)
follow-up to #851).
- `pad item list` — grouped `## Icon Name (N)` sections with a table each when
listing across collections (mirroring the table layout), a single table when
scoped to one collection. Heading style matches `project changelog`.
- `pad item starred` — single table.
- `pad collection list` — Name / Slug / Items / Default.
- `--format` help no longer carries the "markdown on select commands" caveat.
The markdown renderers deliberately do NOT reuse the colorized helpers
(ColorizedStatus, PriorityColor, Dim): markdown goes to a file, a PR body or an
agent's context, never a terminal, so raw values go in and the reader's renderer
styles them. Every cell is escaped — an unescaped `|` in a title silently adds a
column and corrupts the row.
Refs #898