Skip to content

Collapse white space across style span and inline box boundaries - #25

Open
nicoburns wants to merge 9 commits into
mainfrom
devin/1788524905-collapse-whitespace-across-spans
Open

Collapse white space across style span and inline box boundaries#25
nicoburns wants to merge 9 commits into
mainfrom
devin/1788524905-collapse-whitespace-across-spans

Conversation

@nicoburns

@nicoburns nicoburns commented Sep 4, 2026

Copy link
Copy Markdown
Member

LLM Contributions: Unspecified.

Reworks phase-I white space processing in TreeStyleBuilder so collapsing happens over the whole inline formatting context, rather than independently per style span.

Current state vs. main

On main, push_uncommitted_text processes each span's text in isolation: it trims the start when the span is first (or the previous committed text ended in whitespace) and trims the end when the span is closing. A collapsible space at a span boundary therefore disappears, so <span>Hello </span>world builds as Helloworld.

The trimming is replaced with a single carried piece of state, pending_whitespace: Option<usize> (the span the whitespace came from). A collapsible whitespace run is not committed when it is seen; it is committed as a single space only once following content proves it renders, so it survives span and inline box boundaries but is still dropped where CSS Text says it should be:

  • at the start of the inline formatting context,
  • at the end of it (it simply never gets committed),
  • immediately before and immediately after a preserved segment break (phase-I rule 1), keyed off is_segment_break — this is what makes collapsible whitespace around <br> (a preserved "\n") disappear;
  • but not after a preserved space or tab, which main dropped too and browsers keep: <span style="white-space:pre">a </span> b is two spaces wide.

The committed space keeps the style of the span it came from, matching how browsers paint a boundary space, and adjacent runs with the same style are now merged instead of emitting a StyleRun per commit. Since soft wrap opportunities are determined before white space collapsing, pending_whitespace also records whether any of the collapsed white space came from a span that allows wrapping; if so the committed space uses that span's style with TextWrapMode::Wrap, so <span style="white-space:nowrap">AA </span> BB can still break where browsers break it.

Two supporting changes:

  • set_white_space_mode commits buffered text before switching, so text is processed under the mode in effect when it was pushed rather than the most recent one.
  • push_inline_box flushes pending whitespace (the box is the content the space collapses into, and the space must land before the box's index) and marks the last item kind, so whitespace after a leading box is not treated as start-of-IFC whitespace.

The collapse path also no longer builds a per-span String: it walks whitespace/non-whitespace runs and commits non-whitespace slices straight out of the buffer.

Out of scope: <br> is still encoded as a preserved "\n" rather than a dedicated forced-break item, phase-II trimming of collapsible whitespace at soft wrap points is unchanged, and hanging modes are untouched.

Changelog

Fixed

  • Collapsible white space is now collapsed across style span and inline box boundaries, instead of being trimmed at each span boundary, and is removed around preserved segment breaks. A space collapsed from white space in a wrappable span remains a soft wrap opportunity even when it is attributed to a nowrap span.

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/a9f0131145654530a87ad078d0d3c42b
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/a9f0131145654530a87ad078d0d3c42b?variant=devin-insiders
Requested by: @nicoburns

@staging-devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nicoburns
nicoburns force-pushed the devin/1788524905-collapse-whitespace-across-spans branch 2 times, most recently from 37f28d0 to 27e98c8 Compare September 8, 2026 15:56
@staging-devin-ai-integration staging-devin-ai-integration Bot changed the title Collapse whitespace across span and inline box boundaries Collapse white space across style span and inline box boundaries Sep 8, 2026
Remove collapsible whitespace immediately before and after a preserved
segment break, while keeping collapsible whitespace that follows a
preserved space or tab. Flush pending text when the white space mode
changes so it is processed with the mode in effect when it was pushed.
Split collapsible text into whitespace and non-whitespace runs and commit
the non-whitespace runs directly, rather than building a per-span copy of
the text with its whitespace collapsed.
Soft wrap opportunities are determined before white space collapsing, so
a collapsed space is a wrap opportunity if any of the whitespace it
collapses comes from a span that allows wrapping, even though the space
itself is attributed to the span it started in.
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