Commit Graph
295 Commits
Author SHA1 Message Date
Brandon Thomas 80663cccfd Merge PR #846 2026-10-14 01:54:43 -04:00
Brandon Thomas 9dc2068580 Merge PR #857 2026-10-14 01:54:41 -04:00
Brandon Thomas d34384574c Merge PR #853 2026-10-14 01:54:37 -04:00
Brandon Thomas d83184f8b3 Merge PR #863 2026-10-14 01:54:37 -04:00
0f4f382b0e feat(text): improve editing, snapping, and threading
Add multi-click text selection, pending caret formatting and clipboard support, text-aware colour controls, guide/grid snapping, and frame threading with loaded-port interactions.

Include the layout, drop-cap and IDML updates carried from #83, with safeguards for generated and linked stories, external text references, local IDs, locked frames and atomic colour edits.

Fixes #23.

Co-authored-by: Sean Hammond <sean.hammond@und.edu>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:41:46 -06:00
noah1400 554019cdd5 Tables: table.options limits header and footer rows (#861)
table.options added as many rows as the requested header and footer
counts needed, without a limit. A large number typed into the Table
panel's Header Rows field froze the app and exhausted memory. Both
counts are now capped at 100, the limit table.insert already has.
2026-10-14 00:32:16 +02:00
sanyamsingh001andCodex bfa536352d FIX-CHILD-NOTE-PASTE: filter unsupported markers in child stories
Co-Authored-By: Codex <codex@openai.com>
2026-10-14 07:54:46 +10:00
noah1400 1bddba0e75 Compose: cross-reference index no longer rebuilds itself (#851)
The cross-reference index composed its destination stories through
the cache. One with a running header asked for the running-header
index, which composed the story holding the cross-reference, which
asked for the cross-reference index again: the stack overflowed and
the app aborted. Destination stories with a running header are now
composed without it, like those with cross-references already were.
2026-10-13 23:07:21 +02:00
sanyamsingh001andCodex f4f2f0bb08 FIX-TABLE-SELECTION: resolve selected merged-cell owners
Co-Authored-By: Codex <codex@openai.com>
2026-10-14 06:20:41 +10:00
Brandon ThomasandClaude Opus 5.5 e862e0a613 fix: integrate batched community PRs (#572 with #662's fallible spread_param; #524's test helper back in its module)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:28:50 -04:00
Brandon Thomas 777d8c3251 Merge branch 'pr/572' into batch1
# Conflicts:
#	crates/tools/src/tests.rs
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/src/i18n/ar.rs
#	crates/ui-egui/src/i18n/it.rs
#	crates/ui-egui/src/i18n/ja.rs
#	crates/ui-egui/src/i18n/pt_br.rs
#	crates/ui-egui/src/i18n/uk.rs
2026-10-13 02:24:24 -04:00
Brandon Thomas 89e9abbc8d Merge branch 'pr/662' into batch1
# Conflicts:
#	crates/engine/src/cmd/object.rs
2026-10-13 02:23:56 -04:00
Brandon Thomas a390905beb Merge branch 'pr/647' into batch1
# Conflicts:
#	crates/tools/src/lib.rs
#	crates/tools/src/tests.rs
#	crates/ui-egui/src/canvas.rs
2026-10-13 02:23:33 -04:00
Brandon Thomas 0a14d9fb97 Merge branch 'pr/539' into batch1 2026-10-13 02:23:12 -04:00
Brandon Thomas 2103af784a Merge branch 'pr/537' into batch1 2026-10-13 02:23:11 -04:00
Brandon Thomas d5613411ca Merge branch 'pr/522' into batch1 2026-10-13 02:23:11 -04:00
Brandon Thomas 6e551af3e7 Merge branch 'pr/663' into batch1 2026-10-13 02:23:11 -04:00
Brandon Thomas b758c6180a Merge branch 'pr/649' into batch1 2026-10-13 02:23:11 -04:00
Brandon ThomasandClaude Opus 5.5 b70b586a16 fix(path-type): NaN-safe bracket clamping (f64::clamp panics on a NaN path length)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:22:34 -04:00
Brandon Thomas 878169130e Merge branch 'pr/600' into batch1 2026-10-13 02:21:53 -04:00
Brandon Thomas 8a36af3af8 Merge branch 'pr/630' into batch1 2026-10-13 02:21:53 -04:00
Brandon Thomas b095274498 Merge branch 'pr/680' into batch1 2026-10-13 02:21:39 -04:00
Brandon Thomas 528f5138df Merge branch 'pr/678' into batch1 2026-10-13 02:21:39 -04:00
Brandon Thomas eb855a1964 Merge branch 'pr/672' into batch1 2026-10-13 02:21:39 -04:00
Brandon Thomas 392a5c7ab7 Merge branch 'pr/668' into batch1 2026-10-13 02:21:39 -04:00
Brandon Thomas 8255d58c2e Merge branch 'pr/667' into batch1 2026-10-13 02:21:39 -04:00
Brandon Thomas e009a43d10 Merge branch 'pr/666' into batch1 2026-10-13 02:21:39 -04:00
sanyamsingh001andCodex 481b7d2f3b PARITY-EFFECTIVE-PPI: check transformed image resolution
Co-Authored-By: Codex <codex@openai.com>
2026-10-13 13:17:58 +10:00
sanyamsingh001andCodex fa9c7b08b2 PARITY-DISTRIBUTE-LOCKS: preserve locked objects during distribution
Co-Authored-By: Codex <codex@openai.com>
2026-10-13 12:43:50 +10:00
sanyamsingh001andCodex 5ca6a474b9 PARITY-TABLE-SPLIT: split each original selected cell once
Co-Authored-By: Codex <codex@openai.com>
2026-10-13 10:59:32 +10:00
sanyamsingh001andCodex b4db428608 PARITY-ARRANGE: step past same-layer siblings in Arrange
Co-Authored-By: Codex <codex@openai.com>
2026-10-13 10:48:56 +10:00
sanyamsingh001andCodex f7adb11cdc PARITY-CHARACTER-STYLE: capture selected character formatting
Co-Authored-By: Codex <codex@openai.com>
2026-10-13 10:46:10 +10:00
sanyamsingh001andCodex 7abcbc745f PARITY-DATA-SOURCE: honor quoted delimiters and record boundaries
Co-Authored-By: Codex <codex@openai.com>
2026-10-13 10:44:20 +10:00
Marco Arnulfo 9e15d5a17e fix(cli): accept a UTF-8 BOM in scripts and document the syntax in script --help (fixes #654) 2026-10-13 00:41:46 +02:00
Marco Arnulfo 3d59dd5d97 fix(cmd): reject unknown spread values instead of falling back to page 1 (part of #651) 2026-10-13 00:38:54 +02:00
Marco Arnulfo fc01666ac2 feat(text): select sentence, paragraph and story on 3, 4 and 5 clicks (fixes #622) 2026-10-12 23:58:11 +02:00
moppeeerandClaude Opus 5.5 f96895f400 feat(text): Edit type on a path along the curve
The Type tool's clicks, drags and double-clicks on type on a path went to
the character at the same spot of the straightened line, and the caret
and highlight were drawn straight. A click now finds the character where
its nearest point along the path is (compose::PathTextMap, from the line
to the path and back, as path_glyphs places the glyphs); the caret stands
across the path there and the highlight bends with the text. A click on
the letters, above the path, hits the frame.

Depends on #636 (PathWarp::nearest).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:35:58 +02:00
moppeeerandClaude Opus 5.5 cded7d997e feat(tools): Drag type-on-a-path start and end brackets
Selected type on a path shows its start and end brackets across the path,
as in InDesign, and the Selection and Direct Selection tools drag them
along it (Move Bracket, one undo step): the text starts and ends where
they are, and text past the end bracket is overset.

- doc: PathType.end (None: the path's end)
- geom: PathWarp::nearest, the arc length of the nearest point
- engine: type.pathOptions {end}; brackets stay on the path and can't cross
- compose: the line runs from the start to the end bracket
- idml: EndBracket read and written
- tools: Cursor::PathBracket

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:32:56 +02:00
moppeeerandClaude Opus 5.5 c35515c54d feat(tools): The Pen continues an open path from either end point
As in InDesign, the Pen over an end point of an open path (selected, or
under the pointer) shows a continue cursor; clicking it carries on drawing
that path, new anchors going on its subpath, and clicking its other end
closes it. Dragging from the end point first reshapes its direction
lines. From the first anchor the subpath is reversed first.

- engine: path.reverse (Object > Paths > Reverse Path), path.setAnchor;
  path.appendAnchor and path.close take a subpath, and appendAnchor
  refuses a closed subpath
- tools: Cursor::PenContinue

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:18:14 +02:00
skylar taylor-barrick 17cf5b4e91 test(recovery): make failed republishing fixtures deterministic
Force actual failed recovery publication at the reserved destination so privileged runners exercise the intended retention path. Keep the normal writer, publication order and existing assertions; enable these fixtures across platforms.

Validation: all six local gates and the FreeBSD root VM workspace build/tests.

PR #627.
2026-10-12 13:57:37 -06:00
skylar taylor-barrick 8e151a2fd4 fix(recovery): retain recovered checkpoints until save or close
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.
2026-10-12 12:15:46 -06:00
skylar taylor-barrick 9509b2bcea fix(book): stage chapter updates before saving
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.
2026-10-12 12:12:01 -06:00
skylar taylor-barrick b9048a5b08 fix(save): preserve live state when persistence fails
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.
2026-10-12 11:53:46 -06:00
moppeeerandClaude Opus 5.5 1dc33dd280 fix(render): One underline bar per stretch of text, no seams
The canvas drew an underline (and a strikethrough) as one rectangle per
glyph; where two anti-aliased edges met at a fractional pixel they left
a lighter seam between the letters. Contiguous bars of the same colour
and position are merged into one, as the PDF export already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:29:09 +02:00
moppeeerandClaude Opus 5.5 e0cf54ec2b fix(engine): note.edit reads CR as a paragraph return too
note.edit was the one story-text command still reading `text` without
text_param. The progress-log line held real CR and CRLF characters where
it meant to show the escapes; it reads `\r` and `\r\n` now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:26:49 +02:00
moppeeerandClaude Opus 5.5 0ac04151c9 fix(engine): Every command that writes story text reads CR as a paragraph return
frame.create and text.insert turned \r and \r\n into paragraph returns,
but story.replaceRange, story.setText, note.new, footnote and endnote
text, type on a path and table cells kept the CR in the text, where it
drew as a missing glyph and joined the paragraphs. They all use
text_param now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:26:48 +02:00
moppeeerandClaude Opus 5.5 d6635f180a fix(engine): The selected-text preview reads only the 60 characters it reports
type.selectionAttrs copied the whole selection to a string before taking
the first 60 characters, so selecting a long story copied all of it on
every query. It now skips leading blanks and stops after 60 characters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:22:03 +02:00
moppeeerandClaude Opus 5.5 ef87428481 feat(engine): Report the selected text; remember recently used fonts
type.selectionAttrs reports the start of the selected text on one line
(`selectedText`, up to 60 characters), for previews such as the font
menu's Selected Text sample. The preferences keep `recentFonts`, the
fonts last picked in the font menus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:20:17 +02:00
moppeeerandClaude Opus 5.5 9ab226d741 fix(eyedropper): Sample rasters only; colour text through object.color
A placed PDF, EPS or SVG under the Eyedropper matches attributes again,
as before, instead of failing with "no placed image under the point"
(Asset::is_raster, shared by the tool and color.sample). color.sample
hands its colour to object.color, which now colours selected text, the
text of selected frames ({text: true}), or the typing colour of an empty
story; a caret in existing text is refused before a swatch or undo step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:56:17 +02:00
moppeeerandClaude Opus 5.5 d7d6f27069 feat(eyedropper): Sample a placed image's colour into the selection
The Eyedropper on a placed image now does what InDesign does: with text
selected, clicking the photo colours the text with the image's colour under
the pointer; with objects selected, it fills them. The colour is an unnamed
colour (reused when the same colour is sampled again). Images on locked
layers can be sampled, and unfilled frames over the image let it show through.

- color.sample {at, spread?, target?: fill|stroke, ids?} samples the frontmost
  visible raster image at a spread point; one undo step; a caret or a point
  with no image is refused without an edit.
- object.color shares its swatch lookup with it.
- The Eyedropper tool sends color.sample over an image, matchAttributes
  elsewhere as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:56:17 +02:00