Commit Graph
16 Commits
Author SHA1 Message Date
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
Brandon Thomas 94bf1bf7f9 Merge pull request #1780 from dotCooCoo/fix/note-delete-keeps-caret
Footnotes: deleting a footnote or endnote keeps the caret on the same text
2026-10-25 12:26:13 -04:00
Brandon Thomas bb45cdcc50 Merge pull request #1775 from dotCooCoo/fix/footnote-moves-drop-typing-format
Footnotes: moving the caret into or out of a footnote drops formatting not yet typed
2026-10-25 12:26:06 -04:00
dotCooCoo db935e2090 Footnotes: deleting a footnote or endnote keeps the caret on the same text
footnote.delete and endnote.delete removed the reference character from
the story but left a caret or selection in the story text at its old
byte offsets. Everything after the reference moved back by the
reference's length, so the caret ended up three bytes further along the
text. A caret or selection after the reference now moves back with the
text, and one before it stays where it is.

footnote.setText left a caret in the replaced footnote at its old
offset, which could fall past the end of the new text or inside a
character. Backspace there then failed with an internal error. The
caret now goes to the end of the new text.
2026-10-24 09:11:53 -07:00
dotCooCoo 56fcfb3153 Footnotes: moving the caret into or out of a footnote drops formatting not yet typed
Go to Footnote Reference, Insert Footnote and Delete Footnote (when the
caret is in the deleted footnote) moved the caret without clearing the
pending typing format. Formatting chosen at the old insertion point and
not yet typed then came back when the caret returned there, for example
in a new footnote that takes a deleted footnote's id. The three
commands now clear it, as text.select and text.move do.
2026-10-24 06:59:15 -07:00
NetterSilverandClaude Haiku 5.5 f0ce96138c Saturate footnote and endnote numbering at u32::MAX
Found while testing crates/compose/src/notes.rs:133 (also crates/doc/src/notes.rs:265 footnote_start and crates/doc/src/endnotes.rs:150 endnote_start)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 09:07:37 +00:00
aiongg 117420a829 Merge #522: Every command that writes story text reads CR as a paragraph return
Conflict: ROADMAP.md: both progress-log lines
Conflict: crates/engine/src/cmd/table.rs: next's setCell (StrokeEdit/EdgeSel, edit_table with ID) with the PR's text_param for the cell text
2026-10-12 00:12:48 +00:00
moppeeerandClaude Opus 5.5 3ec6f47e26 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-11 20:12:02 +02:00
aiongg 25aa2735b8 Merge copy-notes: Text: footnotes insert into a story whose references lack footnotes
Conflict: crates/doc/src/slice.rs: tests module keeps next's append_story overflow test and the branch's copy/paste and hostile-marker tests
2026-10-11 13:04:05 +00:00
aiongg fe8a724da4 Text: footnotes insert into a story whose references lack footnotes 2026-10-11 12:54:42 +00:00
aiongg aa743eee88 Merge kanji-page-numbers: Kanji page numbers
Conflicts: engine layout.rs and notes.rs params docs (next's lists plus kanji).
2026-10-10 21:27:19 +00:00
aiongg c28387eaf9 Sections: Kanji page numbers
Kanji numbering style (一, 二, 三, …, written digit by digit: 10 is 一〇)
for sections, footnotes, endnotes and lists. IDML PageNumberStyle and
FootnoteNumberingStyle read and write Kanji and the leading-zero styles;
the list format "一, 二, 三, 四..." maps to it.
2026-10-10 21:23:01 +00:00
aiongg c403cae4c7 Merge #83 update (feat/layout-parity f386a98d): Em Box Height first baseline offset
Conflicts: fonts fontdb.rs (the branch's em box with its from-BASE flag beside next's ICF cache); idml
tests.rs (the branch's copies of tests already on next, and the mojikumi test #129 replaced, dropped;
the Em Box Height test kept). German entry for Em Box Height.
2026-10-10 21:16:13 +00:00
aiongg f386a98d7c Layout: Em Box Height first baseline offset
The first baseline sits the em box top below the frame's top inset: the
font's BASE em box (idtp, else ideo + 1 em), else 0.88 em, for the
largest size on the first line. IDML FirstBaselineOffset="EmboxHeight"
imports and exports as itself; the footnote options list it and the
frame and footnote option commands take emboxHeight.
2026-10-10 21:04:33 +00:00
aiongg 6dda095396 Engine: a cancelled gesture puts back the revision it began at
Cancelling a drag, a preview or an IME composition restores the
document, its selection and now its revision. Revisions come from one
counter, so the numbers a cancelled preview used are never handed out
again and caches keyed by (uid, revision) never show a cancelled
preview.
2026-10-10 16:05:46 +00:00
Brandon ThomasandClaude Opus 5.5 3ad71d5a76 M7: footnotes — Insert Footnote, Document Footnote Options, column-bottom layout, PDF/IDML; generic command dialogs
- doc: FOOTNOTE_REF marker + Story::notes (kept in sync on insert/delete/thread), FootnoteOptions,
  NumberStyle::Symbols, footnote text addressed like cell text (CellAddr::footnote)
- compose: notes numbered (continuous / restart per page, spread, section), composed at column
  width, body text makes room, stacked at the column bottom with the rule above
- render + PDF draw footnote text; IDML export/import in InDesign's structure (verified in
  InDesign 2026), FootnoteOption preferences
- engine: footnote.insert/options/list/setText/delete/goToReference (+ tests)
- UI: caret/selection in footnote text, Footnote Options dialog, Type menu entries; menu items
  labelled '…' with parameters open a dialog generated from the command's params doc
- sample magazine carries a footnote

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:01:27 -04:00