Fix list numbering counters and per level indentation - #16
Conversation
Two unrelated list bugs, both visible in the file attached to #3. Numbering counters were keyed on num_id. Pandoc and LibreOffice emit a separate w:num for each list block and point them all at one w:abstractNum, so a plain two item list arrives as numId 4 and numId 1 both mapping to abstract 1. Keying on the instance gave each block its own counter and every item rendered as "1.". Counters are now keyed on the abstract definition, which is what the count actually belongs to. Lists with genuinely separate abstract definitions still restart, and there is a test for each direction. Indentation for a numbering level was parsed and then never used. A w:lvl carries its own w:pPr, which is where the per level indent lives, and nothing merged it into the paragraph properties. Every level of a list drew at the same left position. The level properties are now merged between the paragraph style and direct formatting, which is where they sit in the property chain, so a level indent applies unless the paragraph overrides it. Rendering the file from #3 now gives "1." and "2." for the two numbered items, with the nested bullets stepped in one level, which matches the LibreOffice reference in that issue. Closes #12. Closes #13.
Applying a numbering level's own indent moves list markers, so the page-one PNG for letter and for contract both change. Verified by rendering both samples before and after. The only visual difference is list markers moving to their level indent, with wrapped text now aligning under the text start instead of returning to the margin. Nothing else on either page moved. The docx part hashes are untouched, including numbering.xml, which confirms this is a rendering change and not a change to the OOXML we write.
7b8c0d4 to
c895a9e
Compare
|
Rebased onto current main and added the baseline update, because the Output stability job had not run on this PR when it was opened. It landed on main with the sprint merge afterwards. It does fail on the original commit, as expected. Applying a numbering level's own indent moves list markers, so I checked the delta rather than just regenerating. Rendering both samples before and after, the only visual difference is list markers moving to their level indent, with wrapped text now aligning under the text start instead of returning to the margin. Nothing else on either page moved. One detail worth recording: the docx part hashes are untouched, Baseline updated with an audit reason. All seven checks now pass. |
Closes #12 and closes #13. Both were found rendering the file attached to #3, and both are verified by rendering it again.
Numbering counters, #12
Counters were keyed on
num_id. That is the numbering instance, not the list.Pandoc and LibreOffice emit a separate
w:numper list block and point them all at a singlew:abstractNum. The file in #3 is exactly that:Two instances, one list. Keying on the instance gave each its own counter, so both items rendered as
1..Counters are now keyed on the abstract definition. Lists that really do have separate abstract definitions still restart independently, and there is a test for each direction so the fix cannot drift into the opposite bug.
Level indentation, #13
A
w:lvlcarries its ownw:pPr, and that is where the per level indent lives. We parsed it intoCT_Lvl::pprand then never looked at it, so every level of a list drew at the same left position. In the #3 file the levels ask for 720 and 1440 twips and both rendered at the same place.Level properties are now merged between the paragraph style and direct formatting, which is where they belong in the property chain. A level indent applies unless the paragraph sets its own.
Result
Rendering
office2pdf_test.docxfrom #3.Before:
After:
That matches the LibreOffice reference in #3.
Checks
cargo fmt --all --check,cargo clippy --workspace --all-targets -- -D warningsand the full suite all pass. 336 tests, up from 333, with three added here.Scope
Deliberately does not touch #10 or #11, the other two halves of #3. #10 is in the same function PR #2 is rewriting and should wait for that to land.