fix(docx): break a table across pages where the layout breaks it - #724
Merged
Merged
Conversation
The layout splits a table only between rows, repeats its header rows on every page it continues on, and never leaves them at the foot of a page alone. The export stated none of it. Every row the layout placed is now w:cantSplit, repeatHeader(n) rows are w:tblHeader and keep with the row under them, and a row of blocks is kept whole the same way. The committed word-export-companion.docx preview is re-rendered: its six table rows gain w:cantSplit and nothing else changes.
DemchaAV
force-pushed
the
fix/docx-table-pagination
branch
from
September 23, 2026 12:18
f1d4409 to
f3cb1f9
Compare
A row name's index was parsed with Integer.parseInt, which throws on a name that only resembles the pattern. The index is kept as text and a row is looked up by writing its index the same way, so such a name matches nothing instead of failing the export.
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.
Why
Word re-paginates a DOCX itself, so it only breaks a table where the layout does if the file says where. The layout:
repeatHeader(n)rows at the top of every page the table continues on.splitTablerefuses a head that is only header).The export wrote none of it. Word's default lets a row break mid-line wherever its own page ends, and a long table printed its header once.
What changed
DocxSemanticBackend.breakRowsWhereTheLayoutDoes, run after each table is written:w:cantSplit.repeatedHeaderRowCountrows getw:tblHeader, and their cell paragraphs getw:keepNext, so the last header row stays on the page of the first body row.writeRowkeeps a row of blocks whole the same way.RowDefinitionlays a row out as one atomic piece.AtomicNodeTooLargeException), and the session then exports without a layout. So a placed row is always one a page can hold. In a document that could not be laid out, rows stay free to break, because no page holds such a row whole.DocxLayoutMetrics:placedRow(table, row)andplaced(node)are new.tableColumnsintoownRows, so both callers skip a composed cell's nested table. That table emits its rows under the owner's path.assets/readme/examples/word-export-companion.docxis re-rendered. Itsdocument.xmldiff is exactly six<w:trPr><w:cantSplit/></w:trPr>additions, one per table row, and nothing else.Verification
Full reactor gate (
clean verifyover core, render-pdf/docx/pptx, templates, testing, qa, coverage) → BUILD SUCCESS. Examples after install: 93 green;CommittedAssetDriftTestwent red on the stale preview until it was re-rendered.New
DocxTablePaginationTest(7 tests):cantSplit.repeatHeader(2): both header rows aretblHeaderand keep with the next row, and the body rows are neither.repeatHeader: no header row and no keep.cantSplitrow.cantSplitbut still getstblHeader.addRowis kept whole.Sabotaging both guards (
placedRow→true, header keep → always) fails 3 of them.Lane: shared-engine (render-docx) — table row properties only; no public API change.