Stop unwrapping sparse rows that wrapping could not have produced - #10
Merged
Conversation
Fit Width and the manual narrow/widen actions unwrap continuation rows before re-laying out a table. The check that decided what counts as a continuation row only looked at the shape of the row: any row that left at least one column empty under a filled one was merged into the row above. Ordinary sparse data has that shape too, so distinct records were silently collapsed into a single row - including automatically, when power auto fit runs after an unrelated edit. Wrapping leaves a checkable trace, so test for it instead of guessing: - It fills a cell's segments from the top, so a segment can never sit under an empty cell. - It is greedy, so it never leaves room for the next token. A row whose first token would still have fitted after the previous segment was never wrapped. The reference width for that test is measured only over rows that fill every column. A continuation row must leave a column empty, so those rows carry the real column width; measuring the candidates too would let a hand-split row widen the very column it is tested against, which is what kept hand-split words such as "scrip" / "t already" joinable. Rows that wrapping did produce are still rejoined, so widening a fitted table still rebuilds the original sentence and repeated fits stay idempotent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KsNFrStLUQaEZNtCybK4XD
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c90137e79
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Two ways the continuation check could reject a genuine continuation: - Header rows are never wrapped, so when a fit pushes body cells below the header width, formatTable widens the rendered column back to the header. The reference width then described a width the body was never split at, and a later fit refused to rejoin the record. Measure only body rows now. - Wrapping hard-splits an over-wide link or code span mid-token, so a fragment such as "[x y](ur" no longer parses as a link. Re-tokenising it under-measured the segment. Compare the whole cell instead, which needs no tokenising and is the conservative direction: it only refuses a merge when the entire cell would still have fitted after the previous segment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KsNFrStLUQaEZNtCybK4XD
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.
The defect
Fit Width and the manual narrow/widen actions unwrap continuation rows before re-laying out a
table.
isLikelyContinuationRowdecided what counts as a continuation row from the shape ofthe row alone: any row that left at least one column empty under a filled one was merged into the
row above.
Ordinary sparse data has exactly that shape, so distinct records were silently collapsed:
became
This also fired automatically, when power auto fit runs after an unrelated edit.
The fix
Wrapping leaves a checkable trace, so test for it instead of guessing:
have fitted after the previous segment was never produced by wrapping.
The reference width for that second test is measured only over rows that fill every column
(
wrappingReferenceWidths). A continuation row must leave a column empty, so those rows carry thereal column width. Measuring the candidates too would let a hand-split row widen the very column it
is tested against — which is what keeps hand-split words such as
scrip/t alreadyjoinable intables the user wrote by hand.
What is deliberately unchanged
Rows that wrapping really did produce are still rejoined, so widening a fitted table rebuilds the
original sentence and repeated fits stay idempotent.
One case stays merged and cannot be fixed by any algorithm: a table whose sparse pair is a valid
wrap output at its own column width. For
| Alice | first record |/| | orphan record |at width 13,fit(25)on the single-row formproduces exactly those two lines, so the two readings are the same text. The fix removes the cases
that are decidable and leaves this one, rather than guessing.
Verification
The change is identical in all three cores (JetBrains, Notepad++, VS Code) and was checked against
the reference implementation with a differential harness:
Behaviour changes are confined to the three operations that unwrap (
FIT,NARROW_COLUMN,WIDEN_COLUMN); align, sorting and structural edits are untouched. A separate invariant run over5 000 tables confirms no operation loses text.
Three scenarios were added to the shared golden fixture, kept byte-identical across the three
repositories.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KsNFrStLUQaEZNtCybK4XD