text-autosize 60551322.
Conflict: crates/doc/src/item.rs: next's reference-point doc and default auto_size_ref 4 (centre, as IDML leaves it) plus the branch's minimum-size and No Line Breaks fields
Conflict: crates/engine/src/lib.rs: autosize pass before next's record_undo_step on the success path; bump_revision for next's global revisions
Conflict: crates/engine/src/cmd/interchange.rs: next's grep_style_warnings and .indd comment plus the branch's autosize::apply on import
Conflict: crates/engine/src/cmd/object.rs: branch's textFrameOptions params doc with next's firstBaseline values
Conflict: ROADMAP.md: progress log both
Conflict: docs/gaps.md: next's optical kerning wording with the branch's auto-size note on #180
- layout.parents.edit takes `parent` (id, full name, or a prefix only one
parent has) and asks the canvas to fit that parent's spread; turning
editing on without one shows the first parent. The result names the
parent shown.
- Commands resolve parents by id, then full name, then a unique prefix.
Unknown or ambiguous names are errors, so a typo no longer clears a
page's parent; null or "[None]" clears it.
- Pages panel: only the row of the parent the canvas shows is selected;
rows, drag payloads and the Apply Parent menu carry the parent id.
Parent rows show rendered thumbnails of the parent spread, cached by
document revision like page thumbnails.
- Delete All Guides on a parent acts on the parent the canvas shows.
Fixes#624.
win-mixed-dpi 38dad0fb. Cargo.lock: next's lock plus the winit git source and the dpi 0.1.1 it brings (merged clean; cargo metadata --offline leaves it unchanged).
Conflict: apps/designcraft/src/main.rs: next's startup (adapter selection, catch_unwind, apple events) with log_uncaptured_errors at the top of its wgpu_render_state block; request_adapter_texture_size and mod gpu_limits merged clean
Conflict: ROADMAP.md: progress log both
Conflict: docs/hardware-parity.md: header keeps next's change list plus the mixed-DPI note
ar.rs covered 1,456 of the interface strings; the newer catalogs (it, ja,
pt-br, uk) had since grown to a 1,690-key union. This adds the 238 keys
Arabic was missing, in the same clean-room Modern Standard Arabic and
InDesign-style vocabulary the file already uses (كائن مرسّى، مسار مغلق،
خطوة وتكرار، الفحص المسبق، دمج البيانات، الكائن الأصل…):
- the whole menu-path family (نص/…، كائن/…، جدول/…، نافذة/…) — Type on a
Path, Track Changes, Story Direction, Transform Again, Pathfinder…
- the special-character and white-space inventory (شرطة كاملة، مسافة
شعرية، محرف نهاية الفقرة، علامات الاقتباس المستقيمة…) and their
symbols (رمز حقوق النشر، رمز العلامة التجارية…)
- data merge (سجل، سجلات في الصفحة، تحديد مصدر بيانات…), EPUB/HTML/XML/
IDML exports, proof setups and colour-blindness previews, anchored
objects, parent pages, slug and bleed fields, quick apply, preflight.
Same table, same lookups — Arabic now covers the union of every
language's keys, matching Japanese's completeness (1,694 keys).
upstream/main c3859c82 (#614e198eb5d, #6159509b2bc, #6168e151a2f, #617c3859c82).
Conflict: ROADMAP.md: header keeps next's change list plus orderly native exit recovery; progress log both
Conflict: apps/designcraft-cli/src/main.rs: next's case-insensitive .jpg/.jpeg check with main's write_atomic
Conflict: apps/designcraft/src/main.rs: on_exit keeps next's startup.presented() (not an Option) and adds preserve_documents_on_exit; next's discard_marked_text and main's preserve_documents_on_exit both; Services write uses write_atomic and keeps next's clipboard_text; tests both
Conflict: crates/engine/src/cmd/book.rs: main's ChapterBatch paginate with next's chapter-number resolution and {pages, chapters} result and doc
Conflict: crates/engine/src/cmd/file.rs: revert takes main's discard_document ordering without the revision + 1 (next's DocState::new hands out a fresh revision)
Conflict: crates/engine/src/recovery.rs: main's save_tracked, write_entry and open (st.bump_revision() for next's global revisions); next's reopen-twice test assertions kept
Conflict: docs/gaps.md, docs/target-app-parity.md: headers combined; next's Language, Books and Numbering lines plus main's book update safety line
A tab is at most 260 px wide. A longer document name ends in an ellipsis
(cut at a grapheme boundary, RTL names included), the dirty marker and
zoom stay readable, and the full name shows in the tab's tooltip. Tabs
and their close buttons carry accessible labels.
Fixes#603
In the frame a story ends in, Balance Columns lowers the bottom of the
columns after the last explicit column break as far as the text still
fits, reusing the bounded search that balances columns above spanning
paragraphs. Frames the text runs on from fill normally. Text Frame
Options gets a Balance Columns checkbox.
Conflict: crates/engine/src/cmd/object.rs: object.fit's doc keeps next's text and adds the `axis` clause; test modules from both sides
Conflict: crates/ui-egui/src/canvas.rs: kept next's input code (it sends the second press as Down with clicks: 2) and dropped the PR's release-time DoubleClick; the PR's UI test stays
Conflict: crates/tools/src/select.rs: the handle double-click joins next's second-press preamble, after the port checks and before editing text and the frame/content toggle (Down or DoubleClick with click_count 2 on a handle runs object.fit along fitting_axis); the DoubleClick arm stays empty; module doc from both
Conflict: crates/tools/src/tests.rs, ROADMAP.md: both sides
Height Only, Width Only, Height and Width and Keep Proportions frames fit
their text after every undoable command (same undo step) and after IDML
import, around the reference point, with minimum height/width and No Line
Breaks. Text Frame Options gains an Auto-Size section; IDML reads and writes
the minimum and no-line-break attributes. Applies to unthreaded frames and
the last frame of a thread; vertical frames and type on a path are left as
they are. (#180)
Conflict: crates/engine/src/cmd/file.rs: the spec keeps next's pdfCrop boxes and loadCursor with the PR's width bound and placement precedence; the PR validates `width` earlier, so next's later want_w line goes; next's loadCursor branch stays
color.sample takes `matchFrom`: with no opaque image pixel under the point (an empty part of an image frame, a transparent pixel), it applies that object's attributes as object.matchAttributes does, in the same command; the tool passes the object under the pointer. sample_item and the tool walk shown_children(), so only a multi-state object's active state is sampled, and sample_item skips points outside the graphic's clipping path. object.matchAttributes's body is a function both commands share.
Conflict: crates/engine/src/cmd/style.rs: object.color keeps next's apply_color, spec and enabled check (#84); takes the PR's color.sample (with next's enabled check), image_color_at and sample_item; drops the PR's color_swatch, color_items and has_text_or_selection; explicit `id`/`ids` win over a text selection in apply_color; the PR's tests follow next's caret behaviour (a caret takes the sampled colour for the next typing)
Conflict: crates/tools/src/tests.rs: both sides; the eyedropper test's Asset and Graphic literals gain next's pdf_crop, pdf_box, clip and wrap fields
Conflict: crates/ui-egui/src/i18n.rs, i18n/{ar,it,ja,pt_br,uk}.rs, ROADMAP.md: both sides
Conflict: crates/engine/src/tooling.rs: every with_ctx caller (IME preedit, commit, end, caret) takes the PR's `|s, cx| s.tool.…` form; pointer keeps next's end_composition before dispatch and tool_key its composing() early return
Conflict: crates/ui-egui/src/canvas.rs: the cursor block takes `space` from navigation_space, then the zoom branch, then `(space && !cmd) || alt_text`; the spring-zoom pointer events carry next's `clicks`; the PR's tests name their button helper `press` (next's tests have a `primary`) and compare cursors with what cursors::show sets for the engine cursor (next paints or rasterizes cursors per platform)
Conflict: ROADMAP.md, docs/target-app-parity.md, docs/ui-parity.md: status lines list both sides; progress and change-log rows keep both
winit 0.30.13 mishandles WM_DPICHANGED during a live drag on Windows 11:
the window flips between the two scales and grows past the GPU surface
limit. Pin winit to the one commit of rust-windowing/winit#4694, its
0.30.x backport of the fix.
The device asks for the adapter's largest texture side instead of
eframe's fixed 8192, and an uncaptured wgpu error is logged instead of
panicking, so a window larger than the surface limit draws wrongly
until it shrinks rather than closing the app.
Illustrator, VectorCraft, Figma and Inkscape put copied objects on the
system clipboard as SVG markup. Pasting it now creates editable paths, as
InDesign does with Illustrator art: fills, strokes (weight, caps, joins,
dashes) and opacity come through as unnamed colours, groups stay groups,
text comes in as outlines, CSS pixels become points (0.75 pt/px) and the
art is centred in the view. One undo step; garbage is refused.
- engine: edit.pasteSvg {svg, spread?, at?}
- canvas: Ctrl/Cmd+V with SVG on the clipboard (not while typing)
- Edit > Paste with nothing copied here asks for the system clipboard
- control channel: ui.paste {text}
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The update rebases the compact panel next has (already inside the control bar's scroll area) and adds accessibility labels and the progress line.
Conflict: crates/ui-egui/src/panels/mod.rs: next's swatch_list with the PR's swatch_picker returning the chip's response; next's swatch-list test discards it
Conflict: crates/ui-egui/src/chrome.rs: kept next's control-bar tests (they find the Fill chip by its group)
Conflict: crates/ui-egui/src/{lib.rs,object_control.rs}: rebased duplicates; kept next's side, then took the PR's labels
Conflict: ROADMAP.md: both progress lines
Conflict: crates/engine/src/cmd/layout.rs: Document Setup keeps next's refusal of an out-of-range start page; layout.section's spec keeps next's styles (kanji) with the PR's 1–99999 bound; the section body takes the PR's SectionEdit, whose start number goes through next's start_number check; tests keep next's section_start_numbers_are_bounded with the PR's one-undo-step test (the PR's start_numbers_are_bounded expects Document Setup to clamp, which next refuses, so it is left out)
Conflict: crates/doc/src/lib.rs: kept next's iterative saturating page_number; dropped the PR's second MAX_PAGE_NUMBER (next has it in page.rs)
Conflict: crates/ui-egui/src/dialogs.rs: next already leaves Enter and Escape to an open popup; kept next's side and added the PR's Style-menu key test
Conflict: crates/engine/src/cmd/mod.rs, crates/ui-egui/src/{i18n.rs,i18n/it.rs}: rebased duplicates; kept next's side
The update rebases the engine commits next has and adds the progress docs.
Conflict: crates/engine/src/cmd/{book,layout}.rs: rebased duplicates; kept next's side
Conflict: docs/target-app-parity.md: next's Language line (Norwegian) with the PR's Books line
The update rebases the tint fix next already has (60bf43b9, with the known-swatch check combined).
Conflict: crates/engine/src/cmd/object.rs, crates/ui-egui/src/{i18n.rs,i18n/it.rs,panels/properties.rs}: kept next's side
The PR's cut-per-column fix and its test duplicate next's equivalent (4f16d883); the merge records the head.
Conflict: crates/compose/src/lib.rs, crates/compose/src/tests.rs: kept next's code and tests
The update is a restack on #536 and #537 (whose selected-text fix next already has); #536's rebased head comes in as its base.
Conflict: crates/engine/src/cmd/text.rs, crates/fonts/src/{fontdb,lib}.rs, crates/ui-egui/src/{i18n,lib}.rs, i18n/it.rs, panels/font_menu.rs: rebased duplicates of PR code next has; kept next's side
Conflict: crates/engine/src/cmd/text.rs: kept next's selection_attrs (typing format, `mixed`) and took the PR's selected_text_preview for the selected text
Checkpoint the latest document state during App::on_exit after honoring current quit approvals. Keep incomplete or stale plans, clear recovery for clean documents and report unavailable or failed storage.
Follow-up to #545; cancelable macOS Dock Quit remains open in #544.
PR #617.
Conflict: crates/ui-egui/src/i18n.rs, i18n/{ar,it,ja,pt_br,uk}.rs, panels/properties.rs: rebased duplicate of the PR code next has; kept next's side and took the new pasted-into-frame fix
Conflict: ROADMAP.md: dropped the rebased duplicate progress line
Conflict: crates/engine/src/cmd/file.rs: spec strings keep next's (extension, return value, .indd); Save a Copy adds the extension then rebases data-source paths on a copy; file_save takes main's prepare-then-commit order with next's bump_revision
Conflict: ROADMAP.md: status line lists both changes; progress log keeps both sides
Keep recovered snapshots available through a second crash before autosave. Track checkpoint ownership across folders and restarted IDs; Save, Close and Revert clean only checkpoints owned by that document.
Follow-up to #506 and the retention concern in #380.
PR #616.
Prepare and stage every chapter before a book update writes files. Preserve imported IDML sources, reject open native chapters and report completed paths after a later write failure.
Follow-up to #485.
PR #615.
Route desktop writes and CLI raster exports through the engine atomic writer. Add actual-caller regressions for reader visibility, private modes, symlinks and valid long filenames.
Follow-up to #485.
PR #614.
Preserve document paths, revisions and collection contents when persistence fails. Rebase Save a Copy paths without changing the open document.
Follow-up to #485.
PR #613.
gaps.md gap 11, typography-parity.md (Tabs row), target-app-parity.md (typography row) and
ui-parity.md (panels row) described the Tabs panel as missing.
an_image_contour_stops_at_its_frame builds its Graphic with next's clip and wrap fields.
a_wrap_object_cutting_a_narrow_frame_leaves_its_sliver_empty and lines_in_band test a line's
band from its top to its baseline. New test: a Detect Edges clipping path overhanging its frame
wraps text (Same As Clipping) only within the frame.
Conflict: crates/compose/src/lib.rs: wrap_exclusion keeps next's custom boundary and outline closure, which now yields (outline, clipping frame) and limits the contour to the frame via Contour::within
Conflict: crates/compose/src/lib.rs: contour_path keeps next's (it, kind) form; Same As Clipping (the graphic's clip path) and Bounding Box (shown bounds) return the frame path as the clip, other kinds the frame with no clip
Conflict: crates/compose/src/lib.rs: main loop and estimate_slots keep next's grid and wrap_slot code; wrap_slot drops its desc argument and tests the band from the line top to its baseline (free_slots and the in-band edge search), for both callers
same_para_style_spacing uses deserialize_explicit_value, so Some(None) round-trips through
serde. Test: SameParaStyleSpacing as a Properties element on the based-on Normal style closes
the gap between consecutive headings; SetIgnore keeps the usual spacing.
Builds the desktop app and the CLI from source with `nix build`, and offers
packages, an overlay, `nix run`, a dev shell and a formatting check.
- Cargo.lock drives the dependencies (git sources via allowBuiltinFetchGit).
- Installs the desktop file, hicolor icons, MIME types and AppStream metadata
from packaging/linux/, validated at build time.
- Wraps the binaries so the dlopen'd libraries (libwayland-client,
libxkbcommon(-x11), X11, Vulkan loader, libEGL, libdbus for the portal file
chooser) are found on NixOS: native Wayland on GNOME and Hyprland, X11 as
fallback.
- Fonts from storytold/craft-fonts are pinned to the release workflow's revision
where the app embeds them.
- doCheck is off (the suite needs corpora and a GPU); `nix build` was verified.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Conflict: crates/compose/src/lib.rs: same-style gap replaces the pending space; otherwise next's text_above span space-before rule
Conflict: crates/doc/src/attrs.rs: same_para_style_spacing before the drop-cap fields and their doc
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/idml/src/tests.rs: both sides' tests
Conflict: crates/engine/src/atomic.rs: main's side (the reviewed #485 code supersedes the PR head on next)
Conflict: crates/engine/src/recovery.rs: main's #506 code, with next's write_entry helper kept
Conflict: apps/designcraft/src/profile.rs: main's own_run returning Option (and_then), with next's portable root_with argument
Conflict: crates/ui-egui/src/lib.rs: main's QuitState quit flow (d020b4e8) over the #545 head; next's Find Font alert guard; one import_warning_tests module (next's, with the Find Font test)
Conflict: apps/designcraft/src/native_menu.rs: next's MAC_APP_MENU layout, which already has the dc-quit item running app.quit
Conflict: ROADMAP.md: next's header with the quit change added; next's log entries then main's three
Conflict: docs/target-app-parity.md: main's atomic save, recovery and quit lines
File > Place of a text file with `link: true`, or with the new
Preferences > File Handling > Create Links When Placing Text Files,
records on the story the file's path, size and hash, and the style map
and style-conflict option used. The Links panel and links.list show
these files OK / Modified / Missing like graphics. links.update imports
a modified file again into the same frames and thread with the saved
style map (Auto Rename's choices are kept, so no new _wrd_ styles). As
in InDesign, edits made in the layout are replaced: the Links panel and
Window > Links > Update Link ask first (Update / Cancel) when a linked
story was edited in the layout, while the links.update command updates
and returns a warning, as InDesign scripting does. links.relink,
links.goTo and links.embed (Unlink) take {story}. Saved in the native
format; IDML writes the text unlinked. Tracked changes import as
accepted, as before. Tests cover place-with-link, Modified/Missing
status, update with the saved style map keeping frames, the
local-edits warning, the confirmation dialog (confirm, cancel, no
dialog for unedited stories), relink, unlink, the preference, and a
native save/load round trip. Closes#597.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-up.
- OK ran layout.section and then layout.chapterNumbering: two undo steps,
and a chapter start the second command refused (over 99 999) left the
section applied. `layout.numberingOptions {page, …section, chapter}`
checks both parts before the document changes and applies them in one
edit; the window's OK runs it. layout.section and
layout.chapterNumbering share its parsing.
- Enter or Escape with a Style menu open confirmed or closed the whole
dialog. Dialogs now leave both keys to an open popup (read before the
dialog draws, since egui closes a popup on Escape that frame).
- A start page of 4294967295 overflowed page_number (a panic in debug
builds, page 0 in release). Page numbers saturate; layout.section
refuses start numbers outside 1-99 999 (MAX_PAGE_NUMBER, as chapter
numbers) and Document Setup clamps its start page instead of wrapping
a 64-bit number into 32 bits.
Also rebased on main: the restructured ROADMAP keeps main's text, and the
inventory in docs/target-app-parity.md lists chapter numbering and the
window.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>