Commit Graph
4115 Commits
Author SHA1 Message Date
eba00a0dec Opening documents: index lookups in Document::check and the format-1 style upgrade (#2218)
* fix(doc): index items, threads and styles when opening a document

* Apply review fixes

- crates/doc/src/tests.rs

* address review: borrow style names in pin_para_default

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
Co-authored-by: autocraft-bot[bot] <354215646+autocraft-bot[bot]@users.noreply.github.com>
2026-11-11 16:20:34 -05:00
Dylan M. Taylorandaiongg 15bea9fa7a Tagged Text, RTF, EPUB classes and PDF layers: lookups by set or map instead of list searches (#2212)
* fix: index style, font, class and layer name lookups in exporters and importers

* Apply review fixes

- crates/epub/src/css.rs

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-11 16:20:09 -05:00
Dylan M. Taylorandaiongg 5a3507510e File reads: refuse devices and pipes, cap whole-file reads (#2227)
* fix(engine): whole-file reads take regular files only, up to the format limit

* Apply review fixes

- crates/engine/src/io.rs

* Apply review fixes

- crates/engine/src/io.rs

* Fix failing CI check

- crates/engine/src/io.rs

* address review: refuse to save an encoded document longer than the open limit

* address review: open files for reading without blocking (FIFOs, stream-backed pseudo-files)

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-11 16:19:45 -05:00
Dylan M. Taylorandaiongg 8d59590449 Package: copy each font as it was loaded, check read roots, number duplicate names in one pass (#2208)
* fix(engine): package fonts from their loaded bytes under the read roots

* address review: a font's own file is neither overwritten nor packaged when it changed since loading

* Apply review fixes

- crates/engine/src/cmd/package.rs

* address review: compare packaged font file in fixed-size chunks

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-11 16:19:20 -05:00
Dylan M. Taylorandaiongg cfd99ba9b5 Automation roots: compare paths exactly; recovery reads only regular entry files (#2205)
* fix(engine): exact root containment and regular-file recovery entries

* Apply review fixes

- crates/engine/src/recovery.rs

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-11 16:18:55 -05:00
Dylan M. Taylorandaiongg 34f24a4d2a Gradients: expand midpoint stops in linear time (#2214)
* fix(color): sample gradients by binary search when expanding midpoints

* Apply review fixes

- crates/color/src/gradient.rs

* Apply review fixes

- crates/color/src/gradient.rs

* Fix failing CI check

- crates/color/src/gradient.rs

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-11 16:18:31 -05:00
Dylan M. Taylor eba5b9f845 datamerge: all further pages in one insertion, page lookups by start index (#2279) 2026-11-11 16:18:07 -05:00
Dylan M. Taylorandautocraft-bot[bot] c684db5428 Tools: selection bounds in one walk, bounded smart spacing and parent snapping (#2260)
* tools: selection bounds in one walk, caps on smart-spacing boxes and parent occurrences

* Apply review fixes

- crates/tools/src/lib.rs

* address review: iterative selection walk; stop collecting spacing boxes at the cap

---------

Co-authored-by: autocraft-bot[bot] <354215646+autocraft-bot[bot]@users.noreply.github.com>
2026-11-11 16:17:42 -05:00
Dylan M. Taylorandautocraft-bot[bot] 79d7a912f1 Strokes: cap the points a wavy or hashed stroke places along a path (#2188)
* Strokes: cap the points a wavy or hashed stroke places along a path

* address review: zero-length quadratic contributes no length in stroke samples

* Fix failing CI check

- crates/geom/src/stroke_style.rs

* Fix failing CI check

- crates/geom/src/stroke_style.rs

---------

Co-authored-by: autocraft-bot[bot] <354215646+autocraft-bot[bot]@users.noreply.github.com>
2026-11-11 16:17:18 -05:00
Dylan M. Taylorandautocraft-bot[bot] 589f5ff8a3 Engine: Erase and Smooth search each distinct drag sample once (#2272)
* engine: Erase/Smooth look at each distinct drag sample once, thinned past 4096

* Apply review fixes

- crates/engine/src/cmd/anchors.rs

* address review: decide whether a drag touched the path on every distinct sample, then thin

---------

Co-authored-by: autocraft-bot[bot] <354215646+autocraft-bot[bot]@users.noreply.github.com>
2026-11-11 16:16:54 -05:00
Dylan M. Taylorandaiongg bcbc3ed424 Story: appending text no longer scans every run and the whole prefix (#2245)
* doc: appending to a story extends the last run, no scans

* Apply review fixes

- crates/doc/src/story.rs

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-11 16:16:29 -05:00
Dylan M. Taylor ed3f45a57a render: cap the blend-area growth rounds, one name per optional-content layer (#2257) 2026-11-11 16:16:04 -05:00
Dylan M. Taylor 94c6798577 swatches panel: group membership and row lookups by name map (#2262) 2026-11-11 16:15:39 -05:00
.CooCoo 513f77b88e Tables: commands given a table id run with nothing in a table selected (#2607)
* Tables: commands given a table id run with nothing in a table selected

Table commands whose params list `story?` and `table?` (table.insertRow,
table.deleteColumn, table.options, the Convert Rows commands and the
others) were refused with "place the insertion point in a table" when the
call named the table but the selection was not in one. A call that passes
`table` now acts on that table whatever is selected. A table that is not
in the document, or not in the given `story`, is refused, and a `story`
that is not a non-negative integer is an error.

The menus are unchanged: with nothing in a table selected, the table
items stay disabled, and calls that name no table are still refused.

* Tables: a bad story is refused whether or not a table is selected

A call that names a table with a story that is not a non-negative integer (a string, a negative number, a fraction or null) was refused only when nothing in a table was selected. With a table selected, the command ignored the story and acted on the named table. Both paths now read story with one helper and refuse it the same way.

* Tables: an edit to a named table keeps a caret in footnote text

With the caret in footnote text, a table command that names a table
runs, and the edit cleared the caret's footnote address, so the next
typing went into the story. clamp_selection now leaves footnote
addresses alone, as in_cell does.
2026-11-11 19:56:37 +00:00
Dylan M. Taylor 19815eba4a Fix Flatpak permissions for update checks and self-updates (#2626)
* fix(flatpak): allow release checks and self-update helpers

* test: keep Flatpak permission parsing within strict Clippy rules
2026-11-11 14:24:07 -05:00
FredApps c64378ded9 Merge pull request #1936 from ashokram-si/feat/spread-spine-line-1838
Canvas: a spine line where the pages of a spread meet (#1838)
2026-11-11 07:57:58 +01:00
Dylan M. Taylor edd2f24bb0 address review: cap whole-reference strings and the resolved parameters of a step; range adjustment uses the inserted length 2026-11-11 05:11:14 +00:00
Dylan M. Taylor c85f7425a4 address review: build unvar value only when an instance exists; check interpolation length before copying; bound the limit-error preview 2026-11-10 21:48:57 -05:00
aiongg ef82d650db Fix failing CI check
- crates/engine/src/script.rs
2026-11-10 21:47:43 -05:00
aiongg 95acc4d47e Apply review fixes
- crates/engine/src/cmd/variables.rs
2026-11-10 21:47:43 -05:00
aiongg d0683224ca Apply review fixes
- crates/engine/src/cmd/variables.rs
- crates/engine/src/cmd/variables/tests.rs
- crates/engine/src/script.rs
2026-11-10 21:47:43 -05:00
Dylan M. Taylor e8f162ea9f fix(engine): end runaway loops in variable deletion, data-merge markers and nested scripts 2026-11-10 21:45:28 -05:00
skylar taylor-barrick 576e35b508 Merge pull request #1030 from midasmatterhorn/fix/r4-eps-tiff-preview-offsets
images: test WMF-only DOS EPS preview handling
2026-11-10 20:49:04 +01:00
skylar taylor-barrick c2211e0f41 Merge pull request #1161 from y-az/feat/anchored-text-frames
Anchored text frames: own stories and ids through copy, paste, duplicate, release and delete
2026-11-10 20:48:08 +01:00
9da88149be Fix Links panel stalls on network paths (#1444)
* Fix Links panel stalls on network paths

* Fix Links review findings

* Fix Links worker gating and wasm build

A link check blocked on another document's unreachable share no longer
holds back the document now shown: after 200 ms a fresh worker takes
over (at most four alive at once) and the stale result is dropped.

relinked_asset used the native-only fingerprint_from, breaking the
wasm build; it now uses fingerprint_of. The EPS relink and IDML link
reach tests build Windows paths correctly.

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

* Fix Links worker repaint and graphic read retry

Switching documents before the 200 ms takeover now schedules a repaint
for it: a blocked worker never asks for one, so without other input the
panel kept waiting. A failed graphic read is no longer cached as
missing, so the next check reads again. The legacy EPS fixture clears
its source fingerprint, as documents from before fingerprints have
none, so the test no longer depends on running within two seconds.

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

* Keep touched links OK and poll Links within seconds

Only a new size now marks a graphic Modified from its fingerprint. A
file with the same size but a new time (saved again, copied, restored
or checked out) is compared byte for byte, once per new time, and stays
OK when unchanged.

External changes are polled every two seconds instead of every five
minutes. The next check waits at least as long as the last one took
(up to five minutes), so a slow share stays idle half the time.

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

* Wake Links when a worker slot frees; translate check strings

A worker thread asks for a repaint when it ends, so a document waiting
at the four-worker limit gets a worker as soon as a superseded one
returns from its blocked call, without other input.

Rows from a check keep a weak reference to their document. The key
names it by address, which a later document can't reuse while the
allocation is kept.

The Links panel's new strings ("Checking", "Checking links…", "Link
status is unavailable.") use the UI's ellipsis and are translated in
every interface language. The comments on Session::text_link_checks and
on the byte comparison in links::status describe what they do now.

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

* Links: rows from the document, statuses from a check that can stop

The panel lists links from the document on the UI thread (no file is
looked at) and fills in the statuses a worker check last found, kept
per document. An edit shows at once, and a check of an earlier edit
still supplies statuses instead of being discarded.

- A check of another document is told to stop and ends before its next
  file; only one blocked in a file system call is replaced, so blocked
  workers no longer hold their slots for a whole document.
- Checks are timed on the worker, and what they remember passes to the
  worker that replaces them.
- A fingerprint is kept only for a file whose time was settled when it
  was read, as for linked text. A file found unchanged by its bytes
  gets its current size and time stored with the document
  (remember_link_files), without marking a saved document as changed.
- Asset::set_link keeps link and fingerprint together; copies made by
  Package and Copy Links To carry none.
- The Session holds one LinkListChecks. Update Link lists files only
  when a linked story was edited in the layout.
- The unused "Checking links..." caption is removed.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 17:39:39 +01:00
95abb2b03b pt-BR: translate 996 missing interface strings and the unit names (#1539)
* pt-BR: translate the 634 interface strings added since the catalog was completed

Covers the strings the catalog lacked after #495: tool names, menu
paths (Edit > Menus), Japanese typesetting dialogs (ruby, kinsoku,
mojikumi, warichu, kenten), special characters, Load Styles, Text
Frame auto-size, Data Merge, preflight, font replacement and About.
Tools are "Ferramenta X", parent pages "página principal", stories
"artigo"; menu paths reuse the existing menu names. IT, VA and Y:
stay as they are, as in every other language.

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

* pt-BR: one term per feature, the unit names, a catalog test and the docs

Review fixes for the new rows: Gradient Feather, stroke styles and type
on a path use the catalog's existing terms; warichu's Line Spacing no
longer reads as Leading; em/en dash, hair space, nonbreaking space and
hyphen and paragraph return take their Brazilian typographic names; the
file and word counts read correctly for one. File > New's unit names,
which reach tr at run time, are translated too.

The new test checks every pt-BR row's placeholders, padding and
ellipsis, and that each menu path is made of the menu names.

Docs: pt-BR re-measured at 2,416 of 2,419 strings (61% before) in
localization-parity.md, gaps.md (gap 21), target-app-parity.md and the
ROADMAP languages table and progress log. Readiness is unchanged.

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

* Docs: trace each localization count to its commit; list Russian

The 1,724 baseline was counted at a127c6d5 (#355); recounting that
commit by the same rule gives 1,723, with pt-BR at the same 1,057. The
2,419 strings are main at 438d7b6d. The 2,021 figure is gone: it was
the same rule at the last commit of 2026-10-10, not another scale.

Russian (ru, 1,705 of 2,419) joins the other shipped languages, which
makes six beyond the twelve; ROADMAP's two "Also shipped" lines become
one that includes it.

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

* pt-BR: the 12 strings main added since; docs re-measured at 2e36dcf9

Merging main brought window and guide commands, the InDesign shortcut-set
import and the credits' PRs column, which pt-BR didn't translate yet. Its
button label and result message reach tr as literals no other catalog
has, so they join the shared test's list of UI strings.

Re-measured at main 2e36dcf9: pt-BR translates 2,431 of 2,434 strings
(the Control panel's IT, VA and Y: stay English) and the unit names;
Russian 1,709 of 2,434. The PR adds 645 strings and 7 unit names.

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

* Docs: pt-BR at 2,574 of 2,941 strings by i18n-report; Russian listed

Re-measured on main f3bcc886 with `cargo xtask i18n-report`: pt-BR
translates 2,574 of 2,941 interface strings (1,933 before); the 367 it
lacks are mostly strings main added since 2026-10-23. pt-BR to full is
4-6 h. localization-parity.md, gaps.md (gap 21), target-app-parity.md
and the ROADMAP languages table and progress log say so, each with its
revision row; the ROADMAP entry is dated today, as the review asked.

Russian (1,855 of 2,941) joins the other shipped languages, eight beyond
the twelve, and ROADMAP's two "Also shipped" lines become one.

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

* pt-BR: drop two rows main removed; the test lists eight live labels

`cargo xtask i18n-report` flagged ten pt-BR rows whose keys its
interface list lacks. "/1000 em" and "Import InDesign Set…" are gone
from the code, so their rows go. The other eight still reach tr
(Auto-Sizing, Color Theme, Minimum Height/Width, No Line Breaks,
Reference Point, the shortcut-import result and the unavailable-fonts
message) and join the test's list of UI strings.

The report now counts 2,939 strings; pt-BR translates 2,572 of them
(88%), Russian 1,853. The docs say so; the PR adds 632 strings and the
7 unit names.

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

* pt-BR: the 364 strings main added since 2026-10-23

Keyboard Shortcuts sets (craft-keymap's dialog, import messages and
counts), panel docking, OpenType features, page presets, the Package
summary and the command dialog's parameter names. "Atalho", "conjunto"
and "escopo" for shortcut, set and scope; tab groups stay "grupo de
guias" and inks "de escala"/"especial", as in the catalog. Key names
stay as printed on keyboards.

`cargo xtask i18n-report` now lists only the Control panel's IT, VA and
Y: for pt-BR: 2,936 of 2,939 strings. The docs say so; pt-BR to full is
1-2 h (an in-app check and the older parent-page and story terms).

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

* pt-BR review fixes: Affix in, Dir, End, Pathfinder and three clashes; doc scales

- "Affix in" (where footnote prefix and suffix appear) is "Afixos em".
- "Dir" is a folder in file.save, recovery save and links.copyTo and a
  direction in text.move: "Pasta/direção".
- The End key is "Fim", as Home is "Início".
- Pathfinder keeps its name ("Objeto/Pathfinder"), as "Pathfinder:"
  already did, instead of "Localizador de caminhos" beside "demarcador".
- Pattern (stroke dashes) is "Padrão de traço", apart from Default
  ("Padrão"); Skipped is "Pulados", apart from "ignoradas"; Heading is
  "Intertítulo", apart from Title and Section headings.

ROADMAP's "Also shipped" line now uses one scale (today's i18n-report of
2,939 strings); the pt-BR note names main ef6c3686, and Russian reads
1,855 of 2,939.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 13:50:31 +01:00
aiongg 0078f832a7 Merge pull request #2179 from storytold/fix/sec-grep-compile-and-scan-budget
GREP: refuse subroutine calls and bound the empty-match scan
2026-11-09 21:23:30 -05:00
ljkx 32a1dbc734 Place: a graphic dropped on a line gets its own frame and leaves the line alone (#2290) (#2521)
* Place: a graphic dropped on a line gets its own frame and leaves the line alone (#2290)

drop_frame took any unlocked item under the pointer whose content takes a
graphic, so a file dropped on a line's stroke turned the line into a
zero-height image frame. It now also requires the item's path to enclose
an area, as the place cursor's click already does.

* Place: the next file of a drop doesn't replace a graphic that got its own frame (#2290)

A graphic dropped on a line, or on the page, gets a frame of its own at
the pointer but left frame_free set, so the next file of the same drop
found that new frame under the pointer and replaced the first graphic.
Any graphic placed by the drop now clears the flag.
2026-11-09 13:29:55 +00:00
autocraft-bot[bot] 57e68009da Fix designCraft 0.18.0: arrowheads point the wrong way on curves whose (#2515)
Fixes #2514.

- crates/doc/src/arrow.rs
- crates/doc/tests/autocraft_regression_2514.rs

Co-authored-by: autocraft-bot[bot] <354215646+autocraft-bot[bot]@users.noreply.github.com>
2026-11-09 12:53:59 +00:00
kuseidos bb54c44ad9 Command API: refuse a page index past the end, and say how many pages went (#2460)
* Command API: refuse a page index past the end, and say how many pages went

layout.pages.delete answered ok for an index past the last page and deleted nothing for it, so a caller off by one removed a different range and read a success; on a 336-page book that is page 337 instead of 336. Both commands now check every index against the document and refuse it with the sentence the MCP export commands have used since #70, return how many pages they touched so a no-op and a success are told apart, and state in their params that the indices count from 0.

* Pages: count the pages a delete will remove, not the indices it was given

delete_pages refused [0, 0, 1, 2] on a four-page document as if it would leave none, because the guard measured the length of the list instead of the pages it names. Same family as the index check next to it: the count was of the wrong thing. A test in the engine pins it.

* Pages: refuse a malformed page list instead of dropping what it cannot read

Review finding: page_indices used filter_map, so a list holding a string, a fraction or nothing at all was silently shortened — the caller was told a page was handled when it never was, which is the same mistake the command now refuses one level down. Every entry must be a whole number, and pages must be a list. Tests cover all three shapes, and the new test functions carry docstrings so the coverage check has nothing to report.
2026-11-09 04:05:22 +00:00
Dylan M. Taylor b08d60b912 Merge pull request #2488 from dotCooCoo/chore/craft-update-updater-fixes
Updates: the updater reports installing, ready, installed and failed, and installs at exit
2026-11-08 22:12:35 -05:00
NetterSilverandClaude Haiku 5.5 55729a5128 Skip RTF header/footer left, right and first-page groups on import
Found while testing crates/textimport/src/rtf.rs:43-63 (SKIP list) and :201 (`SKIP.contains(&word.as_str())`)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 02:45:42 +01:00
Dylan M. Taylor a337204cfe Geom: step budget in Pencil fit, stripe band cap, balanced Pathfinder union (#2251)
* geom: step budget in freehand fit, stripe band cap, balanced unions

* move test
2026-11-08 22:56:03 +00:00
dotCooCoo 076c6b1afc Updates: the updater reports installing, ready, installed and failed, and installs at exit
craft-update moves from c5a1cbfb to c7c84230 on dotCooCoo/craft-libs, a
branch that merges storytold/craft-libs#687 and #696 into craft-libs main.

The check result window shows for every status but idle and stays closed
while the startup prompt is open. At the first start after an update it
reports that the update installed or why it failed. Its Restart to Update
calls Updater::restart_to_update. The install helper now starts when the
app exits and drops the updater.
2026-11-08 12:46:13 -08:00
NetterSilverandClaude Haiku 5.5 5da2393e28 Reject signed row numbers in XLSX cell references
Found while testing crates/textimport/src/xlsx.rs:15

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 18:14:57 +01:00
Youssef Azriouil 241d0a41db Copy: drop the second pass over anchored stories in the clipping 2026-11-08 16:13:58 +01:00
aiongg 8e34117922 Apply review fixes
- crates/engine/src/cmd/file/new.rs
2026-11-08 14:29:02 +00:00
NetterSilverandClaude Haiku 5.5 4a7fc340f8 Clamp negative gutter in file.new and file.savePreset to 0
Found while testing crates/engine/src/cmd/file/new.rs:179 (apply_settings: `nd.gutter = f64_or(p, "gutter", nd.gutter)`); compare crates/engine/src/cmd/layout/margins.rs:101 (`g.max(0.0)`)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 15:10:20 +01:00
aiongg 8ca6149325 Apply review fixes
- crates/pdf/src/gradient_inks.rs
2026-11-08 13:06:21 +00:00
NetterSilverandClaude Haiku 5.5 c73699374f Clamp midpoint in Gradient::expanded_stops like sample does
Found while testing crates/color/src/gradient.rs:~101-110 (expanded_stops); the unclamped value comes from crates/idml/src/import/swatches.rs:128-129

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 12:49:47 +00:00
NetterSilverandClaude Haiku 5.5 8e5e40d76b Drop signed numeric character references in DOCX XML parser
Found while testing crates/textimport/src/docx.rs:132-133 (parse, Event::GeneralRef branch)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 08:32:16 +00:00
NetterSilverandClaude Haiku 5.5 88a45f5d58 Apply typographic quotes when xref format has an unterminated '<'
Found while testing crates/doc/src/xref.rs:~100 (expand, early `return out` in the `tag_end` None branch)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 06:10:10 +01:00
aiongg f16065eaee Merge main into feat/anchored-text-frames 2026-11-08 02:22:05 +00:00
Kushagra Kumar f9cfd99adc Text: adjust hyperlink and placeholder source ranges on story edits (#1219) (#1229)
* Text: adjust hyperlink and placeholder source ranges on story edits (#1219)

Text-anchored hyperlinks and data-merge placeholders store byte ranges
(`start..end`) pointing into story text. When text earlier in the story is
inserted or deleted, these offsets remained unchanged, causing hyperlink
targets and data-merge placeholders to drift across unrelated text or
point to invalid UTF-8 boundaries.

This change:
- Implements `Document::adjust_text_ranges` in `designcraft-doc` to shift
  or resize text hyperlinks and placeholders when story text is edited.
  Pure insertions at or before the link shift it forward; insertions
  inside expand the link's span; deletions before shift it back; deletions
  consuming or overlapping the link clamp to surviving text or prune it if
  entirely consumed.
- Cleans up obsolete hyperlinks and placeholders in `set_story_text`.
- Wires range adjustment into engine text commands: typing, deleting,
  selection replacement, autocorrect, `story.replaceRange`, find/change,
  and spelling change.
- Adds comprehensive unit tests in `designcraft-doc` and 7 integration
  regression tests in `crates/engine/tests/hyperlink_offsets.rs`.

* fix(engine): adjust hyperlink and placeholder ranges for physically removed text under track changes

* fix(engine): adjust text ranges for formatted paste, case change, and drag move

* fix(engine): record change case adjustments per character to preserve enclosed hyperlinks

* fix(engine): adjust text ranges for track changes, inline markers, and preserve zero-length ranges

- Route Track Changes accept/reject deletions through adjust_text_ranges, and transfer replaced text hyperlinks to inserted text so links survive accept.
- Hook inline marker operations to adjust_text_ranges (notes, endnotes, xref, anchored objects, index markers, tables, editorial notes, unvar, and place text).
- Replace datamerge::shift_after with adjust_text_ranges.
- Only prune ranges that the edit emptied (s < e && s_new >= e_new), preserving zero-length ranges.
- Drop inverted ranges first and use saturating arithmetic in remap_range.
- Preserve doc.hyperlinks and placeholders ordering in move_text_ranges by mutating in place.
- Remove dead wrapper mark_deleted and call mark_deleted_reporting.
- Fix changes.track invocation parameter to 'on'.
- Add comprehensive regression tests in doc and engine covering all review items.

* fix(text): guard cell find/change, pre-record tracked replaces, shift para xref anchors

* fix(text): record stable IDs for tracked replacement redirects

* fix(text): reconcile range adjustments for review feedback

* fix(text): adjust ranges on delete surrounding and clean up dead auto edit

* Prune text ranges on TOC index and live caption regeneration

* test(engine): format regenerating_index_prunes_story_hyperlinks line wrap
2026-11-07 19:54:00 -06:00
FredApps 7e32b5ffd5 Merge pull request #2412 from ZIDAN44/fix/2401-white-overprint-preflight
Preflight: white or [Paper] set to overprint is reported (#2401)
2026-11-07 15:38:00 +01:00
NetterSilverandClaude Haiku 5.5 6365f98abe Keep Lab::hue within 0..360 for tiny negative b
Found while testing crates/color/src/cms/lab.rs:25-27 (Lab::hue)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 12:56:41 +00:00
NetterSilverandClaude Haiku 5.5 2fb2689efe Normalize marquee rect in hit::intersects_rect
Found while testing crates/geom/src/hit.rs:28-35 (intersects_rect: `path.anchors().any(|(_, _, a)| r.contains(a.p))` and the early-out using `b.intersect(r)`)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 11:14:34 +01:00
aiongg e977f82558 Fix [Bug Report] [DesignCraft] Image content and frame don't move together (#2423)
Fixes #2422.

- crates/engine/src/cmd/object.rs
- crates/engine/tests/autocraft_regression_2422.rs
2026-11-06 18:21:30 -05:00
Zinadin Zidan cd315908aa Preflight: a frame with states is looked at as PDF export draws it (review)
Flex Layout's convert turns a multi-state group into a frame that keeps
its states. PDF export draws every object pasted into a frame, but the
white overprint check walked only the active state, so a white
overprint in another state printed unreported. Which children export
draws is now one function, drawn_children, used by both.
2026-11-07 03:07:28 +06:00
Zinadin Zidan 231ee6d4c3 Preflight: white overprint is looked for where PDF export prints (review)
Ruby and kenten in a threaded story were reported against the story's
first frame, on its page, wherever the text was; they are now reported
against the frame that shows them, and text no frame has room for isn't.
Parent pages' items and anchored objects print too and weren't looked
at; items on a hidden or nonprintable layer, or in a hidden or
nonprinting group, don't print and were reported. The check now walks
the items as PDF export draws them, with its rules (the parent page
items a page shows now come from one function both use), and a frame
PDF export leaves out reports none of its ruby and kenten.
2026-11-07 02:09:42 +06:00