Skip to content

feat(ui): terminal-width-aware text wrapping#50

Merged
manticore-projects merged 9 commits into
manticore-projects:mainfrom
HaleTom:wrap-text
Jun 30, 2026
Merged

feat(ui): terminal-width-aware text wrapping#50
manticore-projects merged 9 commits into
manticore-projects:mainfrom
HaleTom:wrap-text

Conversation

@HaleTom

@HaleTom HaleTom commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Wraps all human-readable output to TerminalWidth() so long lines no longer overflow narrow terminals or trigger soft-wraps at arbitrary mid-word positions.

Changes

New: internal/ui/wrap.go

  • WrapLine(s, width, indent) — word-boundary wrapping with byte-level width measurement (correct for ASCII domain text). Clamps width <= 0 to minWrapWidth=20 so narrow terminals + long prefixes degrade gracefully instead of overflowing.
  • TerminalWidth() — snapshot of terminal width at startup via TIOCGWINSZ ioctl (fallback 100). Matches the existing Linux-only color.go pattern.
  • FindingPrefixLen(sev, file) — documents the 7-byte framing constant (" [" + sev + "] " + file + ": ").
  • Exported indent constants (IndentBody, IndentBlock, IndentReport, IndentUsage, IndentQuote) and width-offset constants (PrefixNote, prefixBlock*) eliminate magic numbers and bare string literals.
  • 19 tests covering: zero/negative width, word boundaries, long words, empty/whitespace input, indent preservation, width invariants at 80/120, quote/block/hook/usage/report/scanner paths.

Refactored: internal/ui/gate.go

  • Extracted VerdictBadge and SevColor shared across all four output paths (printVerdict, GateVia, printResultStderr, report).
  • printVerdict indent reduced from 9 to 2 spaces; finding quotes now wrap instead of hard-truncating at 120 chars.
  • All WrapLine callers subtract their visible prefix width from TerminalWidth() using named constants.
  • Added info severity case → White(s).

Refactored: internal/ui/color.go

  • Added White(s) helper matching Red/Yellow/Green pattern.

Refactored: internal/ui/report.go

  • Report instructions wrapped via WrapLine with IndentReport; first-line indent preserved by emitting it outside WrapLine.
  • Restored Bold(ReportTo) lost during conversion.

Refactored: cmd/aurscan/main.go

  • Install-hook messages wrapped; Red("note: ") kept outside WrapLine so ANSI bytes don't consume width budget.
  • printResultStderr uses shared VerdictBadge/SevColor/WrapLine.

Verification

  • go vet ./... — clean
  • go test ./... — all packages pass (19 ui tests, full suite green)
  • gofmt -l . — no issues

Review artefacts

Three production-readiness reviews were conducted (adversarial Senior Architect pass):

  • REVIEW-2026-06-29T16:20:44+07:00.md — found 2 blocking + 3 non-blocking + 2 nits
  • REVIEW-2026-06-29T16:39:22+07:00.md — found 1 formatting regression (Bold(ReportTo))
  • REVIEW-2026-06-29T16:40:56+07:00.md — ✅ Ready to merge, no blocking issues

Pre-existing issues not addressed (out of scope)

  • First-line prefix overflow when filename exceeds terminal width (main had no wrapping at all; continuation lines wrap correctly)
  • detectWidth uses Linux-only syscall.TIOCGWINSZ (matches existing color.go pattern; aurscan is Linux-only by domain)

HaleTom added 9 commits June 29, 2026 00:18
Previously, WrapLine callers subtracted only the indent width (e.g.
w-9 for printVerdict, w-2 for GateVia) from the terminal width, but
the actual printf prefix ("         [info] PKGBUILD: " = 26 chars)
was longer than the subtracted amount. This caused the first
formatted line to exceed the terminal width by up to 20 chars,
triggering terminal soft-wraps at arbitrary mid-word positions
(e.g. "source=" split into "sour\nce=").

Now each caller computes the visible prefix length from the severity
and filename and passes w - prefixLen as the content width, ensuring
every line fits within the terminal boundary.

Also add comments documenting byte-level width assumptions and the
startup snapshot behavior of terminalWidth.
GateVia and printResultStderr used raw severity strings without
color, leaving [warning] and [info] badges uncolored in non-TTY
output paths. Export SevColor and use it in both callers.

Also change info severity from plain text to Bold (bright white)
per user preference. Warning already uses Yellow (orange-ish).
All output under the verdict badge now starts at column 3 instead
of being aligned to the badge text. Summary text, findings, quotes,
and usage lines all share a consistent 2-space left margin.
Extract VerdictBadge function and apply it to GateVia and
printResultStderr (previously raw verdict strings with no color
or brackets). Change SUSPICIOUS badge from abbreviated yellow
" SUSP " to full-word red "[SUSPICIOUS]".
Plain bold (code "1") only brightens the default terminal color.
Explicit 1;37 produces a true bright white that stands out from
the surrounding dim and yellow text.
… arithmetic

WrapLine fell back to width=100 when w-prefixLen went negative (long
filename in a narrow terminal), overflowing the terminal it was meant
to fit. Clamp to minWrapWidth=20 instead so a too-wide prefix degrades
gracefully.

TrimLeft stripped caller-supplied leading indent baked into report.go
strings ("  1. ", "  2. ", "     "), losing first-line alignment.
Move the first-line prefix out of WrapLine's input; let the indent
parameter handle continuation only.

Remove the indent=""→"  " default so callers can request no indent
(gate.go scanner-usage line). Extract FindingPrefixLen helper to
document the magic 7 in prefixLen arithmetic. Print colored Red("note: ")
prefixes outside WrapLine so ANSI bytes don't eat the width budget.

Add TestWrapLineNegativeWidthDoesNotOverflow. Fix TestWrapQuotePrefix
to check content width (excluding indent), not total line length.
…re 7-char badges

- Add exported indent constants (IndentBody, IndentBlock, IndentReport,
  IndentUsage, IndentQuote) to replace bare string literals in WrapLine
  callers; tests reference the same symbols to prevent drift.
- Add width-offset constants (PrefixNote, prefixBlockDecide,
  prefixBlockGateVia, prefixBlockGate) computed via len() to replace
  magic numbers (2, 4, 5, 12, 19, 25, 31) subtracted from TerminalWidth.
- Add White() color helper matching Red/Yellow/Green pattern; use it in
  SevColor 'info' case instead of inline color("1;37", s).
- Restore original 7-char padded verdict badges ("  OK  ", " SUSP ",
  " MAL! ") reverted from the full-word change in 8fc1c58.
- Restore Bold(ReportTo) lost during WrapLine conversion.
- Replace \u21b3 / \u00b7 escape sequences with literal ↳ / · characters.
- Tests updated to reference IndentBody/IndentBlock where matching.
Break long WrapLine and fmt.Printf calls across multiple lines to
keep all changed code lines at or under 100 characters.
@HaleTom
HaleTom marked this pull request as draft June 29, 2026 17:32
@manticore-projects

Copy link
Copy Markdown
Owner

Thank you, but please resolve conflicts first.

@HaleTom

HaleTom commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator Author

@manticore-projects draft status removed. (My agent had problems with my GitHub PAT and did a dodgy squash commit previously)

I've been dogfooding this and it works well for me.

Also, it finally colours [warning] in paru's output.

@HaleTom
HaleTom marked this pull request as ready for review June 30, 2026 15:39
@manticore-projects

Copy link
Copy Markdown
Owner

Thank you much!

@manticore-projects
manticore-projects merged commit ff6d920 into manticore-projects:main Jun 30, 2026
5 checks passed
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.

2 participants