feat(spreadsheet): state the cell an xlsx file spells none of - #869
Open
andiwand wants to merge 1 commit into
Open
feat(spreadsheet): state the cell an xlsx file spells none of#869andiwand wants to merge 1 commit into
andiwand wants to merge 1 commit into
Conversation
andiwand
force-pushed
the
feat/sheet-grow-ods
branch
from
September 9, 2026 18:36
b1a34f0 to
0e4adc5
Compare
andiwand
force-pushed
the
feat/sheet-grow-xlsx
branch
from
September 9, 2026 18:36
fdc77f2 to
64210bb
Compare
andiwand
force-pushed
the
feat/sheet-grow-ods
branch
from
September 9, 2026 19:41
0e4adc5 to
9e6f87f
Compare
andiwand
force-pushed
the
feat/sheet-grow-xlsx
branch
from
September 9, 2026 19:42
64210bb to
1b8e95e
Compare
andiwand
force-pushed
the
feat/sheet-grow-ods
branch
from
September 9, 2026 20:11
9e6f87f to
4e73db9
Compare
An `.xlsx` file spells a `c` only for a cell that holds something, so a write into an empty position refused. The page carries no lock on such a cell, so the host got the refusal back after the user had typed. `insert_cell` states the `c` in its row in column order, and the `row` in `sheetData` in row order where the file states none, then widens `dimension` around the new cell. Nothing is reindexed: the cell map is keyed by position, so an insert touches one entry. A position a merge covers refuses first, because Excel ignores what a covered `c` holds. The check reads `mergeCells` again, since the parsed flags only exist for a cell the file states. `TableRange::contains` left the last row and column of the range out, which made the parser's two covered-cell branches disagree: a merge too big to walk cell by cell marked one row and one column too few. The range is closed everywhere else it is read, so `contains` is closed now too. LibreOffice opens a grown workbook and reads the new cells, checked with `soffice --convert-to`. The reference output is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKFKbUVCYF2VhujdmjhhPW
andiwand
force-pushed
the
feat/sheet-grow-xlsx
branch
from
September 9, 2026 20:22
1b8e95e to
51aec1f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Generated with Claude Code
Rebased on main now that #868 has landed. Step 2.2 of
docs/design/spreadsheet-editing.md.What it does
An
.xlsxfile spells aconly for a cell that holds something, so a write into an empty position refused. The page carries no lock on such a cell, so the user typed and the host got the refusal back. This was the last such hole.insert_cellstates thecin its row in column order, and therowinsheetDatain row order where the file states none, then widensdimensionaround the new cell. Nothing is reindexed — the cell map is keyed by position, so an insert touches one entry.A position a merge covers refuses first, because Excel ignores what a covered
cholds. That check readsmergeCellsagain, since the parsedis_coveredflags only exist for a cell the file states.The fix that came with it
TableRange::containswas half open — it left the last row and column of the range out. The parser marks the covered cells of a big merge withcontainsand those of a small one with an inclusive loop, so the two disagreed: a merge too big to walk cell by cell marked one row and one column too few, andSheetCell::is_coveredwas wrong for those cells.to()is read as the last position of the range everywhere else — the parser's own loop, thedimensionhandling — socontainsis closed now too. It had exactly one caller before this pull request.TableRange.containspins it, andthe_last_cell_of_a_wide_merge_refuses_toopins what it meant for the parser; both fail against the old comparison.Checks
soffice --headless --convert-to csvon a grownOrdnerruecken.xlsxreads7.5at the new column of row 1 andgrownat the new bottom-right corner.containsfix moves no rendered cell. It reaches the renderer only through a backstop the cursor normally makes unreachable.Test
OoxmlSpreadsheetWritegains seven cases: an absent cell written, column order, row order, the wideneddimension, the absent covered cell that still refuses, the last cell of a wide merge that now refuses too, and a save and reopen. The test workbook gained asheet_prefixargument so a<dimension>can sit where the schema orders it.https://claude.ai/code/session_01KKFKbUVCYF2VhujdmjhhPW