Skip to content

feat(text): Advanced Text, Auto-fit & Internationalization — issue #16 epic#59

Merged
MHoroszowski merged 1 commit into
masterfrom
feature/issue16-advanced-text
May 18, 2026
Merged

feat(text): Advanced Text, Auto-fit & Internationalization — issue #16 epic#59
MHoroszowski merged 1 commit into
masterfrom
feature/issue16-advanced-text

Conversation

@MHoroszowski
Copy link
Copy Markdown
Owner

Epic: Advanced Text, Auto-fit & Internationalization — Closes #16

Resolves the full issue #16 epic against the ruff-formatted fork master (manual port per CLAUDE.md §2, not cherry-pick).

Scope delivered

  • Run-level character formatting: strike (MSO_TEXT_STRIKE_TYPE), superscript/subscript (baseline), character_spacing/kerning (Centipoints), latin/east_asian/complex_script font faces, run highlight color.
  • Text-frame layout: columns (1–16), column_spacing, text_direction (MSO_TEXT_DIRECTION), auto-fit introspection (overflow_info(), will_overflow(), shrink_text_to_fit()).
  • Internationalization: paragraph + column RTL (rtl, rtlCol), East-Asian / complex-script font runs.
  • Auto-fit: lnSpcReduction on normAutofit; TextFitter.wrapped_line_count / line_height; upstream TextFrame.fit_text exceptions scanny/python-pptx#168 empty-line-source crash fixed in _break_line.

Schema correctness

New simple types ST_TextPoint, ST_TextNonNegativePoint, ST_TextColumnCount; child elements wired in XSD sequence order (highlight before latin, ea/cs after) with full successor tuples — verified against in-repo ECMA-376 XSD. rPr child order [solidFill, highlight, latin, ea, cs]; autofit choice kept exclusive (no normAutofit+spAutoFit co-occurrence) to avoid PowerPoint repair.

Verification (trinity at merge commit, captured verbatim)

  • pytest tests/ -q3972 passed, 0 failed (+47 new in tests/test_issue16_advanced_text.py)
  • ruff check src testsAll checks passed!; ruff format --check232 files already formatted
  • behave features/1130 scenarios passed, 0 failed (+11 new in features/iss-16-advanced-text.feature)

UAT script uat/uat_issue16_advanced_text.py round-trips 15/15 (exit 0). Maintainer UAT sign-off received in review; PowerPoint no-repair confirmed via object-model probe (deck loaded as named doc, sheets=0). Visual screenshot was environment-blocked and was honestly deferred to maintainer §6a UAT rather than substituted.

Closes #16

…epic

Resolves all 11 sub-features of the issue #16 epic on one branch.
Fork-state probe confirmed none existed here (unlike #18's arrowheads);
this is genuinely all-new text-API surface. Maintainer UAT pending.

New API:
- Font.superscript / Font.subscript — a:rPr/@baseline (signed
  ST_Percentage fraction: +0.30 super, -0.25 sub; mutually exclusive).
- Font.strike — MSO_TEXT_STRIKE_TYPE (NONE/SINGLE/DOUBLE ->
  noStrike/sngStrike/dblStrike), a:rPr/@strike.
- Font.highlight — lazy _HighlightColor proxy over a:rPr/a:highlight
  (CT_Color); read-without-mutate, schema-ordered before the typeface
  trio (verified: [solidFill, highlight, latin, ea, cs]).
- Font.character_spacing / Font.kerning — a:rPr/@spc (signed) and
  @kern (non-negative), centipoints like Font.size.
- Font.latin / Font.east_asian / Font.complex_script — a:rPr a:latin/
  a:ea/a:cs trio. Font.name STILL sets ONLY a:latin (backward compat,
  regression-tested).
- TextFrame.columns / TextFrame.column_spacing — a:bodyPr @numcol
  (1..16, ValueError otherwise) / @spcCol (EMU).
- TextFrame.text_direction — MSO_TEXT_DIRECTION enum, a:bodyPr/@Vert.
- Paragraph.rtl — a:pPr/@rtl (Arabic/Hebrew/Persian; PowerPoint shapes).
- TextFrame.will_overflow() / TextFrame.overflow_info() — read-only
  (does NOT mutate txBody or set autofit; ISC-68-verified) structured
  _OverflowInfo report via TextFitter. Closes scanny#1114.
- TextFrame.shrink_text_to_fit() — eager normAutofit fontScale
  (thousandths form, e.g. "11111"); does not rewrite run sz. Adds
  CT_TextNormalAutofit/@lnSpcReduction. Closes scanny#1107.
- fit_text long-word crash fix (scanny#168): _break_line now
  force-accepts the shortest candidate when no line fits a single
  word wider than the frame, instead of returning None and crashing
  _wrap_lines on a None unpack.

New simpletypes (ST_TextPoint/ST_TextNonNegativePoint/
ST_TextColumnCount), enums (MSO_TEXT_STRIKE_TYPE, MSO_TEXT_DIRECTION),
oxml registrations (a:highlight->CT_Color, a:ea/a:cs->CT_TextFont).
All new a:rPr/a:bodyPr/a:pPr children/attrs are XSD-ordered
(dml-main.xsd ground truth); autofit choice exclusivity verified.

Tests: 47 new unit tests in tests/test_issue16_advanced_text.py
(super/sub 5, strike 4, highlight 4, spacing 4, trio 5, columns 4,
direction 4, rtl 4, overflow 5, shrink 3, fit168 3) + 11 behave
scenarios. Per-attr save->reopen round-trip coverage included.

Trinity (verbatim):
  python3 -m pytest tests/ -q            -> 3972 passed (3925 + 47)
  ruff check src tests                   -> All checks passed!
  python3 -m behave features/ --no-color -> 1130 scenarios, 0 failed
                                            (1119 + 11)

UAT: uat/uat_issue16_advanced_text.py runs clean, 15/15 round-trip
checks, exit 0 (fixture includes the scanny#168 long unbreakable word and a
latin+ea+cs+Arabic multi-script run per the UAT-fixture-diversity
discipline). No-repair = directly observed: real PowerPoint loaded the
deck as a named 4-slide presentation with zero modal sheets (no repair
dialog) across multiple clean relaunches, no crash. Visual rendering of
the slides is DEFERRED — PowerPoint's document window would not surface
to screen/AX this session (an intermittent PowerPoint-side environment
wall the #18 screenshot-probe documented; not a file defect). Visual +
PowerPoint-resave preservation are the maintainer's §6a acceptance
surface; not claimed here.

Closes #16
@MHoroszowski MHoroszowski merged commit ee53fd0 into master May 18, 2026
16 checks passed
@MHoroszowski MHoroszowski deleted the feature/issue16-advanced-text branch May 18, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Epic] Advanced Text, Auto-fit & Internationalization

1 participant