Commit Graph
2376 Commits
Author SHA1 Message Date
22e99fc2b7 Tables can be copied and cut: whole tables, rows and cells (#1744) (#1784)
* #1744: WIP

* #1744: Select Table copies and cuts the whole table

Copy of a whole-table selection used to keep only the cells' paragraphs
(copy_blocks flattened a cross-cell range), and Cut only cleared the text.
Now Copy puts the table on the clipboard and Cut removes the table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #1744: selected table rows and cells copy as a table; Cut clears their text

Copy of whole rows, cells of a row or a block of cells puts a table of just
those cells on the clipboard (Table::slice). Cut of rows or cells clears their
text and keeps the rows and cells, as in Word (Word check A).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #1744: review fixes

Table::slice widens every row to a merged cell partly selected (no ragged
copy); an empty selected table or cell copies and cuts; a text selection over
exactly a nested table copies it; one selected_table per Cut; tests for
slice merges/widths/controls, tracked and locked cuts, and the text route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #1744: Cut clears every cell Copy takes; Spike stays off for empty cell selections

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* #1744: a copied part of a percentage-width table keeps a point width

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* ROADMAP: tidy merged header

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* ROADMAP: keep only the #1744 rows over main's version

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* ROADMAP: remove conflict markers; keep only the #1744 rows over main's version

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* #1744: rename the range Cut helper clear_range_cells (main added clear_cells)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Remove conflict markers from ROADMAP.md; leave main's header line alone

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* cargo fmt

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Import Path in table structure after merging main

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-29 21:47:27 -04:00
Fin WarmanandBrandon Thomas f658c872a2 Tables: share spanning minima by preferred widths (#1883)
* Tables: share span minima by preferred widths (#1883)

* 1222: Match nested preferred span weights

* docs: word the #1883 layout-parity entries

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-29 21:40:41 -04:00
Fin WarmanandBrandon Thomas a066fe5f13 Keep zero-sized paragraph frames in normal flow (#2810)
* 411: Keep zero-sized paragraph frames in normal flow

* M2.1: keep frame controls consistent with document defaults (#2810)

* M2.1: check the final frame round trip (#2810)

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-29 21:38:01 -04:00
Dylan M. Taylor ccb8ce8494 packaging: Flatpak finds and prints to CUPS printers (#4909)
* 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.
2026-10-29 18:48:31 -04:00
skylar taylor-barrick 165d5725dc Merge pull request #4894 from OPUZZLES/opuzzles/pilot-recipient-label-sheets
Labels: continue selected recipients across sheets (#4880)
2026-10-29 14:18:49 -06:00
OPUZZLES 01a1bf3921 M9: assert unused recipient labels are empty (#4880) 2026-10-29 18:14:46 +01:00
OPUZZLES 5a9e414d1e M9: generate all recipient label sheets (#4880) 2026-10-29 17:49:08 +01:00
Dylan M. Taylor aadb077e07 Honor CARGO_BUILD_TARGET in FreeBSD packaging for aarch64 release builds (#4760)
Add packaging/freebsd/package.sh, matching the sibling craft apps. The release
workflow cross-compiles aarch64 FreeBSD in an x86_64 VM with CARGO_BUILD_TARGET
set; the script builds with --target, reads binaries from the target directory,
names the archive after the target arch, and checks ELF/FreeBSD/arch instead of
running binaries that cannot run on the host.
2026-10-28 15:53:55 -04:00
Dylan M. Taylor 9724f15c3d Grant network access so update checks can reach GitHub (#4741) 2026-10-28 13:36:48 -04:00
Brandon ThomasandClaude Opus 5.5 3de6ff95af Release 0.12.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.12.0
2026-10-28 11:52:06 -04:00
Brandon ThomasandClaude Opus 5.5 65bb8b3709 macOS packaging: retry stapler when Apple's CloudKit drops the connection
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 11:52:00 -04:00
Dylan M. Taylor c4fafc2154 Enforce Rust coding standards via Clippy (#4501)
* Refactor doc for strict Clippy checks

* Refactor docx for strict Clippy checks

* Refactor engine for strict Clippy checks

* Refactor fonts for strict Clippy checks

* Refactor formats for strict Clippy checks

* Refactor layout for strict Clippy checks

* Refactor mcp for strict Clippy checks

* Refactor pdf for strict Clippy checks

* Refactor proof for strict Clippy checks

* Refactor render for strict Clippy checks

* Refactor ui canvas for strict Clippy checks

* Refactor ui dialogs for strict Clippy checks

* Refactor ui ribbon for strict Clippy checks

* Refactor ui support for strict Clippy checks

* Refactor wordcraft-cli for strict Clippy checks

* Enforce workspace Clippy standards and document lint policy

* Deflake the IME epoch test

* Fix platform-gated imports for wasm builds
2026-10-27 22:00:30 -04:00
Dylan M. Taylor df5a59275d Fix platform-gated imports for wasm builds 2026-10-28 01:24:26 +00:00
Dylan M. Taylor ab91e9f96c Deflake the IME epoch test 2026-10-28 01:06:49 +00:00
Dylan M. Taylor 1c8f6e9257 Enforce workspace Clippy standards and document lint policy 2026-10-28 01:06:48 +00:00
Dylan M. Taylor bc05149bd9 Refactor wordcraft-cli for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 51c70e1606 Refactor ui support for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor ac2cc0c4ef Refactor ui ribbon for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 9c0f61356c Refactor ui dialogs for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 260a629e9e Refactor ui canvas for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 1ecb22c67d Refactor render for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 36f6244cd4 Refactor proof for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor ffaeda9316 Refactor pdf for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 815d3f0032 Refactor mcp for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 937c7e532d Refactor layout for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 7976368de7 Refactor formats for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 0436139c57 Refactor fonts for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor a2435388e5 Refactor engine for strict Clippy checks 2026-10-28 01:06:48 +00:00
Dylan M. Taylor 75d30d69b4 Refactor docx for strict Clippy checks 2026-10-28 01:06:47 +00:00
Dylan M. Taylor 1d3e6d9ca8 Refactor doc for strict Clippy checks 2026-10-28 01:06:47 +00:00
aiongg d522bfd8b1 Merge pull request #4492 from Jeremy8776/feat/install-scope-policy
Windows installation policy: WordCraft
2026-10-27 17:08:58 -04:00
aiongg 0bd3420553 ci: use storytold/craft-common-actions at the merged installer-policy commit 2026-10-27 20:51:47 +00:00
Jeremy 54e1b1e7f3 fix(installer): check the exact architecture-specific machine folder
The pre-signing check matched any folder named Program Files, so it rejected
a valid MSI when Windows resolves Program Files elsewhere, accepted the 64-bit
root for an x86 package and accepted a different app name. Build the expected
folder from the package architecture's resolved root and the policy name.
2026-10-27 19:13:02 +00:00
aiongg 4b8b06fe03 Merge pull request #4602 from Silvertree2010/perf/export-speed
Speed up PDF export by about 24 %
2026-10-27 13:41:24 -04:00
NetterSilverandClaude Opus 5.5 de3bfaf049 Keep harfrust shape plans per face
Each shaping call let harfrust compile a new shape plan (the face's
lookups for the run's script, direction, language and features), which
took about as long as shaping a short run. Each thread now keeps up to 64
plans (the oldest dropped to make room), found by face and harfrust's
ShapePlanKey::matches, and passes the plan to the shaper. A kept plan is
only used for the face it was made for: the face id (from one process-wide
counter, so no two faces share it) together with the font bytes' address,
length and face index. The plan is the one the shaper would have made for
the buffer, so the glyphs are the same; tests shape with kept and fresh
plans and compare, and check the per-thread bound.

PDF export of the export_bench document (259 pages), interleaved with main
(A/A within 1 %): median 421 ms -> 319 ms (-24.2 %), measured on a loaded
machine; on a quieter run earlier 294 ms -> 224 ms (-23.8 %). PNG export of
page 1 (which lays out the whole document): about -34 %. The PDF and PNG
bytes are identical to main's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:39:37 +01:00
aiongg f8e327b068 Merge pull request #3936 from benandez/fix/3907-section-marks
#3907: continuous sections running off a page go onto the next; empty section marks in a row stack to the page bottom
2026-10-27 12:37:46 -04:00
aiongg 50a8ebe307 Merge pull request #4387 from benandez/fix/3872-followup
#3872 follow-up: font table found by its stored spelling; privacy scrub keeps attribute values well-formed
2026-10-27 12:37:26 -04:00
aiongg f270dbd3b0 Merge pull request #4060 from benandez/fix/3995-thai-test-guard
#3995: Thai one-face fallback tests skip unless a Thai font with Latin is installed
2026-10-27 12:37:05 -04:00
Jeremy ffa35d62db fix(installer): resolve the wizard scope and folder correctly
Real msiexec runs (per-user and all-users, silent and wizard) found two defects
that the metadata fixtures cannot see:

- "Only for me" published ALLUSERS=2, so FindRelatedProducts treated the run as
  per-machine and skipped the existing per-user copy. An interactive upgrade
  left two registered products and uninstall left files behind. The page now
  leaves ALLUSERS unset for a per-user choice.
- Windows Installer resolves Program Files once, for the context it started in,
  so choosing "Everyone" in the wizard installed into the user profile with a
  machine-wide registration. The wizard now sets the new-install folder itself
  after the choice (Program Files, Program Files (x86) for 32-bit, or the
  per-user Programs folder). Silent installs are unchanged.

check-install-policy.ps1 now fails if either regresses.
2026-10-27 15:32:42 +00:00
aiongg 436d444ef0 fix(ui): dropdown menus grow back after a search with no matches (#4577)
* ui: craft_ui::ComboBox everywhere and the combo arrow popup on craft_ui::combo::Menu

Repin craft-libs to aiongg/craft-libs 62bb0e1d (dropdown regrow). Ban egui::ComboBox in clippy.toml.

* chore(deps): craft-libs 60d60d48 (dropdown fixes)

* chore(deps): craft-libs 6af63481 (dropdown fixes)

* chore(deps): craft-libs 4d7b82f7 (dropdown fixes)

* chore(deps): craft-libs 92d392cf (#387 merged)
2026-10-27 10:27:21 -04:00
NetterSilverandClaude Opus 5.5 ffa127c615 Skip per-character table lookups for plain text in layout and PDF export
Shortcuts that give the same answers as the lookups they skip:

- is_rtl: nothing before U+0590 is right to left, so Latin, Greek and
  Cyrillic text skips the bidi class search.
- strong_rtl and is_mark: ASCII letters are the only strong ASCII
  characters, and no ASCII character is a mark.
- cluster_starts: in ASCII text every character starts a grapheme except LF
  after CR, and no ASCII character joins a cluster.
- display lines: a glyph run's vectors and text are sized up front, and the
  symbol-font check is made once per run instead of once per cluster.
- PDF glyph runs: the baseline (the y most glyphs share) is only worked
  out for italic runs, the only ones that use it, and a run on one baseline
  returns it without counting.

Tests check each shortcut against the full lookup (every code point for the
bidi classes, every ASCII pair for the clusters).

PDF export of the export_bench document, interleaved with main: median
293 ms -> 241 ms (-18 % with the previous commit). The PDF bytes are
identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:39:09 +01:00
NetterSilverandClaude Opus 5.5 8cdc172171 Lay out the paragraph after a kept heading once
A paragraph with keep with next measures the paragraph after it before it is
placed (next_first_line). That measurement called layout_para directly, so
every paragraph following a heading was laid out twice in each layout pass:
once to measure it and once, through the cache, when it was placed.

The measurement now goes through the layout cache under the key
para_labelled uses (Ctx::para_ahead) when its inputs are the same: no
proofing, no typed word, not inside a text box, no inline text boxes that
resize, the body's tracked-deletion view. Otherwise it is laid out on its
own as before. It counts nothing (list labels, equation numbers and the
page-total flag are restored), so pagination is unchanged.

Adds crates/engine/examples/export_bench.rs, which saves a long generated
document (the sample document 200 times, 259 pages) through io::save_bytes
and prints wall times:

  cargo run --release -p wordcraft-engine --example export_bench -- pdf 200 9

PDF export on that document, interleaved with main (Ryzen, 16 threads):
median 286 ms -> 256 ms (-10.6 %). The PDF bytes are identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:39:09 +01:00
Jeremy d603983a61 docs(installer): note that the 32-bit all-users folder is Program Files (x86); tidy wording 2026-10-27 12:25:21 +00:00
Jeremy 72b8818ea6 packaging(windows): ship one dual-scope MSI
The package is dual-scope, so the separate -windows-user MSI was the same package under a
second name. Build and policy-check the single plain-named MSI before signing, which is the
name every sibling app, the launcher and the shared windows-arm64 workflow use. Replace the
loop test with one that checks the MSI is policy-checked once, before it is signed.
2026-10-27 12:17:18 +00:00
Jeremy 3031870ce3 docs(installer): describe the per-user default install location and scope 2026-10-27 12:09:04 +00:00
Jeremy 1b0a59d4d2 fix(installer): harden install-policy checks and packaging-lint workflow 2026-10-27 12:02:00 +00:00
Jeremy 8edd6cb8eb fix(installer): address scope and ARM64 review feedback 2026-10-27 12:01:59 +00:00
Jeremy 89a059fb2d feat(installer): default to a per-user ArtCraft folder 2026-10-27 12:01:59 +00:00
Martin BallandClaude Opus 5.5 1b485e1f90 #3907: CodeRabbit — a kept paragraph is measured against the next page's body (a different first-page header)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:24:50 +00:00
Martin BallandClaude Opus 5.5 751eb4b204 #3907: CodeRabbit — a stacked mark past the page bottom draws no line number either
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 10:39:26 +00:00