Skip to content

feat(spreadsheet): write a cell of several runs - #870

Merged
andiwand merged 1 commit into
mainfrom
feat/sheet-rich-cells
Sep 9, 2026
Merged

feat(spreadsheet): write a cell of several runs#870
andiwand merged 1 commit into
mainfrom
feat/sheet-rich-cells

Conversation

@andiwand

@andiwand andiwand commented Sep 9, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Rebased on main now that #869 has landed. Step 2.3 of docs/design/spreadsheet-editing.md, and the last of step 2.

What it does

A cell whose paragraph held several runs was locked rich, because the write went through one text run and would have lost the others. What it loses is the formatting of a text the user is replacing anyway, which is what every spreadsheet does.

text_run_of descends through a single span before it looks for the run, so a cell that holds one run writes through it and that run keeps its style — the same walk spreadsheet.js::runOf makes over the page, which is what keeps the two showing the same thing. Where the paragraph holds several runs they are replaced by one, and the elements over the old children keep their ids and stop being reachable, as the xlsx write already did.

The rich lock stays on what a write would take away without the user seeing it go: a link, whose target is not what the cell shows, and a line break or several paragraphs, which are a second line the overlay cannot write.

xlsx needed no engine change — sheet_set_cell rewrites the whole c — so the lock alone changes there.

One thing worth knowing

Rebuilding a paragraph removes its old children from the dom while their elements keep their ids. Those elements' pugi::xml_node dangles from then on, which is the cost ooxml/spreadsheet already pays for the same tombstoning, and it is now written down in odf/AGENTS.md. Nothing reaches them through the tree; an Element handle taken before the write would.

Reference output

The pins are not advanced in this pull request. 1876 cells over 37 files lose data-odr-lock="rich" and its odr-locked class; every changed line in a local regeneration is one of those <td>s and nothing else. CI is green either way, because .odr-locked only sets a cursor and only under .odr-editing, so no pixel moves. The regeneration goes with the merge.

Test

OdfSheetWrite gains four cases: several runs written, one span kept, and a link and a line break that still refuse. OoxmlSpreadsheetWrite gains the rich inlineStr cell. html_test gains the cell of several runs that carries no lock and the link that is locked rich.

test/browser/sheet/editing.html held its rich cell as two runs; it holds a link now. All four sheet check pages pass in headless Chrome — 51, 14, 20 and 8 checks, none failed.

https://claude.ai/code/session_01KKFKbUVCYF2VhujdmjhhPW

@andiwand
andiwand force-pushed the feat/sheet-grow-xlsx branch from fdc77f2 to 64210bb Compare September 9, 2026 18:36
@andiwand
andiwand force-pushed the feat/sheet-rich-cells branch from 94fc6a5 to e4f08f0 Compare September 9, 2026 18:36
@andiwand
andiwand force-pushed the feat/sheet-grow-xlsx branch from 64210bb to 1b8e95e Compare September 9, 2026 19:42
@andiwand
andiwand force-pushed the feat/sheet-rich-cells branch from e4f08f0 to b1f41d2 Compare September 9, 2026 19:42
@andiwand
andiwand force-pushed the feat/sheet-grow-xlsx branch from 1b8e95e to 51aec1f Compare September 9, 2026 20:22
Base automatically changed from feat/sheet-grow-xlsx to main September 9, 2026 20:31
A cell whose paragraph held several runs was locked `rich`, because the
write went through one text run and would have lost the others. What it
loses is the formatting of a text the user is replacing anyway, which is
what every spreadsheet does.

`text_run_of` descends through a single span before it looks for the run,
so a cell that holds one run writes through it and keeps its style - the
same walk `spreadsheet.js::runOf` makes over the page, which is what
keeps the two showing the same thing. Where the paragraph holds several
runs, they are replaced by one, and the elements over the old children
keep their ids and stop being reachable, as the xlsx write already did.

The `rich` lock stays on what a write would take away without the user
seeing it go: a link, whose target is not what the cell shows, and a line
break or several paragraphs, which are a second line the overlay cannot
write.

xlsx needed no engine change - `sheet_set_cell` rewrites the whole `c` -
so the lock alone changes there.

1876 cells over 37 files lose the lock in the reference output. The pins
are not advanced here; the regeneration goes with the merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKFKbUVCYF2VhujdmjhhPW
@andiwand
andiwand force-pushed the feat/sheet-rich-cells branch from b1f41d2 to 99db1dc Compare September 9, 2026 20:36
@andiwand
andiwand merged commit 8141e37 into main Sep 9, 2026
25 checks passed
@andiwand
andiwand deleted the feat/sheet-rich-cells branch September 9, 2026 20:38
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