Skip to content

feat(web): global word-wrap toggle for code and diff views#985

Open
junmo-kim wants to merge 4 commits into
tiann:mainfrom
junmo-kim:feat/code-wrap-toggle
Open

feat(web): global word-wrap toggle for code and diff views#985
junmo-kim wants to merge 4 commits into
tiann:mainfrom
junmo-kim:feat/code-wrap-toggle

Conversation

@junmo-kim

@junmo-kim junmo-kim commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Fixes #905.

Problem

The web UI renders code blocks, unified diffs, and long tool output/input with horizontal scrolling only (overflow-x-auto). On narrow screens — Android PWA, phones — long lines run off the right edge and you have to scroll sideways to read them, which is awkward mid-conversation.

Solution

Add a word-wrap toggle next to the copy button in the code block header. The preference is stored globally in localStorage (hapi-code-wrap, default off), so one toggle applies to every code block, diff, and tool input/output at once, and it survives reloads.

To keep line numbers aligned when a line wraps, code blocks now render one grid row per logical line — a line-number cell and a code cell as siblings in the same row. When the code cell wraps, the row grows taller and the number stays pinned to the first visual line, matching the GitHub / VS Code gutter behavior. This replaces the previous two independent <pre> columns, whose separate text flows drifted out of alignment when wrapped. Rendering falls back to plain-text line splitting (with the same normalization) while highlighting is pending or the language is unsupported, so line numbers always match.

This PR also adds a lightly shaded gutter background behind the line numbers, consistent in light and dark themes, so the line-number column reads as a distinct gutter.

Default is off, so existing horizontal-scroll rendering is unchanged unless the user turns wrap on.

Usage

Click the wrap icon in any code block header. The setting is remembered across the session and all code/diff/tool views.

Wrap off (default) Wrap on
Light
Dark

Tests

  • Unit tests (vitest + Testing Library): useCodeWrap persistence + same-tab sync; per-line rendering (line count, wrap on/off, plain-text fallback); wrap-toggle suppression when a code block is nested inside an interactive ancestor (avoids nested <button>); <pre> preformatted semantics.
  • Manually verified end-to-end on desktop and mobile (390px) viewports, in light and dark themes.

Reviewing

Commits are split for review:

  1. refactor(web): add per-line shiki line-splitting helper
  2. feat(web): add global word-wrap toggle for code, markdown, and diff views
  3. feat(web): add a shaded gutter background behind line numbers

If the gutter background (commit 3) is out of scope for you, it drops cleanly on its own without touching the wrap feature.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Minor] Wrap-off is ignored for compact diff views — DiffView now reads the global wrap preference, but the compact branch still hard-codes whitespace-pre-wrap break-words. Most inline/preview diff call sites omit size="comfortable", so turning wrap off in a code block does not actually disable wrapping for those diffs. Evidence web/src/components/DiffView.tsx:229.
    Suggested fix:
    const shouldWrap = codeWrap
    
    const codeColumnTrack = shouldWrap ? 'minmax(0, 1fr)' : 'max-content'
    // ...
    codeWrap ? '' : 'overflow-x-auto'
    // ...
    cn(codeWrap ? 'w-full' : 'w-max min-w-full', isComfortable ? 'text-sm leading-6' : 'text-xs')
    // ...
    shouldWrap ? 'min-w-0 whitespace-pre-wrap break-words' : 'whitespace-pre'

Questions

  • None.

Summary

  • Review mode: initial
  • One wrap-preference consistency issue found in compact diff rendering.

Testing

  • Not run (automation): bun is not installed in this runner (bun: command not found).

HAPI Bot

Comment thread web/src/components/DiffView.tsx Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • None.

Questions

  • None.

Summary

  • Review mode: follow-up after new commits
  • No issues found in the latest full diff. The prior compact diff wrap-off consistency issue appears addressed. Residual risk: browser layout behavior was reviewed statically only in this runner.

Testing

  • Not run (automation): bun is not installed in this runner (bun: command not found).

HAPI Bot

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.

Mobile Web Terminal Output could wrap

1 participant