A single wrapping object moved by keep options or vertical justification had four passes to
settle before; one-per-object would have given it two.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* packaging: Flatpak finds and prints to CUPS printers
The Print dialog listed no printers in the Flatpak: the runtime has libcups but not
lpstat/lp, the sandbox couldn't reach the CUPS socket, and driverless network printers
(lpstat -e) need Avahi. Bundle lpstat/lp/lpoptions from CUPS 2.4.20 (Apache-2.0,
statically linked, licence installed) and grant --socket=cups and
--system-talk-name=org.freedesktop.Avahi in both manifests.
* packaging: Flatpak reads the user's CUPS settings (~/.cups, read-only)
Review (CodeRabbit): without it the sandbox's lp/lpstat ignore the user's default
printer and saved options (lpoptions) and a print server named in their client.conf.
* packaging: Flatpak CUPS tools reach the host socket when client.conf names a custom path
Review: Flatpak mounts the host's CUPS socket at /var/run/cups/cups.sock whatever
path ~/.cups/client.conf or CUPS_SERVER names, so lp/lpstat/lpoptions now run through
a wrapper that points a socket path missing in the sandbox there. Server names
(remote servers) and sockets that exist are left alone. Tested in the sandbox:
CUPS_SERVER=/run/custom/cups.sock lists the host's printers through the wrapper and
none without it; a host name is passed through unchanged.
* packaging: redirect a custom CUPS socket only when it is the one Flatpak mounted
Review (CodeRabbit): Flatpak picks the socket it mounts at /var/run/cups/cups.sock
with stricter rules than CUPS (flatpak-run-cups.c: a socket CUPS_SERVER, else the
first line spelled exactly "ServerName /path" in ~/.cups/client.conf, else the
default), while CUPS reads the keyword in any case and takes the last ServerName. The
wrapper now redirects only when CUPS' socket is the one Flatpak chose, so a job can't
reach a different server; otherwise CUPS fails on the missing path.
* packaging: never redirect a CUPS_SERVER the sandbox was given
Review (CodeRabbit): Flatpak picks the socket it mounts from the host's CUPS_SERVER,
so one set by flatpak run --env or an override may not be what it mounted. The
wrapper now leaves any CUPS_SERVER alone and redirects only a client.conf socket that
matches Flatpak's choice; otherwise CUPS fails on the missing path instead of
reaching a different server.
* packaging: point CUPS at the mounted socket only when it is the one Flatpak chose, else fail
Review (CodeRabbit): with a custom socket listed first and the default last in
~/.cups/client.conf, Flatpak mounts the custom one at /var/run/cups/cups.sock while
CUPS picks the last line, finds that path, and talks to the custom server. The
wrapper now compares CUPS' socket with Flatpak's choice even when the path exists:
equal, CUPS is pointed at the mount; different, the tool fails with an error instead
of reaching another server.
Found while testing crates/color/src/swatch.rs:94-101 (value_name)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/textimport/src/tagged.rs:~190-205 (the ParaStyle and CharStyle branches of import: `unescape_value(value.trim())`)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Keeping a 1 x 1 table for every further `<Table>` was unbounded in the one
direction the budget exists to close. `<Table></Table>` is fifteen bytes, so
the 512 MiB a part may decompress to holds some 36 million of them, and a
`Cell` is 1,360 bytes: tens of gigabytes, with every table inside both caps.
The test I wrote said as much without my noticing -- its invariant was
`reserved <= MAX + tables`, and `tables` had no bound.
`budgeted_size` now returns `None` once the budget is spent and the table is
not read at all, so the cells one import reserves are at most the budget,
exactly. The invariant is now `reserved <= MAX_IMPORT_TABLE_CELLS`, with no
term that grows with the file.
The warnings needed the same treatment, for the same reason: a file of 400,000
tables each claiming one row and two columns got a line about every one of
them. At most 20 are named, then one line saying the rest were the same, and
the file is told once that its tables ran out of cells between them.
InDesign always writes a document-level StoryPreference in
Resources/Preferences.xml; DesignCraft only wrote one per story. IDML readers
that take the spread reading order from the document's preference, such as
Okapi's IDML filter, failed on DesignCraft's files without it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reserve column and spanning footnotes when fitting inline table row groups. Continue rows in the next column or frame when the remaining space is too small, and include cell-local footnotes in measured row height.
Fixes#1901
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Show file and message dialogs without blocking the frame
A blocking rfd dialog inside the egui frame runs AppKit's modal loop; a
file dragged from Finder and held over the window then re-enters winit's
handler and aborts the app. Dialogs now go through craft-dialogs: a
command without a path asks with a continuation and returns, the host
shows the dialog at the end of the frame, and the continuation runs with
the answer on a later frame, in the document it was asked for. Commands
given a path stay synchronous. The replace-file question is a message
box from the same queue. Quit and Close wait for a Save As dialog's
answer. clippy.toml disallows rfd::FileDialog and rfd::MessageDialog.
* Raise the open file panel when File > Open is chosen again
* Repin craft-dialogs to the craft-libs PR head
* Queue dialogs asked by different code or documents; hold answers behind newer dialogs
Two asks for the same file dialog were treated as one, so Place for one
document and then Choose Image, or Place again for another document, ran
the first ask's action. An ask is now skipped (and the open panel
raised) only when the same code asked for the same dialog for the same
document. An answer that would replace an egui dialog opened since the
asking (an unsaved-changes question, Preferences) waits until it closes;
Quit counts it as pending.
* Repin craft-dialogs to the craft-libs PR head
* Allow the file dialogs' existence checks in the file guard
* Repin craft-dialogs to storytold/craft-libs main
* Honor CARGO_BUILD_TARGET in FreeBSD packaging for aarch64 release builds
The shared release workflow cross-compiles FreeBSD aarch64 in an x86_64 VM and sets
CARGO_BUILD_TARGET. package.sh ignored it: it built for the host, read binaries from
target/release, took the arch from uname -m (amd64 in the VM), and ran the cross-built
designcraft-cli --version on the host.
Take the arch from the target, build and read binaries from the target's directory, and skip
the host-side --version run when cross-compiling. Unset CARGO_BUILD_TARGET keeps the old behavior.
* Pick FreeBSD archive arch from CARGO_BUILD_TARGET with a release_arch helper
Follow soundcraft's pattern: native builds use uname -m, aarch64-unknown-freebsd and
x86_64-unknown-freebsd map to their arch, and any other target exits 2. The --version check
runs only when the archive arch matches the host arch.