Skip to content

Add layout inspection and mutation commands#1

Merged
pmdci merged 7 commits into
mainfrom
feature-layout
May 7, 2026
Merged

Add layout inspection and mutation commands#1
pmdci merged 7 commits into
mainfrom
feature-layout

Conversation

@pmdci
Copy link
Copy Markdown
Owner

@pmdci pmdci commented May 7, 2026

Summary

This PR adds the new layout command group to pptx-toolkit for inspecting and mutating slide layout naming metadata in PPTX files.

It covers the full layout-name workflow we researched:

  • layout list
  • layout remove matching-name
  • layout set

The implementation is based on the OOXML distinction between:

  • p:cSld/@name
  • p:sldLayout/@matchingName

What’s Included

New commands

layout list

Lists slide layouts and shows:

  • Layout ID
  • Name
  • Matching Name
  • Master
  • Theme
  • Used By Slides

Supports filters:

  • --layout-id
  • --name
  • --matching-name
  • --theme

layout remove matching-name

Removes p:sldLayout/@matchingName from all matched layouts.

Supports the same filters as layout list.

layout set

Applies directional property assignment across all matched layouts:

pptx-toolkit layout set <source>:<target> input.pptx output.pptx

Supported source forms:

  • @name
  • @matching-name
  • literal string

Supported target properties:

  • name
  • matching-name

Examples:

pptx-toolkit layout set @name:matching-name input.pptx output.pptx
pptx-toolkit layout set @matching-name:name input.pptx output.pptx
pptx-toolkit layout set "Layout with matchName property":matching-name input.pptx output.pptx --layout-id slideLayout12

Design Notes

Filter model

Layout mutation commands operate on the set of matched layouts.

  • no filters = all layouts
  • filters narrow the set
  • mutations apply per matched layout

set syntax

The layout set parser uses:

  • @ on the source side to indicate property reference
  • plain property names on the target side

This avoids ambiguity between:

  • literal name
  • property reference name

Property-to-same-property validation

These forms are rejected early:

@name:name
@matching-name:matching-name

with a clear error, because they would be no-op self-copies.

OOXML-safe mutation strategy

The mutation code does not reserialize full XML documents.

Instead it:

  • uses encoding/xml.Decoder only to locate exact start-tag byte ranges
  • applies scoped byte-level attribute mutation to those slices only

This avoids OOXML namespace-prefix corruption while still being structured enough to safely target:

  • <p:sldLayout ...>
  • <p:cSld ...>

Test Fixture

cmd/pptx-toolkit/testdata/test.pptx already contains a dedicated divergent-name layout:

  • slideLayout12.xml
  • p:cSld/@name = "matchName-test"
  • p:sldLayout/@matchingName = "Layout with matchName property"

This fixture is now used for layout inspection and mutation coverage.

Tests

Added/expanded tests for:

  • layout XML parsing
  • layout set mapping parser
  • invalid parser cases
  • matchingName removal
  • attribute creation/replacement for both layout properties
  • literal assignment
  • property-to-property copy
  • filtered mutation by --layout-id
  • copy-from-missing-source behavior
  • command filter leakage across repeated executions
  • overwrite prompt path now using command-scoped stdin

Refactors / shared behavior

  • introduced shared mutation preflight:
    • input validation
    • overwrite prompt
  • PromptOverwrite now reads from cmd.InOrStdin() instead of global stdin, making it test-safe
  • reused shared layout filter parsing across layout commands
  • removed duplicated archive extraction in favor of shared helpers

Documentation

Updated:

  • README.md
  • .llm/layouts-matching-names.md

to document:

  • layout list
  • layout remove
  • layout set
  • mapping syntax
  • filter semantics
  • implementation notes and testing expectations

Validation

Ran:

go test ./cmd/pptx-toolkit -count=1

and the package test suite passes.

pmdci and others added 7 commits May 6, 2026 23:10
Extract PrepareMutation to output.go — validates input file and prompts
before overwriting an existing output file. All mutation commands now
call this instead of doing it inline (colors.go updated accordingly).

Add layoutFiltersFromCommand and resetLayoutFlags to layouts.go so the
list command reads flags through cobra rather than global vars, and
resets them after each execution to prevent filter leakage between
repeated calls in the same process.

Fix normalizeThemeFilter to trim whitespace and skip empty entries.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes p:sldLayout/@matchingName from slide layouts using the
encoding/xml Decoder.InputOffset algorithm: locates the exact byte
range of the sldLayout start tag by namespace URI, applies a scoped
regex to that slice only, leaves the rest of the file byte-identical.

Supports the same --layout-id, --name, --matching-name, and --theme
filters as layout list. Without filters, removes from all layouts
that have the attribute set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@pmdci pmdci self-assigned this May 7, 2026
@pmdci pmdci added the enhancement New feature or request label May 7, 2026
@pmdci pmdci merged commit 5723169 into main May 7, 2026
1 check passed
@pmdci pmdci deleted the feature-layout branch May 7, 2026 01:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant