fix(pptx): narrow a paragraph's wrap width by its right margin - #348
fix(pptx): narrow a paragraph's wrap width by its right margin#348dsaad68 wants to merge 1 commit into
Conversation
|
All contributors have signed the CLA — thank you! ✍️ ✅ Posted by the CLA bot. |
Greptile SummaryThis PR adds end-to-end support for DrawingML paragraph right margins:
Confidence Score: 4/5The PR appears safe to merge after correcting the non-blocking schema-version error in the release note. Parsing, cascading, layout, and deferred source recovery are internally consistent and covered by focused tests; the only accepted issue is inaccurate release documentation. Files Needing Attention: .changeset/pptx-paragraph-right-margin.md
|
| Filename | Overview |
|---|---|
| crates/pptx-parse/src/drawing.rs | Parses marR into paragraph properties and tests list-style, paragraph, zero-value, and serialization behavior. |
| crates/pptx-parse/src/model.rs | Adds the optional, backward-compatible margin_right model field. |
| crates/pptx-render/src/layout.rs | Resolves inherited right margins and narrows paragraph wrap width without moving its left edge. |
| crates/pptx-edit/src/deck.rs | Advances snapshots to schema 18 and restores right margins from attached source packages. |
| crates/pptx-render/tests/paragraph_margins.rs | Covers cascade inheritance, direct zero override, expected wrapping, and the no-margin control. |
| .changeset/pptx-paragraph-right-margin.md | Describes the rendering fix but incorrectly identifies the new collaboration schema as 16 rather than 18. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
XML["DrawingML marR"] --> Parse["ParagraphProperties.margin_right"]
Master["Master text style"] --> Cascade["Paragraph-property cascade"]
Layout["Layout list style"] --> Cascade
Shape["Shape list style"] --> Cascade
Direct["Direct paragraph properties"] --> Cascade
Parse --> Cascade
Cascade --> Resolve["Resolve EMU margin to pixels"]
Resolve --> Width["Wrap width = box width - left margin - right margin"]
Width --> Lines["Lay out and align text lines"]
Legacy["Legacy collaboration snapshot"] --> V18["Schema 18 migration"]
Source["Attached source package"] --> Recovery["Recover missing right margins"]
V18 --> Recovery
Reviews (1): Last reviewed commit: "fix(pptx): narrow a paragraph's wrap wid..." | Re-trigger Greptile
|
Incorrect schema version — fixed ( Right, and my slip. This migration was written as 16, renumbered when One thing that supersedes the number itself: |
`a:pPr/@marR` was parsed nowhere, so a right margin never narrowed the wrap width and text ran the full box. 8001 occurrences across the corpus. Reads it into `ParagraphProperties::margin_right`, overrides it with the same `is_some()` rule as its siblings so `marR="0"` resets an inherited margin, and subtracts it from the wrap width without moving the paragraph's left edge. Collaboration schema 18 persists it and recovers it from an attached source. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
d50b74e to
74af2c3
Compare
|
Rebased onto
What the rebase touched, all of it bookkeeping — the rendering change is unchanged:
Two things the renumber exposed that were latent rather than mechanical:
This should merge before #354, which is now stacked on it at schema 22. |
TL;DR:
Before/After:
LibreOffice (reference), BetterOffice before, BetterOffice after, on the committed repro deck.
LibreOffice breaks all five paragraphs at exactly the words this change breaks them at:
Five paragraphs, each asking for a different right margin; before, all five wrap at the
full 600 px box width. No corpus deck that reproduces this is publishable — see
"Where the metric disagrees" below.
Repro file:
crates/pptx-render/tests/fixtures/paragraph-right-margin.pptx, withcrates/pptx-render/tests/fixtures/paragraph-right-margin.mddescribing what each shape exercisesand
.before.png/.after.pngbeside it.Summary:
marRis parsed intoParagraphProperties::margin_right.parse_paragraph_propertiesservesthe master's
p:txStyles, everya:lstStylelevel,a:defPPrand everya:pPr, so one readcovers the whole cascade; the field is
skip_serializing_if = "Option::is_none", so a packagewithout a right margin serializes exactly as it does today.
merge_paragraph_propertiesoverrides it with the sameis_some()rule asmargin_left, so ashape's
a:lstStylebeats the layout's, the layout's beats the master's, and an explicitmarR="0"on a paragraph resets an inherited margin instead of being ignored.layout_contentsubtracts the resolved right margin from the paragraph's wrap width. The line'sstart does not move, so
marLand the bullet gutter are unaffected.mainat 20.merge_source_paragraph_propertiesrecoversthe margin from the source package for snapshots written before the field existed.
earlier revision listed a migratable version whose migration re-serialised
packageJsonfrom amodel without
margin_right, dropping the field; stacking it on this branch removes that path.Where the metric disagrees:
arena-bibliography/18, andfine_pctthere rises 12.08 → 12.67 against a same-commit baseline. The other four slides in that deck
with a non-zero
marR, and every slide of the two decks whose shape list styles carrymarR,render byte-identically.
<a:pPr marL="218800" marR="5012302" indent="210908" algn="r">on its row labels; the referencerenders them as a narrow right-aligned column of seven lines,
beforeran them onto one lineacross the slide, and
afterreproduces the reference's column and pushes the caption blockbelow it into the reference's position. Split by region, the diff inside the table's own rows
falls (19,330 → 13,622 differing pixels) and rises outside it, because the caption block is now
drawn where the reference draws it and the two do not agree line for line — that shape also
carries per-run
spc(character spacing, unimplemented) andspAutoFit, so its wrap is stillwrong once it is in the right place. Text drawn in roughly the right place scores worse than text
not drawn at all.
arena-bibliographyis a third-party presentation, soits renders are not attached; the before/after above is the committed synthetic fixture, whose
paragraphs LibreOffice breaks at exactly the words the fix breaks them at.
Test plan:
cargo test -p betteroffice-pptx-parse -p betteroffice-pptx-render -p betteroffice-pptx-edit(347 tests, all passing)
crates/pptx-render/tests/paragraph_margins.rsfails without thelayout_contentchange:two of its three tests break, the third is the control that must keep passing
a_v15_snapshot_recovers_paragraph_right_margins_from_sourcefails without themerge_source_paragraph_propertieschangecargo fmt --all -- --checkandcargo clippy --all-targetson the three cratescargo checkinsidebindings/python-pptx, which is a separate workspacearena-bibliography/18is the only slide in 48 decks whose pixels changeCloses #347