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>
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.
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.
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>
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>
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>
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.
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.
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.
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>
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>
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>
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>
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>
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>
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>