Skip to content

fix(flow-chat): resolve diff card text truncation on long lines#1185

Merged
limityan merged 1 commit into
GCWing:mainfrom
limityan:fix/diff-card-text-wrapping
Jun 13, 2026
Merged

fix(flow-chat): resolve diff card text truncation on long lines#1185
limityan merged 1 commit into
GCWing:mainfrom
limityan:fix/diff-card-text-wrapping

Conversation

@limityan

Copy link
Copy Markdown
Collaborator

Problem

In the Chat interface, when a diff card renders a very long single-line change, the text beyond the first visual line is cut off and invisible.

Root Cause

InlineDiffPreview uses @tanstack/react-virtual for row virtualization with a fixed row height of 22px (estimateSize: () => ROW_HEIGHT). At the same time, CSS sets white-space: pre-wrap + word-break: break-word to allow text wrapping. These two are fundamentally incompatible:

  1. CSS wrapping folds long lines into multiple visual lines (real height > 22px)
  2. The virtualizer forces each row container to height: 22px
  3. overflow: hidden clips everything beyond 22px

Result: wrapped content is invisible.

Solution

1. Dynamic row measurement (core fix)

  • Configure the virtualizer with measureElement so each row reports its actual rendered height
  • Remove the hardcoded height: virtualRow.size from row containers
  • Apply ref={virtualizer.measureElement} + data-index to all row types (including context-separator)

2. Container resize handling

  • Add a ResizeObserver on the scroll container
  • When width changes, call virtualizer.measure() to invalidate cached heights and re-measure (wrapping depends on width)

3. Large diff truncation

  • Add truncateForDiff() with thresholds: 500 total lines or 50k total chars
  • When exceeded, keep head + tail portions with a ... truncated N lines ... marker
  • Show a visible truncation notice above the diff content
  • This bounds the cost of diffLines() and Prism.tokenize() for very large files

4. CSS cleanup

  • Replace overflow: hidden with overflow-wrap: anywhere on .diff-line__content
  • Remove redundant word-break: break-word (subsumed by overflow-wrap: anywhere)
  • Add .inline-diff-preview__truncation-notice style

Verification

  • pnpm run type-check:web — pass
  • pnpm run lint:web — pass (0 errors)

Files changed

  • src/web-ui/src/flow_chat/components/InlineDiffPreview.tsx
  • src/web-ui/src/flow_chat/components/InlineDiffPreview.scss

InlineDiffPreview used fixed-height virtualization rows (22px) while CSS
allowed text wrapping (pre-wrap). Wrapped content beyond 22px was hidden
by overflow:hidden, making long diff lines unreadable.

Changes:
- Switch virtualizer to dynamic measurement (measureElement) so wrapped
  rows report their real height instead of a fixed 22px estimate
- Add ResizeObserver to invalidate cached measurements when the container
  width changes (wrapping depends on width)
- Add content truncation for very large diffs (500 lines / 50k chars)
  with head+tail preview and a visible truncation notice
- Remove overflow:hidden on diff-line__content; use overflow-wrap:anywhere
- Apply measureElement ref to context-separator rows for measurement
  consistency
@limityan limityan merged commit 7892f7f into GCWing:main Jun 13, 2026
4 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.

1 participant