Conflict: ROADMAP.md: both progress lines
Conflict: docs/target-app-parity.md: next's header, anchored objects wrapping text added to its change list
Conflict: docs/typography-parity.md: next's header (dated 2026-10-12) with #557's change added; Text wrap row: next's text and caveat, plus "on page items and anchored objects"
Conflict: crates/compose/src/lib.rs: next's Exclusion (side, contour) with #557's after field (Exclusion::wraps_line; next's constructors and the tests' helper set None); next's contour_path and wrap_obstacles in frame_specs; next's line loop (carry, grid, wrap_slot) with the line's start byte passed to wrap_slot; wrap_slot, free_slots and estimate_slots take line_start and skip exclusions that don't wrap the line (Jump Object test and in-band edges included); #557's re-break trigger stays in the line loop
Conflict: crates/compose/src/cache.rs: next's ComposeOptions (section_marker) with #557's neighbour compositions
Conflict: crates/compose/src/tests.rs: both test blocks
Conflict: crates/render/src/damage.rs: #557's test before next's patched_diff helper
An anchored object with text wrap pushes aside the text of other stories
whose frames it overlaps on its spread, and the lines of its own story
after the line holding its anchor (custom and above-line objects). Its own
story is composed again with the objects where the previous pass placed
them until they settle, at most four more times. The composition cache
keys a story wrapped by other stories' anchored objects on their
signatures, and canvas damage repaints the stories they wrap.
Conflict: ROADMAP.md: both progress lines
Conflict: docs/gaps.md: next's header, clipping paths added to its change list
Conflict: docs/target-app-parity.md: next's header, clipping paths added to its change list
Conflict: crates/doc/src/item.rs: both Graphic methods (next's shown_bounds, the branch's clip_region)
Conflict: crates/idml/src/names.rs: both imports (ClippingKind, ContourType)
Conflict: crates/idml/src/export.rs: both pushes, TextWrapPreference first, then the clipping settings
Conflict: crates/idml/src/import.rs: both lets (next's wrap, the branch's clip)
Conflict: crates/engine/src/cmd/file.rs: next's size and transform, plus clip: None
Conflict: crates/engine/src/cmd/datamerge/fill.rs: next's Graphic with wrap, plus clip: None
Conflict: crates/engine/src/cmd/mathexpr.rs: next's Graphic with wrap, plus clip: None
Conflict: crates/pdf/src/tests.rs: both tests
A placed graphic keeps its clipping path (Detect Edges, Alpha Channel,
Photoshop Path or User-Modified Path) in graphic space, with the
options IDML carries. IDML import reads ClippingPathSettings and its
saved ClippingPathGeometry (anchors capped, non-finite subpaths
dropped); export writes them back. The canvas and PDF export clip the
image to the path inside the frame clip; an inverted path shows the
image outside it. Without saved geometry nothing changes.
object.clippingPathOptions reports a graphic's clipping path, inverts
it or removes it (Object > Clipping Path > None).
Fixes#450.
#366 with #84's review fixes merged in: keyboard_pane is app.pane == app.focus_pane (the second window too), and the IME line in the parity doc.
Conflict: crates/ui-egui/src/canvas.rs: next's guard (menu_open, text_edit_focused, keyboard_pane)
Review fixes for text editing, paste and threading (fix84-text,
fix84-thread), the Italian/Japanese/Portuguese/Ukrainian Swatches hint
and #83's update merged into the PR branch.
Conflict: ROADMAP.md: header combines #84's threading change with next's 2026-10-11 changes; progress lines and change-log rows both (#84's 2026-10-12 first); stage line #84's (alpha ~5–7 h away)
Conflict: docs/gaps.md: #84's header text plus next's kerning/fonts/print changes
Conflict: docs/roadmap.md: next's M1 row (#186 done), #84's M2 row
Conflict: crates/engine/src/cmd/style.rs: next's side; add_to_swatches calls next's Document::rename_swatch_refs, #84's rename_in_story/rename_in dropped (next's covers text, tables, cells, notes and items); #84's test kept
Conflict: crates/idml/src/tests.rs: next's side (#84 carries #83's tests.rs, already merged in 9196a164)
Conflict: crates/tools/src/select.rs: overlays keeps next's content-move ghosts and live corners, plus #84's snapped loaded-cursor drag frame; a Place click without a drag shows nothing
Conflict: crates/ui-egui/src/i18n/it.rs: next's side (the Swatches hint entry is already further down)
Conflict: crates/format/src/lib.rs: next's side (upgrade, merge_duplicate_assets, then mark_differing_margins_local) in both loaders
Conflict: docs/target-app-parity.md: next's RTL and Interface Language lines, plus #83's "IDML Kashidas"
Brings #514 (MCP request replay), #523 final (already in next), #403
(character fill must name a swatch), #520 and #521 finals (already in
next as their PR heads).
Conflict: crates/engine/src/cmd/object.rs: next's side throughout (transform.move doc with content?, object.fill with tint alone from #525, move_content, reorder/content_move/group/tint_alone test modules); upstream's copy_ids_tests already in next
Conflict: crates/engine/src/cmd/text.rs: both; #403's validate_char_fill after next's ruby_cmd
Conflict: crates/pdf/src/export.rs: next's side (item/item_guarded cycle guard, frame_objects; upstream's anchored loop dropped as in d11ccad3)
Conflict: crates/render/src/lib.rs: next's side (drawing_items, draw_item/draw_item_inner)
The alpha gate's threading row and gap 0 shrink to the Primary Text
Frame page fixes (#165). New gaps: autoflow onto the existing following
pages, and threading into a grouped frame with the loaded text cursor.
#84 brings #83 and upstream main.
Conflict: ROADMAP.md: took #84's (main's restructured roadmap); the Input methods inventory line goes into docs/target-app-parity.md
Conflict: apps/designcraft/src/main.rs: kept this branch's discard_marked_text; config_dir lives in main's profile module
Conflict: crates/ui-egui/src/canvas.rs: keys go through keyboard_pane, which takes main's rule (only the focused pane, split or second window)
Conflict: ROADMAP.md: took #83's (main's restructured roadmap); the Threading inventory line goes into docs/target-app-parity.md
Conflict: crates/compose/src/lib.rs: kept this branch's undrawn trailing spaces after warichu; comment covers both the spaces and the drop cap
Conflict: crates/idml/src/tests.rs: took #83's (drop cap style as a Dropcap nested style, table style fills through the cascade); this branch has no changes of its own there
Conflict: ROADMAP.md: took main's restructured roadmap; this branch's inventory changes (Keep Lines Together default, IDML defaults, drop caps, IDML Kashidas) go into docs/target-app-parity.md, where the inventory lives now
Conflict: crates/format/src/lib.rs: load runs the format upgrade, then merges duplicate assets; kept both sets of tests
Do not resend a request after a transport failure. Report the uncertain outcome and reconnect on the next explicit request.
Validation: all six cargo xtask ci gates passed on the merge candidate; 1,177 native tests passed and all 15 WASM packages checked. Lost-reply, invalid UTF-8 and timeout probes reproduced duplicate edits before the fix and one edit afterward.
Task: #514
Closing the window or Quit (Cmd+Q, now a menu command instead of the predefined
terminate item) asks about each unsaved document: Save, Don't Save or Cancel.
The control channel's app.quit still quits without asking.
Conflict: crates/engine/src/cmd/print.rs: the PR's print_with/craft_print::submit; print_with and the test's expected bytes export through next's interchange::with_pdf_boxes
Conflict: Cargo.lock: next's lock plus only craft-print (the auto-merge had moved windows-sys back to 0.59/0.60 for several crates)
Conflict: Cargo.toml: craft-print entry moved beside craft-ui with a comment
Conflict: ROADMAP.md: status Change texts combined; both progress-log lines (the PR's 2026-10-11 line under the 2026-10-12 ones)
Conflict: docs/gaps.md: status Change texts combined
Conflict: docs/hardware-parity.md: status Change texts combined
Text set in Portuguese ("Portuguese: Brazilian", "Portuguese", pt_BR) got
no hyphenation, so justified Portuguese columns could only stretch their
word spaces (up to 335 % of the normal space in a 56 mm column of 10 pt
Times).
Turn on hypher's "portuguese" feature, beside Spanish: hyph-pt.tex 1.4
(2024-07-13) from hyph-utf8, BSD-3-Clause, credited in NOTICE.
Lang::for_language already maps the Portuguese names and locale codes.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Conflict: ROADMAP.md: both progress-log entries, #531's above next's 2026-10-11 lines.
Conflict: docs/typography-parity.md: status line lists next's changes and the Justification dialog.
Conflict: crates/engine/src/cmd/text.rs: selection_attrs keeps next's typing-format chars and adds paraMixed for {mixed: true}; mixed_para_attrs sits beside next's apply_typing_format and link_style.
Conflict: crates/ui-egui/src/dialogs.rs: titles, draw and confirm arms for both paragraphLocal and justification; the style dialog's justify arm calls the shared justification(), which uses next's composer_choice (Japanese composers) and selects neither composer when mixed; the style dialog's justification check moved into next's confirm_paragraph_style_options (section set to justify, reason in next's status line); tests from both sides.
Conflict: crates/ui-egui/src/i18n/ja.rs: union of rows.
Conflict: crates/ui-egui/src/i18n/uk.rs: union of rows.
Conflict: crates/ui-egui/src/menus.rs: UI_COMMANDS, run_ui arms and Type menu keep next's Paragraph Borders and Shading, Span Columns and Bullets and Numbering plus Justification… (Cmd+Alt+Shift+J, free on next) right after Paragraph Rules…; menu_enabled keeps next's IME check before the type.para check.
Auto-merged crates/ui-egui/src/panels/properties.rs: Justification… joins the Paragraph panel menu list after Paragraph Rules….
Type > Justification... and the Paragraph panel menu (Cmd+Alt+Shift+J) open
the Justification controls of Paragraph Style Options for the selected
paragraphs: word and letter spacing, glyph scaling, composer, kashidas and
Korean line breaks. Values that differ across the selection show empty, and
OK applies only the edited fields through type.para as one undo step.
Spacing values outside their range or out of minimum/desired/maximum order
keep the dialog open with the reason, in both dialogs.
type.selectionAttrs takes {mixed: true} and lists the paragraph attributes
that differ across the selected paragraphs as paraMixed.
Show/Hide Document Grid (View > Grids & Guides, Cmd+') draws the grid
on the positions Snap to Document Grid uses: subdivision and major
lines from each page's top-left corner, across the spread's band of the
pasteboard, behind or in front of page items as the grid settings say.
Dense lines are left out at low zoom. The Properties toggle runs the
command.
Rotate Spread is the rotation part of the Spread element's ItemTransform.
Import maps the three quarter-turn matrices to view_rotation on the spread's
first page and treats anything else as no rotation; pages and items keep
their unrotated spread coordinates. Export writes the rotation part for
document spreads; parent spreads stay identity.
Conflict: ROADMAP.md: progress log keeps both
Conflict: docs/target-app-parity.md: next's New Document line, the PR's Document Setup line
Conflict: crates/engine/src/cmd/layout.rs: setup_tests keep both tests
Conflict: crates/ui-egui/src/dialogs.rs: dispatch takes the PR's documentSetup block and keeps next's numberingSection; tests drop the PR's copies of dialog_context, dialog_frame, visible_label, click_dialog and scroll_dialog (next has them)
Conflict: crates/ui-egui/src/i18n.rs: TABLE keeps both; the PR's Top:/Bottom:/Left:/Right: rows dropped (next has them)
Conflict: crates/ui-egui/src/i18n/it.rs: keeps both; the PR's Top:/Bottom:/Left:/Right: rows dropped (next has them)
File > Document Setup now follows InDesign's layout: Intent, Number of
Pages and Start Page # with Facing Pages and Primary Text Frame (shown,
set when the document is made) beside them, Binding; a Page Size group
(preset menu keeping the orientation, width and height with arrows,
orientation icons); a Margins group (top, bottom, inside, outside, or
left and right without facing pages, with a link that keeps them equal);
Bleed and Slug (collapsible, a column per edge, a link per row); and an
Adjust Layout box whose button applies the changes with objects
following the new page size and margins.
Measures are read in the document's units (a plain 12 is 12 mm in a
metric document, not 12 picas). OK sends one layout.documentSetup (one
undo step); a value that can't be read keeps the dialog open with the
reason in the status bar. New strings are translated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Text set in Portuguese ("Portuguese: Brazilian", "Portuguese", pt_BR) got
no hyphenation, so justified Portuguese columns could only stretch their
word spaces (up to 335 % of the normal space in a 56 mm column of 10 pt
Times).
Turn on hypher's "portuguese" feature, beside Spanish: hyph-pt.tex 1.4
(2024-07-13) from hyph-utf8, BSD-3-Clause, credited in NOTICE.
Lang::for_language already maps the Portuguese names and locale codes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document uids start at 1 in every process, and every running app wrote
its recovery entries into the one recovery folder. Two apps wrote over
each other's `1.designcraft`, and an app that started reopened and
removed the entries of one still running.
A run now has a folder of its own in the recovery folder and holds a
lock in it for as long as it runs. An app that starts moves the entries
of runs that have ended, and those an earlier version wrote, into its
folder and reopens them. A locked folder is left alone.
Conflict: crates/ui-egui/src/dialogs.rs: next's Cell Options functions and the branch's `cancel` both kept; tests: next's test module with the branch's preferences_first_setting_switches_interface_language added and its scroll-down step added to next's preferences_horizontal_scroll_reaches_clipped_options
Conflict: crates/ui-egui/src/menus.rs: Edit › Interface Language submenu removed, next's Русский entry with it
Conflict: crates/doc/src/page.rs: next's Spread::parent_page_for_side is the one parent-page choice (single-sided pages take the first page); the branch's parent_page_index is dropped and its IDML import caller (crates/idml/src/import.rs) uses parent_page_for_side
Conflict: crates/doc/src/build.rs: the branch's parent_page_of/parent_page/parent_guides/margin sync on next's parent_page_for_side; tests both
Conflict: crates/engine/src/cmd/layout.rs: test modules both
Conflict: crates/engine/src/tests_idml.rs: tests both
Conflict: crates/format/src/lib.rs: next's upgrade and duplicate-asset merge, then the branch's mark_differing_margins_local, in both loaders
Conflict: ROADMAP.md: both log lines
Conflict: docs/target-app-parity.md: next's snapping line plus the branch's parent-page guides
Conflict: ROADMAP.md: status line lists both changes (the PR's review date); progress log both lines, the PR's first
Conflict: crates/ui-egui/src/i18n/ja.rs (auto-merged, edited): the PR's ("All", "すべて") row dropped, next already has it
Conflict: Cargo.lock: next's (the PR's dependency is already on next)
Conflict: ROADMAP.md: next's (the PR's earlier head is already merged)
Conflict: docs/gaps.md: next's (the PR's earlier head is already merged)
Conflict: docs/typography-parity.md: next's, test count 170 -> 172 as in d0120bf6
Conflict: crates/compose/src/optical.rs: next's plus d0120bf6's kernable() dash and fullwidth exclusion and its unit test
Conflict: crates/compose/src/tests.rs: next's plus d0120bf6's optical_kerning_leaves_dash_pairs_alone
ROADMAP.md ("Also shipped") and docs/localization-parity.md (language
table, count of shipped languages, revision history), as AGENTS.md asks
when an interface language is added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--export knew .pdf, .epub, .idml and .designcraft and saved a PNG of
the page under every other name: out.html, out.txt, OUT.PDF, and
out.designcraft from `script`. The exit status was 0.
.html and .htm now run file.exportHtml, .rtf and .txt run
file.exportText (the story being edited or of the selected frame), and
extensions match in any case. A name with another extension is an
error before anything runs; one with no extension is still a PNG.
`run` and `script` share one list, and `script` saves a copy for
.designcraft.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two dashes end to end have no ink gap to measure, so -- and the double
em dash opened up by the loosen cap; Chinese sets —— as one continuous
rule. Fullwidth Latin (U+FF21–FF5A) was kernable through its Latin
script and moved CJK text off its em grid. Both are now excluded from
kernable(), with a unit test and a compose test that failed before.
Optical kerning was treated exactly like Metrics: the font's kern pairs
and nothing else, so text set with Optical in InDesign came out wider,
rewrapped and went overset in tightly fitted frames.
Now the font's pairs are turned off for Optical text and each pair is
spaced from its outlines (crates/compose/src/optical.rs): every glyph's
ink is sampled into 28 bands across the em, the pair's mean and smallest
ink gap over the bands both glyphs ink are compared with the font's
stem-to-stem gap (the pair nn, or HH then oo), and the pair moves 60% of
the way towards it, keeping 30% of that gap and moving at most -0.12 or
+0.06 em. Latin, Greek and Cyrillic letters, digits and Western
punctuation take part; spaces, marks, missing glyphs, right-to-left
runs, upright and tate-chu-yoko glyphs and pairs across a fallback font
keep their font spacing. Profiles and references are cached, bounded.
Tests: AV, To and r. close up and nn stays; HH closes up under Optical
but not Metrics (fails on main); every change on a pangram stays within
the bounds and spaces keep their width; profile, gap, adjustment and
character-class unit tests.
Docs: typography parity Kerning row and remaining effort, gap 4,
ROADMAP milestone 6 and progress log.
Fixes#181.
Command descriptions left the new-text hyphenation default and image fitting outcomes implicit. State the default and each fitting mode's semantics, and add an MCP example that disables hyphenation. No behavior changes.
Route visible labels through the existing translation and RTL helpers.
Keep document commands, stored options and user-defined style names intact.
Update the localization status and roadmap progress log.
Conflict: ROADMAP.md: both progress-log entries, next's newer ones first
Conflict: apps/designcraft/src/gpu.rs: next's side; the branch's test fix targets the startup record tests next replaced
Conflict: apps/designcraft/src/main.rs: next's gpu startup and macOS IME helper; config_dir() dropped for the branch's profile::config_dir(), recovery_dir from profile::recovery_dir()
Conflict: crates/ui-egui/src/canvas.rs: next's guard (menu_open, keyboard_pane already limits keys to the focused pane)
Conflict: crates/ui-egui/src/lib.rs: modules from both sides
Conflicts:
- crates/ui-egui/src/canvas.rs (handle_input): the Alt-hand block comes
first, then next's zero point and ruler guide drags, which keep their
menu_open check. The Alt-hand press also waits while a canvas context
menu is open, like the other canvas presses.
- docs/ui-parity.md: the status line names both live corners and the
scrollbars.
show() reserves the 10 px strip on the right and bottom only, so the
rulers, the zero-point corner and guide drags keep their positions.