0x3C-0x3F are plain ASCII < = > ? in Adobe's symbol encoding (<= >= inf
sit at 0xA3/0xB3/0xA5 and therefore at 0x5C), so 'a<b' set in Symbol
drew 'a<=b' on macOS. Drop those four symbol_unicode arms and their
pairs in the whole-table test, and list 0x3C-0x3F as ASCII.
symbol_font_draw returned None for codes with no table entry, so U+F031
('1'), U+F028 ('(') etc. still didn't draw from Symbol. For 0x20-0x7E
with no table entry, fall back to the ASCII character itself when the
face covers it; covers_symbol now delegates to symbol_font_draw so the
shaping path picks the Symbol face for those codes too.
ROADMAP header keeps a single Last reviewed line (replaces, not adds).
The sorter's Ctrl+A runs edit.selectAll with the slides scope, so every
slide in the deck is selected, as in PowerPoint. Nothing covered the key
press itself, so a change to the shortcut could have dropped the scope.
The kittest covers the whole way: the key press, the scope and the
selection it leaves behind. Red-proof: with the sorter's Ctrl+A no longer
asking for the slides scope, the selection stays at the one current slide
and the test fails.
ROADMAP progress-log row added.
The render gate for an empty placeholder's fill checked only
s.fill.is_none(). A quick style that sets a style reference without
an explicit fill left s.fill as None, so the gate skipped the fill
even though the shape had been formatted — the style only appeared
after text was added.
The gate now also checks s.line and s.style: if any of the three has
a local override, the placeholder is considered formatted and the
fill is drawn. A truly unformatted empty placeholder still shows the
dashed outline and prompt.
The pane scrolled only by hand: past a screenful of slides, arrow-key
navigation left the current thumbnail out of view. When the slide changes,
the pane now scrolls it into view - minimally, only once the thumbnail has
left the viewport, as in PowerPoint, so a visible thumbnail never moves the
pane and the user's own scrolling stands. The pane's scroll offset is
recorded in UiState (skipped by serde) for the control channel and tests.
* M2.1: preserve chart parts through native saves
Serialize retained chart relationships and payloads in native files.
Add native and headless file-command round-trip regressions.
Contribution on behalf of @MMexicann.
* Format: bound opaque chart parts as native ZIP entries
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* Model: track transient native chart part entries
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* PPTX: initialize native chart entry metadata
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* Engine: adapt chart native roundtrip fixtures
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* Docs: describe bounded chart sidecars and validation
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* Roadmap: record bounded chart persistence evidence
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
---------
Co-authored-by: skylar taylor-barrick <hi@skylar.cc>
A click on the frame band of an unselected or selected text box or
placeholder started text editing, so the box could not be selected,
moved, duplicated or deleted from its frame. The frame band now selects
the box whole, like PowerPoint; only a click inside takes the caret.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Design › Browse for Themes… with a .pptx or .potx now does what PowerPoint
does: the file's first slide master and its layouts replace the master the
current slide uses (a preserved master stays beside it), stretched to this
deck's slide size. Each slide on the old master moves to the new layout with
the same name, else the same kind, and keeps its content as Layout does. One
undo step. A .thmx still brings its theme only.
Reuse Slides' master copy (media, fresh master, layout and shape ids) moves
into reuse::import_master so both commands share it.
Co-Authored-By: Claude Code <noreply@anthropic.com>
# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# interactive rebase in progress; onto 22db926
# Last command done (1 command done):
# pick 8992623 #807: Browse for Themes brings a template's slide master and layouts
# No commands remaining.
# You are currently rebasing.
#
# Changes to be committed:
# modified: ROADMAP.md
# modified: crates/engine/src/cmd/design.rs
# modified: crates/engine/src/cmd/reuse.rs
# modified: docs/file-format-parity.md
#
Ctrl+F and typing searches without clicking the field first, and the field
keeps the keyboard after Enter finds a match.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Duplicating a shape, moving the copy and duplicating that copy again places
the next copy the same distance further on. Anything else, an undone copy or
another slide gets the usual offset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The importer skipped a slide whose part was missing or unreadable and only
logged it, so `info` showed one slide fewer with exit code 0 and a save wrote
the shorter deck over the original.
`deckcraft_pptx::import_checked` returns the parts it left out (`import` is
unchanged). The engine carries them as `Damage::slides` next to the damaged
media of a `.deckcraft` file: `file.open` and `file.openBytes` return
`lostSlides`, the app shows a message and opens a repaired copy (so Save asks
for a new name), and `deckcraft-cli` warns on stderr.
Co-Authored-By: Claude Code <noreply@anthropic.com>
# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# interactive rebase in progress; onto 1dc6972
# Last command done (1 command done):
# pick d2e995c PPTX: a slide that can't be read is reported, not dropped in silence (#203)
# No commands remaining.
# You are currently rebasing.
#
# Changes to be committed:
# modified: Cargo.lock
# modified: ROADMAP.md
# modified: apps/deckcraft-cli/Cargo.toml
# modified: apps/deckcraft-cli/src/main.rs
# new file: apps/deckcraft-cli/tests/damaged.rs
# modified: crates/engine/src/cmd/file.rs
# modified: crates/engine/src/tests.rs
# modified: crates/pptx/src/lib.rs
# modified: crates/pptx/src/read/mod.rs
# modified: crates/pptx/tests/malformed.rs
# modified: docs/file-format-parity.md
#
# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# interactive rebase in progress; onto 22db926
# Last command done (1 command done):
# pick 31b0d33 PPTX: a slide that can't be read is reported, not dropped in silence (#203)
# No commands remaining.
# You are currently rebasing.
#
# Changes to be committed:
# modified: Cargo.lock
# modified: ROADMAP.md
# modified: apps/deckcraft-cli/Cargo.toml
# modified: apps/deckcraft-cli/src/main.rs
# new file: apps/deckcraft-cli/tests/damaged.rs
# modified: crates/engine/src/cmd/file.rs
# modified: crates/engine/src/tests.rs
# modified: crates/pptx/src/lib.rs
# modified: crates/pptx/src/read/mod.rs
# modified: crates/pptx/tests/malformed.rs
# modified: docs/file-format-parity.md
#
A .pptx or .deckcraft could give a glow, soft edge, shadow or reflection any size. A glow of
~10^16 pt made vello panic while flattening, one of 10^18 pt made rendering ask for 34 GB and abort.
sane_numbers (run by repair on every opened file) now caps them like line widths and font sizes:
glow 150, soft edges 100, shadows 200, reflections 100 pt; shadow scale and skew are kept sane and
non-numbers become 0, on shapes and on text runs, table cells included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
repair re-id'd repeated slide ids but not shape ids, so such a file opened as a deck that fails
validate, and edits by id found only the first of the shapes sharing one. Repeats on a slide,
layout or master (groups included) now get fresh ids from the deck's counter; the first keeps
its id, and decks without repeats aren't copied.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shape.editPoints was a noundo command, so the conversion from a preset to custom geometry was
never recorded and Ctrl+Z took back the step before it. It is undoable now (only an actual change
records a step), and Edit Points ends when Undo turns the shape back into a preset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While a placeholder's text was being edited, place_caret took every click inside the text box
before the hit test, so a shape in front of it couldn't be selected. It now leaves the click to
the hit test when a shape above the one holding the text is under the pointer; a click on the
text where nothing is in front still moves the caret.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows (deckcraft.wxs) and Linux (the desktop file) already offer DeckCraft for .deckcraft,
.pptx, .potx and .ppsx; the macOS Info.plist now declares the same four, so a template or a
slide show opens from Finder as well. A test in apps/deckcraft reads the three packaging files
and fails when they drift apart, and checks every document type names its content type (Finder's
"Change All" needs it). Progress log row for #138 and #347.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PowerPoint stores a Symbol-font character as U+F0xx with <a:sym typeface="Symbol"/>:
U+F0DE is the Symbol font's double arrow (=>). The layout drew it from whichever
installed face happened to map U+F0DE (Wingdings draws an arrow at another angle),
because Apple's "Symbol" on macOS has no private-use cmap at all — it maps the
glyphs to real Unicode instead. The test that checked this skipped on macOS.
Add the Adobe Symbol encoding table (unicode.org MAPPINGS/VENDORS/ADOBE/symbol.txt;
Apple's Mac OS Symbol is laid out identically) and remap a document's U+F0xx code to
the real Unicode character the installed Symbol face draws it at: the PUA code when
the face has one, else the encoding's real character (U+F0DE -> U+21D2 =>).
The remap applies wherever a symbol-font character is drawn:
- text runs with an a:sym font (shape_cells picks the face, shape_item remaps during shaping),
- bullets (symbol_font_char),
- metafile text (symbol_char).
The previously-skipped symbol_font_characters_draw_in_the_sym_font test now runs on
macOS (its guard checks the remapped character), and a new test checks U+F0DE draws
as U+21D2 on Apple's Symbol.
review.reject {index | all} drops revisions from the list without applying
them, so the open deck stays as it is: a rejected inserted slide is never
added, a rejected deleted slide stays, a rejected changed slide keeps its
current content. Accept All skips what was rejected. Rejections are kept on
the compare session (keyed by the open slide id and the revised slide) and
end with End Review; like Compare and End Review, rejecting is not an undo
step, since it leaves the document untouched.
Revisions pane: Reject next to each Accept, and Reject All.
Keep later On Click effects and paragraph builds in separate interactive steps.
Add round-trip and headless show regressions.
Contribution on behalf of @MMexicann.
slides_to_outline only looked at sh.text, which regular text boxes and
placeholders carry. Tables store their text in cells inside
ShapeKind::Table, so convert to .txt or .md silently skipped every
table cell — with exit 0 and no warning.
The outline now walks into tables: each row becomes a tab-separated
line (multi-paragraph cell text is flattened with spaces). Verified
with the issue's python-pptx repro: the four cell texts appear after
the slide title and text box body.
Tests: a deck with a text box and a 2x2 table — the outline contains
all three text sources.
Preserve notes and handout master export, visible text and native parallel
compression while propagating shared font errors through each export path.
Keep the dependency check accurate for native and WASM feature resolution.
PR #708.
anchorCtr's centreing offset was computed for a block that starts at
the box's left edge and then added to lines that alignment had already
placed within the box. For a right-aligned line the two shifts
stacked: the line ended up starting at the box's centre and ran past
the right edge - on the tdf165341 fixture the sentence was cut off at
"...paragraph rig". The clamp at zero made it worse for content wider
than the box: all the overflow went to the right only.
The origin is now set so the drawn text block's own centre (min/max of
the laid-out line extents) lands on the box's centre: every alignment
stays inside the box when it fits, and overflow centres symmetrically
past both edges, as PowerPoint draws it. Empty lines carry no ink and
stay out of the block; vertical text and multi-column bodies are
unchanged (centring is unimplemented for them, as before).
Tests: right/left-aligned, trailing empty paragraph, mixed alignment,
symmetric overflow, and a no-anchorCtr control - the block's centre
equals the box's centre in every case.
Reported with a public LibreOffice test fixture (tdf165341.pptx);
verified by rendering the slide before (text cut at the right edge)
and after (whole sentence centred).
Conflicts resolved onto main's newer shape, and the PR's policy applied to
every alloc_id/add_media/new_slide call site main has grown since: commands
answer bad(cmd, NO_ID_SPACE) (slide.reuse, insert.zoom, SmartArt, photo
album, review.accept, handout/notes masters, master placeholders,
background/artistic/compress pictures, transition sound, ink to shape,
paste special, file.new templates); reid/bring_media/renumber/regenerate
and compare::adopt/accept are fallible; outline import keeps what fit.
Tests use expect() on the now-Option results.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reject unrelated, malformed, incomplete and oversized replies without replaying commands.
Reconnect before sending when unsolicited reply bytes are buffered.
Contribution on behalf of @MMexicann.
Union merges of the 2026-10-14 community PR wave stacked header lines and
left near-duplicate rows, bullets and paragraphs with per-PR counts. Each
progress doc now has one status line and one row per fact, with current
numbers: breadth 84% over 191 features (cargo xtask parity, after removing
duplicate Thesaurus/AutoCorrect/Artistic effects/Corrections checklist
rows), 320 engine commands, 41 dialogs, 1,641 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- review.thesaurus's params doc parses under describe's grammar; describe's edit.copy test
expects the landing branch's {text, html?} answer.
- The Language dialog test picks the landing branch's "Français (France)" entry; the Format
Background test allows the pane's title to appear twice.
- Progress docs rebuilt from the landing branch's versions with land-r6's rows applied on top,
so the union merge no longer drops the pen-pressure, ui.pointer and ui.key rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>