Skip to content

fix: align trailing collapsible space handling across all line-break paths#29

Open
barry166 wants to merge 1 commit intochenglou:mainfrom
barry166:fix/trailing-collapsible-space-linecount
Open

fix: align trailing collapsible space handling across all line-break paths#29
barry166 wants to merge 1 commit intochenglou:mainfrom
barry166:fix/trailing-collapsible-space-linecount

Conversation

@barry166
Copy link
Copy Markdown

@barry166 barry166 commented Mar 30, 2026

Summary

Fixes #11layout() and layoutWithLines() return different lineCount for trailing collapsible spaces.

countPreparedLinesSimple (used by layout()) correctly skips collapsible spaces that overflow the line edge — CSS white-space: normal behavior where trailing spaces hang without triggering a break. The two walk-path counterparts were missing this guard:

  • walkPreparedLinesSimple (used by layoutWithLines() / walkLineRanges()) — canBreakAfter('space') triggered a spurious line break
  • layoutNextLineRangeSimple (used by layoutNextLine()) — same issue

The fix adds the isSimpleCollapsibleSpace check before canBreakAfter in both paths, matching the count path.

Reproduction

Any text where wordWidth + spaceWidth > maxWidth but wordWidth + nextSegmentWidth <= maxWidth:

// Before fix: layout() -> 1 line, layoutWithLines() -> 2 lines
// After fix:  both -> 1 line (CSS-correct)

Changes

  • src/line-break.ts — add isSimpleCollapsibleSpace guard in walkPreparedLinesSimple and layoutNextLineRangeSimple (+12 lines)
  • src/layout.test.ts — regression test with crafted segment data that directly triggers the divergence (+33 lines)

Test plan

  • bun test — 61/61 pass (including new regression test)
  • tsc --noEmit — 0 errors
  • oxlint --type-aware src — 0 warnings, 0 errors
  • Regression verified: reverting the line-break.ts fix causes the new test to fail (walked=2 vs counted=1)

…paths

countPreparedLinesSimple (used by layout()) correctly skips collapsible
spaces that overflow the line edge — CSS white-space: normal behavior
where trailing spaces hang without triggering a break.

walkPreparedLinesSimple (used by layoutWithLines/walkLineRanges) and
layoutNextLineRangeSimple (used by layoutNextLine) were missing this
guard, causing canBreakAfter('space') to trigger spurious line breaks
when word + space > maxWidth.

Add the isSimpleCollapsibleSpace check before the canBreakAfter check
in both walk paths to match the count path behavior.

Add a regression test with crafted segment data that directly triggers
the divergence condition (word=40 + space=5 > maxWidth=42, but
word=40 + next=1 <= 42).

Closes chenglou#11
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.

layout() and layoutWithLines() return different lineCount for trailing collapsible spaces

1 participant