Commit Graph
353 Commits
Author SHA1 Message Date
e6c5a701dd The caret and clicks land between the letters of a ligature (#1974) (#2006)
* Fix #1974: the caret and clicks land between the letters of a ligature

The glyph's advance is shared evenly among its letters (mirrored in
right-to-left text); ligature letters keep their character spacing.

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

* Fix #1974: a long word never wraps inside a ligature

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

* Fix #1974: a hyphenation point never splits a ligature

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

* #1974: ligature tests use a bundled font that draws fi and ffi as ligatures

They assumed the installed default-font stand-in draws ligatures; Liberation Sans (Linux) draws
none, so they failed there.

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-19 13:09:22 -04:00
b8debb3050 Content controls: typed text takes the control's formatting, in any language (#3116)
* Content controls: typed text takes the control's formatting, in any language

Text typed in place of a content control's placeholder takes the
control's own run properties (w:sdtPr/w:rPr, ECMA-376 §17.5.2.27), as
in Word: in a protected form filled in Word for Mac, all 17 entered
values carry the style their control's rPr names. WordCraft kept that
rPr only as XML to write back and gave typed text the placeholder's
formatting minus the placeholder style.

It also knew the placeholder style only by its English id,
PlaceholderText. German Word writes Platzhaltertext (the name stays
"Placeholder Text"), so in forms from German Word every entry stayed
grey, on screen and in the saved file, and restoring a placeholder
added a second Placeholder Text style. The style is now found by its
built-in name.

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

* Content controls: typing drops a showing placeholder's own style

A control without run properties that shows its placeholder: text typed
over it drops the placeholder run's character style whatever its id
and name. Word localizes only the placeholder style's id, but another
program may localize its name too, and the name lookup then misses it.
Restoring a placeholder and new controls keep the name lookup.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-19 12:53:44 -04:00
f1b4be8a04 Restrict Editing: forms protection keeps a form's content controls (#3112)
* Restrict Editing: forms protection keeps a form's content controls

With Filling in forms enforced (w:edit="forms"), Word greys out the
Developer tab's control buttons and Properties, and a field's shortcut
menu offers no Remove Content Control: only the fields' content can be
filled in. WordCraft refused these only outside the fillable fields, so
with the caret in one it removed the control (its content left as
plain, no longer fillable text), inserted new controls inside it, and
renamed it; only lock changes were refused.

Under forms protection, inserting any content control, Properties
(every setting) and Remove Content Control are now refused before they
run. Typing, Toggle Check Box, Choose List Item and Set Date still fill
the fields. Other protection modes are unchanged.

Observed in Word for Mac 16.113 on a protected real-world form
(72 content controls: rich text, check boxes, date pickers); the same
form filled in WordCraft opens in Word still protected, with its values,
ticks and dates.

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

* Restrict Editing: parity row states what forms protection refuses

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

* Restrict Editing: correct the comment on content-control property edits in forms mode

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-19 12:49:05 -04:00
Diego GueriniandClaude Opus 5.5 2d0169e718 A Word 2003 XML or web page saved as .doc opens by what it holds (#2853) (#2942)
* #2853: Word XML, web pages and MHTML saved as .doc open by what they hold

A Word 2003 XML Document named `.doc` went to the Word 97-2003 reader, which refused it ("Invalid
CFB file"), and the window showed a blank page. Word XML (2003 or Flat OPC), a web page and a
Single File Web Page (MHTML) under a `.doc`, `.docx` or `.rtf` name now open by what they hold,
as in Word. MHTML is read for the first time (`.mht`/`.mhtml` too): the MIME parts are split and
decoded, the page is imported as HTML in its charset and its pictures load from the other parts.

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

* #2853: leave MHTML to #1104, keep Word XML and web pages saved as .doc

#1104 adds an MHT reader (`wordcraft_formats::mht`), so this branch drops its own MHTML reader and
the `.mht`/`.mhtml` extensions instead of adding a second one. A Word XML Document or a web page
under a `.doc`, `.docx` or `.rtf` name still opens by what it holds (the #2853 fix).

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

* #2853: a web page's signature needs its tag name to end (`<htmlish>` is other XML)

CodeRabbit: `starts_with("<html")` took XML with a root like `<htmlish>` under a `.doc` name for a
web page, though XML that isn't a Word document stays an error. `<html` and `<!DOCTYPE html` now
need white space, `>` or `/` after them.

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

* #2853: rustfmt

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 17:04:33 -04:00
dhruvLearner8 384d5ef307 Cross-reference: caption labels of your own are Reference types (#2940) (#2957)
* Cross-reference: caption labels of your own are Reference types (#2940)

* Caption labels come from the SEQ field's caption, not a digit (#2940, review)

* Caption label after a chapter number field (#2940, review)
2026-10-18 17:01:41 -04:00
528da1f6a2 Comments: a draft survives a failed commit (#1348) (#1512)
* #1348: WIP

* #1348: keep comment drafts per document, keep them on a refused edit, write them before save/close/new/open

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

* #1348: a refused comment draft can be dropped; fields read-only where comments can't change

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

* #1348: ui-parity: one Task panes and Context menus row after the rebase

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

* Docs after rebasing on main

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

* #1348: keep the window open while a web save is unconfirmed; split the roadmap row by operation

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

* #1348: pending comment drafts count as unsaved changes for the browser; a save error isn't hidden by a draft refusal

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

* #1348: an agent can't replace the document over a pending comment draft without force

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

---------

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-18 11:57:07 -04:00
b8b1ec6141 Mail merge review follow-ups: keep the filter on failure, cap spreadsheet text (#1287) (#1295)
* #778: .xls and legacy-encoding recipient lists; filter and sort recipients

- Recipient lists: legacy Excel 97-2003 .xls (BIFF8 reader on the cfb crate already in the
  tree); Excel 5.0/95 and password-protected .xls refused with a clear message; a CSV named
  .xls reads as text, an HTML one gets an error. .xls added to the picker filters (desktop,
  web, built-in browser) and drop handling.
- Text lists (and plain-text import) detect legacy encodings when not UTF-8/UTF-16: GBK/GB18030,
  Big5, Shift_JIS, EUC-KR, Windows code pages (encoding_rs + chardetng, MIT/Apache); an
  `encoding` param overrides.
- mailings.filterRecipients / mailings.sortRecipients: field, comparison (equal, notEqual,
  less, greater, lessOrEqual, greaterOrEqual, blank, notBlank, contains, notContains), value,
  And/Or joins; sort keys. Preview, Finish & Merge and labels use only the matching records
  in sort order. Edit Recipient List edits every record and keeps the filter.
- Recipient List dialog: Filter and Sort section and a merge-order column; catalog rows;
  strings in every catalog; docs.

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

* i18n: Hungarian and French strings for this change

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

* Review fixes for #885: total order for recipient sort, Bulgarian strings

- compare_cells now ranks numbers (compared numerically) before text (compared
  case-insensitively), so it is a total order; a column mixing 9, 10 and 1a
  could make slice::sort_by panic. Regression test sorts mixed columns.
- Bulgarian catalog: the 24 Filter and Sort strings.

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

* #1287: placeholder (work in progress)

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

* #1287: keep the filter on a failed Edit Recipients; cap .xls/.xlsx cell text; dialog drops rules on unknown fields and caches the merge order

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

* #1287: rustfmt

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

---------

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-18 11:56:19 -04:00
8b0f1762a1 Split Cells on merged cells: divisor message and 1x1 top-row cut (#2592) (#2913)
* #2592: Split Cells on a merged cell: divisor message, 1 x 1 cuts the top row off (Word check)

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

* #2592: Split Cells dialog shows the divisor message; docs

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

* #2592: clippy

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

* #2592: Split Cells 1 x 1 on a merged cell changes nothing (corrected Word check)

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

* Split Cells on a merged cell follows Word: divisor message, 1 x 1 changes nothing (#2592)

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:55:32 -04:00
PanyangYandBrandon Thomas de8a81c1e4 References: Word sources file import in Manage Sources (#2640) (#2897)
* References: Word sources file import in Manage Sources (#2640)

Manage Sources gains Import… and references.sources an "import": path
parameter: it reads a b:Sources document (Word's own Sources.xml) into the
document's sources with the same reader as a document's own bibliography
part. A tag already here is left alone, an untagged entry is matched by
title and author or gets a tag like a new source, the whole import is one
undo step, and a file that isn't b:Sources is refused. Desktop only; the
web build hides the button.

The docx reader now shares the b:Sources parser (crates/docx/src/
bibliography.rs) with the import, with the same dedupe and 10,000-source
cap; the hostile-input cap test still passes.

Tests: docx unit tests (names, kinds, accessed/DOI fallbacks, repeated
tags, empty entries, wrong root), engine import test (add, undo, second
import, untagged matching, refused file), ui tests (the dialog button asks
for a "sources" file; finish_pick imports), wordcraft-cli end to end
(import, cite, bibliography, save, reopen; the package's customXml
carries the sources). The button's label is in every interface catalogue.

ROADMAP progress log and docs/roadmap.md, gaps.md, file-format-parity.md
and target-app-parity.md get their rows.

* References: review fixes for the sources import (#2640)

- read_sources validates the root namespace instead of the local name alone:
  an un-namespaced or unrelated <Sources> is refused, and both bibliography
  namespaces read — OOXML's and Word's own 2004/10 (the VBA Source.XML
  format), the latter mapped onto the canonical b prefix with parse_ns.
  Tests: the 2004/10 namespace is accepted; a no-namespace or unrelated
  root is refused.
- The import loop builds the tag and (title, author-or-editor) sets once and
  keeps a per-stem counter, with the stem rule shared with auto_tag
  (auto_tag_base). Importing thousands of untagged sources no longer costs
  O(n^3). Test: untagged sources sharing a stem get Riv21, Riv211, Src, and
  a second import adds none.
- docs/target-app-parity.md and docs/file-format-parity.md no longer claim
  bibliography sources aren't saved in DOCX: #169 and #532 are closed and
  the round trip exists (#790).

* References: doc comments for the sources import helpers (#2640)

Hoist the untagged-source matching helper (by_author) to module level and
document sources, auto_tag_base and sources_ui, so the functions this PR
touches meet CodeRabbit's docstring-coverage pre-merge check.

* References: re-apply the sources import's progress notes (#2640)

The rebase onto current main took upstream's copies of ROADMAP.md,
docs/file-format-parity.md and docs/gaps.md, because the rows this PR
adds conflicted with upstream's own appends. Re-apply them on the current
text: the progress log and revision rows, the bibliography row's
source-format note, and #15's evidence, with each status line's change
note. The other two documents (docs/roadmap.md, docs/target-app-parity.md)
merged cleanly and keep their rows.

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:54:47 -04:00
2646700ca0 #2573: Picture Format › Size takes sizes in any unit, pixels too, and opens a Size dialog (#2889)
* #2573: Picture Format › Size takes sizes in any unit, pixels too, and opens a Size dialog

The picture size options were too limited (#2573, and #1901's request to enter pixels without
deforming the picture): the ribbon's W/H fields were points only, rejected "300 px", resized on
every keystroke (one undo step per digit), and there was no way to scale from the original
size, lock or unlock the aspect ratio, or reset the size.

- Picture Format › Size: W/H show the interface unit (Options › Advanced) and take a size typed
  in any unit, `px` included; it applies on Enter as one undo step, and the other side follows
  so the picture keeps its proportions. A drag still applies live.
- The Size group's launcher (and `picture.size` run without a size) opens a Size dialog: height
  and width, scale of the original size or of the size it opened with, Lock aspect ratio,
  Relative to original picture size, the original size with its pixels, and Reset.
- `picture.size {"original": true, "scale"?}` sizes from the picture's original size (its pixels
  at 96 ppi, read from the image adjustments started from, less what is cropped). A size past
  4000 pt that keeps the proportions now shrinks as a whole instead of flattening.
- New strings translated in every interface catalog.

The crop tool already exists (Picture Format › Size › Crop) and is being extended in #2027 and
#2440; options cut off in a narrow window are what #708 and #1293 (ribbon groups that shrink to
fit) address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZArmeAT48gF84aKj7Zx4C

* contributors: credit @matteo-andreuzza by their GitHub profile name

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZArmeAT48gF84aKj7Zx4C

* #2573: Size keeps the proportions at the 1–4000 pt limits and follows the selection

Review follow-ups (CodeRabbit on #2889):

- Size dialog Reset on a photo larger than 4000 pt (a 6000 px wide one is 4500 pt) set it to
  the original size, which `picture.size` then clamped side by side: the picture was flattened.
  Reset now shrinks both sides by one factor.
- Locked, a side typed past the limit clamped the other on its own (15×30 pt with width 4000
  became 4000×4000). Both sides now scale by one factor.
- `fit_size` (engine) only shrank: a proportional size under 1 pt (scale 1% of 50×200 pt) became
  1×2 pt. It now picks the factor nearest 1 that brings both sides within 1–4000 pt, falling
  back to side-by-side clamping only for shapes too long and thin for any; the dialog uses it.
- Dialogs aren't modal: picking another picture while the Size dialog was open made OK size it
  with the first one's numbers. The form now follows the selection (starts over on the new
  object, closes when nothing is left to size).
- Doc comments on the Size form's methods.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZArmeAT48gF84aKj7Zx4C

* #2573: Size dialog reads the picture again after a crop, change or resize

Review follow-ups (CodeRabbit on #2889):

- The open Size form only compared the selected object's position. A crop from the ribbon,
  Change Picture or a handle drag while the dialog is open left Reset and OK working from the
  old crop and size. The form now remembers the picture, crop and size it was read from (bit for
  bit, without comparing whole objects that may hold large embedded data) and reads them again
  when any changes.
- An egui harness test drives the dialog end to end: launcher, a height typed in pixels, nothing
  applied before OK, OK sizes in proportion as one undo step and closes the dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZArmeAT48gF84aKj7Zx4C

* #2573: size fields never resize a picture just by showing it

Review follow-up (CodeRabbit on #2889): egui's DragValue clamps a value already outside its
range when it is drawn and reports that as a change. The Size fields act on changes, so:

- Picture Format's W/H resized a picture smaller than 1 pt (a 1×1 px spacer is 0.75 pt) or
  larger than 4000 pt as soon as the tab was shown, an edit and an undo step nobody asked for.
  The code before this PR had the same problem with its 4–2000 pt range.
- The Size dialog's scale fields silently changed a picture enlarged past 10000% (a small icon
  made large), and its lengths a size outside 1–4000 pt, which OK then applied.

The range now bounds only what is typed or dragged (`clamp_existing_to_range(false)`). Both
regression tests fail without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZArmeAT48gF84aKj7Zx4C

* #2573: Shape Format and Chart Design size fields leave existing sizes alone too

Review follow-up (CodeRabbit on #2889, outside the diff): the same egui clamp as in d56a105.
Shape Format's W/H (4–2000 pt) and Chart Design's (36–2000 pt) clamped a size outside their
range as soon as the tab was shown and resized the object unasked. The new Size dialog makes this
easier to reach, since it takes shapes up to 4000 pt, but a thin line under 4 pt was already cut.
Both now show such a size as it is and act only on a new value. Shape Format's range follows
`picture.size` (1–4000 pt), so dragging a 3000 pt shape no longer snaps it back to 2000.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZArmeAT48gF84aKj7Zx4C

* #2573: Esc cancels a size typed in Picture Format; a typed size applies when the field is left

Review follow-up (CodeRabbit on #2889, outside the diff) asked to apply typed sizes on Enter only.
That is not done: a field keeps what was typed when it loses focus, as text fields do, and
otherwise typing a height in the Size dialog and clicking OK would throw it away. A harness test
now pins that path with a real click (press, then release frames later).

Checking it turned up a real bug: Esc did not cancel in the ribbon's W/H fields. egui 0.36 keeps
a DragValue's typed text after Esc and applies it the next frame, when the field still counts as
having just lost focus but Esc is no longer pressed. The fields now remember when Esc ended the
typing and drop that late value. (In the dialog Esc cancels the whole dialog, so nothing applies
there either; both are tested.)

Docs and comments now say "applied once typed (Enter, Tab or a click elsewhere; Esc cancels)"
instead of "applied on Enter".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZArmeAT48gF84aKj7Zx4C

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:54:25 -04:00
72467d037b Keep the selection's font when typing over a backward selection (#2911)
Fixes #2879

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:52:17 -04:00
GavinQiErandBrandon Thomas 8bde3b3c25 fix: dropping an object near the top of the next page no longer sends it back (#2829)
move_object anchored the object to the paragraph under the drop point and
computed the offset from that paragraph origin. With a Square-wrapped object
the surrounding text reflows once the object moves away, so the first
paragraph of the target page - the anchor when dropping near its top -
slides back to the previous page and the object follows it.

Re-check the page after placing an object across pages and re-anchor when the
placement did not land on the target page (up to three attempts). Same-page
moves still place once, so resize and nudge are unchanged.

Adds a kittest that presses, moves and releases onto the top of the next page
and asserts the object stays on the page under the pointer.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:49:47 -04:00
c91c1793a3 #2108: File › Print scales pages to another paper size (#2699)
* #2108: File › Print scales pages to another paper size

Scale to paper size on File › Print (Word: Pages per sheet › Scale to
paper size): No Scaling or any Layout › Size paper (Letter, Legal, A4, …).
Every page is scaled to the paper and centred, the paper turned to the
page's orientation, in the preview, the print job and Save these pages
as PDF. Native jobs also ask the spooler for that media. The document's
page size is unchanged. New `paper` param on ui.print/ui.printSubmit and
file.printPdf; unknown papers are errors.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* pdf: bookmark destinations from #2364 use the scaled Fit too

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:48:17 -04:00
00cd3f3368 Fix stray leading space in RTF list items on export (#2667)
Found while testing crates/formats/src/rtf.rs:269-272 (Writer::para)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:48:02 -04:00
Debarghaya MitraandBrandon Thomas cff4cd35b8 Page setup: resolve section correctly when focus is in a header, footer or note (#2072) (#2663)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:47:46 -04:00
6e30349bbb #1327: protection checks cover tables, Paste Formatting and recipient refresh (#2618)
* #1327: protection checks cover tables, Paste Formatting, template update and recipient refresh

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

* #1327: record any content below the protection walk's depth limit

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

* #1327: formatting-only protection also refuses table properties and row height

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:45:40 -04:00
8c812bf1d6 #1230: Insert Caption on pictures and shapes; Different First Page in Page Setup (#2615)
* #1230: Insert Caption on pictures and shapes; Page Setup header and footer options

- Right-clicking a picture, shape, text box or chart offers Insert Caption…, as in Word.
- references.caption with a picture or shape selected puts the caption next to the
  paragraph holding it, in the same cell or text box (it used to go after the whole table).
- The Caption dialog proposes Figure for a picture selected in a table, not Table.
- Page Setup: Headers and footers check boxes (Different Odd & Even Pages, Different First
  Page), applied on OK only if changed, in one undo step; a title page can go unnumbered.
- Tests: engine caption_for_an_object_in_a_cell_stays_in_the_cell; kittest
  right_click_on_a_picture_offers_insert_caption and
  page_setup_different_first_page_leaves_the_title_page_unnumbered.
- Docs: ui-parity, target-app-parity, ROADMAP progress log.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8veLveuUsJJm6UEcQPEuW

* ui-parity: keep Insert Caption on the context-menu row

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:45:24 -04:00
beedd1b30d Drop Cap Options dialog (#2601) (#2602)
* #2601: Drop Cap Options dialog

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

* gaps: keep the Drop Cap Options note on the dialog-depth row

* i18n: translate the two Drop Cap disabled reasons in the audited catalogs

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:44:30 -04:00
Marco ArnulfoandBrandon Thomas 913621c1c4 Font dialog: Kerning for fonts and its Points and above size (#2295)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:41:26 -04:00
divyanshu2074andBrandon Thomas d9ca2573a6 fix(engine): count multi-column spanning cells once in table formula ranges (#2200)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:40:00 -04:00
Antoine BoxhoandBrandon Thomas 61a626820e #1552: no spelling squiggle under the word being typed (#2183)
Word draws no red squiggle under the word being typed. It appears when the word ends or the
caret leaves it by a key or a click. The session records the word after a text command that
edits the caret's paragraph, with apostrophes and hyphens counted as the spelling check counts
them, and drops it once the caret is anywhere else. The layout leaves that one range out of the
spelling squiggles, and a caret move without an edit lays out only that paragraph again. F7 and
the Spelling pane still report the word, and grammar marks are unchanged.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:39:21 -04:00
95b5c71f80 Save writes the chosen file when its folder refuses a temporary file (macOS privacy protection) (#2138) (#2167)
* #2138: save writes the chosen file when its folder refuses a temporary file (macOS privacy protection)

On macOS a Save-panel pick inside a protected folder (Desktop, Documents…) grants
access to that file only, so the sibling .wordcraft-save-*.tmp was likely refused
with EPERM. On PermissionDenied creating the temporary file, write the destination
directly; a remaining permission error on macOS says where to allow access.
Untested on a Mac: the fallback path is pinned on Unix with a read-only folder.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* #2138: a failed save in a folder refusing the temporary file keeps the original

Review (FredApps): the in-place fallback truncated the destination before
writing, so a failure partway through lost the previous document.

The fallback now keeps the existing file's bytes in memory (up to 512 MB)
before writing it in place and writes them back if the save fails, or
removes a new file it created. If that write-back fails too, the error
says the file may be incomplete. A file over the limit isn't written in
place; the error suggests Save As.

Tests: the reviewer's partial-write test (read-only folder), a new file
removed on failure, and the size limit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8veLveuUsJJm6UEcQPEuW

* #2138: keep the original untouched when no safe replacement is possible

When the folder refuses the sibling temporary file, an existing destination
is no longer overwritten in place (no in-memory rollback): it stays
byte-identical and the error says to use Save As to another folder or allow
access to the folder (macOS: Privacy & Security > Files and Folders). A
destination that doesn't exist yet is created exclusively and removed again
if the write fails.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8veLveuUsJJm6UEcQPEuW

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:38:04 -04:00
874e5a76a0 #2052: a second picture style, border or artistic effect replaces the first (#2148)
Picture Styles, Picture Border and Artistic Effects now draw again from the
bitmap under them (kept per drawn picture in Session::picture_looks), so
Thick Frame then Simple Frame is only a simple frame, a border replaces the
border and keeps the style, a style replaces the border, and an effect
replaces the effect ("none" removes it), as in Word. Transparency was already
absolute (#1175); the test pins it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:37:12 -04:00
872b2bc99d DOCX: ink inside groups and drawing canvases survives saving (gap 2) (#2097)
* gap: nested ink WIP

* gap 2: native ink nested in groups and drawing canvases survives DOCX saves

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

* gap 2: review round 1: ungrouping keeps nested ink; no orphan parts

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

* gap 2: Impact cell matches the restated impact

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

* gap 2: only Word ink pins a group against Ungroup

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

* gap 2: alternate ink must hold an a:graphic to be written as standalone

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

* gap: nested ink WIP

* gap 2: native ink nested in groups and drawing canvases survives DOCX saves

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

* gap 2: review round 1: ungrouping keeps nested ink; no orphan parts

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

* gap 2: Impact cell matches the restated impact

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

* gap 2: only Word ink pins a group against Ungroup

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

* gap 2: alternate ink must hold an a:graphic to be written as standalone

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

---------

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-18 11:34:42 -04:00
70fc00c80f Symbols keep their symbol font when the text font changes (#2036) (#2037)
* Symbols: a w:sym character keeps its symbol font when the text font changes (#2036)

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

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

* #2036: review round 3: docx test reads sym_font, paste drops the symbol font, astral symbols stay text

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

* #2036: insert.symbol decides symbol or text per character

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 11:33:00 -04:00
1b45615940 Insert › Shapes keeps the selected shape and text (#2019) (#2030)
Inserting a second shape removed the first: after an insert the new
shape stays selected, and `insert.shape` replaced the selection, so each
shape replaced the one before. Word draws a new shape beside whatever is
selected and never deletes it (checked by hand in Word for Windows: a
second shape is drawn over the first, which stays).

The new shape now goes after the selection, which is left alone, and
becomes the selection. Selected text stays too. A picture still replaces
a selected picture, which is what Word does as well (checked in Word for
Windows), so `insert.picture` is unchanged.

Tests: three shapes inserted in a row are all kept, which fails with the
old code (1 of 3 kept); a shape inserted over selected text keeps the
text and is selected itself; a picture inserted over a selected picture
replaces it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:32:07 -04:00
492aceb960 Fonts Word embeds as subsets lay out the text set in them (#2240) (#2540)
* #2240: fonts Word embeds as subsets lay out the text set in them

Embedded fonts were registered under the family inside the font file. Word
embeds a subset ("embed only the characters used") under a made-up family
(___WRD_EMBED_SUB_46) and the text asks for it by the font table's name
(OBRBWW+Century Schoolbook), so it still fell back to a substitute. Each
embedded file now comes with its font table name, and its faces go by that
name when they don't already.

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

* #2240: the black-circle fallback test passes its font's table name

main's new `circle_checks_face_coverage` test (#2582) called `add_document_fonts` with bare font
bytes; with this branch each embedded font comes with the name the document's font table gives
it, so the test passes "Times New Roman" alongside the face it renames to it.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:28:52 -04:00
Fin WarmanandBrandon Thomas a5d817a9ef TOC: keep direct number tabs on refresh (task 276) (#2475)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:27:26 -04:00
09b822fdbe Update Field after save and reopen of a table of contents; no extra blank line per cycle (#2182) (#2553)
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:27:11 -04:00
5c4408f341 Paste: plain text keeps the formatting of the paragraph it lands in (#2423) (#2424)
Paste of plain text from another program gave every line after the first
a paragraph with default formatting. The text became a fragment of
unformatted paragraphs (Fragment::from_text), and insert_fragment keeps
the target's formatting only in the first one. Pasting several lines into
a right-to-left paragraph turned all but the first left-to-right, and the
text after the caret lost its paragraph formatting too.

Paste now inserts plain text as Keep Text Only does. Each line after the
first splits the paragraph as Enter does, so it keeps the paragraph's
direction, style, alignment, indents, spacing and list. Empty lines become
empty paragraphs with that formatting. Copies from WordCraft and HTML or
RTF from other programs keep their own formatting as before. A paste is
still one undo step.

Tests cover a right-to-left paragraph, empty lines and a final line break,
and a list. The typing and UI parity docs and the ROADMAP progress log
have rows for the change.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:23:43 -04:00
3348e93140 ASK and SET fields show nothing (#1765) (#1785)
* #1765: WIP

* #1765: ASK and SET fields show nothing

Like Word, ASK and SET only assign text to a bookmark: they draw no
result on the page or in a PDF. The stored result is kept and saved.

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

* file-format-parity: note ASK/SET on the existing Fields row instead of a third one

---------

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-18 09:57:31 -04:00
11f1d0aee6 Lowercase list items no longer get a grammar underline (#1741) (#1783)
* #1741: WIP

* #1741: list items no longer get the sentence-capital grammar squiggle

The English "Capitalize the first word of a sentence" rule skips the first
word of a list paragraph (own or style numbering); later sentences are still
checked. check_text_with and paragraph_issues take a list_item flag.

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

* #1741: review fixes

Thread the capital-first flag into the Polish, Croatian, Italian, Turkish and
Portuguese grammar rules; test the drawn squiggles through layout() for own,
style and num 0 numbering; tidy the proof test.

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

* #1741: main's Vietnamese proofing test passes the new list-item argument

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* #1741: the third call in main's Vietnamese proofing test

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 09:57:15 -04:00
1cea0f7e11 Equations: a script runs until a space or operator, as in Word (V_dd, x_2a) (#1609) (#1951)
* WIP for #1609

* Equations: a script after _ or ^ is the whole run of letters and digits (#1609)

Word for Mac 16.113.4: V_dd and V_(dd) build up the same (dd is all
subscript), likewise x^ab, and Linear format shows V_dd bare.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Equations: bare scripts end at a space, digits continue a script run, upright function names (#1609)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Equations: a bare script also ends before a following period (#1609 review)

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

* ROADMAP: drop three progress rows main already has

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:37:37 -04:00
3bede06646 Restrict Editing: exceptions don't open page setup or styles; tracked-changes protection keeps revisions (#1881)
With read-only (or comments) protection and an editable exception, the check after a
command only compared text and paragraph formatting outside the exceptions, so page setup
(section properties) and style definitions could change for the whole document. They are
now compared too (styles a command adds are allowed). Protected for tracked changes,
Accept/Reject and the Track Changes toggle are refused, as in Word.

Refs #1327

Co-authored-by: dfgodvan <180286157+dfgodvan@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 09:37:12 -04:00
Marco ArnulfoandBrandon Thomas 4362e6624d Word's Spike: Ctrl+F3 collects cuts, Ctrl+Shift+F3 inserts them (#2507)
* Spike: Ctrl+F3 collects cuts, Ctrl+Shift+F3 inserts them and empties it (gap #24)

* Search test: a lone INSERT's witness within the box's 14 results; Table checked past it

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:57:27 -04:00
Fin WarmanandBrandon Thomas 455e1f419f Include table-cell headings in regenerated TOCs (#2482)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:56:10 -04:00
3a2cea6ca4 #1843: Read Aloud speaks Russian text with a Russian voice (#2430)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:55:18 -04:00
NetterSilverandClaude Haiku 5.5 5a82eafa5a Refresh DATE/TIME fields when opening .doc/.dot by extension (#2418)
Found while testing crates/engine/src/io.rs:183-187 (read_bytes, the "doc" | "dot" arm returns before opened() is called)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 04:55:00 -04:00
8fcaa66e19 Turkish case mapping: i/İ and ı/I capitalise correctly (#1923) (#2009)
* WIP for #1923

* AutoCorrect: Turkish and Azerbaijani case mapping (#1923)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* AutoCorrect: Turkic language detection shares proofing's tag normalisation, I to dotless i covered (#1923)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:43:32 -04:00
0254f3afc7 Hebrew: field results like STYLEREF draw right to left; smart quotes match Word (#1670) (#2007)
* Field results (STYLEREF, REF, PAGE text, note marks) shown as one atomic
cluster now place their inner clusters in UAX #9 visual order, in the
direction of the text around the field, so "פרק א" in a header no longer
draws reversed. Smart quotes already matched Word's logical-order result
in Hebrew (” in acronyms, not gershayim); pinned with a typing test.

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

* #1670: fix round 1: field results shaped per bidi run, so brackets mirror correctly

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

---------

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-18 04:42:54 -04:00
da8b7b7feb Tables: Backspace removes a selected table, rows or columns; Delete clears them (part of #1844) (#2005)
* WIP for #1844

* Tables: Backspace removes a selected table, rows or columns; Delete clears them (#1844)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Tables: delete_range edge-case tests, single-cell Backspace clears, deep tables kept (#1844)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:42:35 -04:00
c9f3da2fc5 DOCX: mixed Hebrew/Latin keeps its order in Word (runs split by direction, w:rtl and language) (#1543) (#1950)
* WIP for #1543

* DOCX: split mixed-direction runs and mark right-to-left pieces w:rtl so Word orders them as WordCraft does (#1543)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* DOCX: right-to-left pieces of split runs say their language (w:lang w:bidi) (#1543)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* DOCX: no phantom tracked formatting on split runs; typed text doesn't inherit run direction (#1543)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Engine: text typed or inserted anywhere takes its direction from its own letters, not the caret's run (#1543)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:41:59 -04:00
82bf806118 Web: input-method rewrites erase before retyping, so non-Latin typing no longer repeats (part of #1480) (#1949)
* WIP for #1480

* Web: an input method's DeleteSurrounding erases around the caret, so non-Latin typing no longer repeats (#1480)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Web: input-method rewrites keep formatting and the typing undo group; AutoCorrect resets the web text field (#1480)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:41:39 -04:00
NetterSilverandClaude Haiku 5.5 6b192f58ce Clamp negative margins before checking they leave text room (#1941)
Found while testing crates/engine/src/cmd/page.rs:392 (margins) and :424 (margins_fit)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 04:41:20 -04:00
SlavenDjandBrandon Thomas 31cb2c8714 #1861: searchable Interface Theme command (View, light/dark/system + toggle) (#1868)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:26:19 -04:00
6d83d13257 Update Field works in headers, footers, notes and text boxes; printing updates every field (#1706) (#1780)
* #1706: WIP

* #1706: Update Fields refreshes fields in headers, footers and text boxes

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

# Conflicts:
#	ROADMAP.md

# Conflicts:
#	ROADMAP.md

* #1706: review fixes

Revision-history row, update_fields doc comment, test covers body field and locked header field.

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

* #1706: update the fields of the part being edited, as in Word

Word check: F9 with the caret in the body leaves header fields alone; with the caret in a header it updates that header. SEQ, citations and TOC run only from the body.

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

* #1706: printing updates every field in the document

references.updateFields takes {"all"?: bool}: the body (with SEQ, citations, TOC) plus every part story, wherever the caret is. Printing passes it.

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

* #1706: ROADMAP status line after rebase

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

* #1706: tests build the field form value added on main

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

* #1706: the test's fields take main's new dirty flag

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

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-18 04:24:53 -04:00
c5a9c954f7 Track Changes Options: Moves (move tracking, Moved from/to marks and colours) (gap 5) (#1779)
* track-move-options: WIP

* track-move-options: Moves options in Track Changes Options and w:doNotTrackMoves

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* track-move-options: Moved from Hidden leaves the layout; per-revision hiding

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* track-move-options: Word's mark lists, (none) moves are plain, no borders on collapsed paragraphs

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* track-move-options: hr and sv translations for Moved from:/Moved to:

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:24:34 -04:00
1f0aeb4626 Ink to Shape: two-stroke arrows and closed-triangle heads (gap 12) (#1778)
* ink-arrows-2: WIP

* ink-arrows-2: Ink to Shape makes two-stroke arrows and closed-triangle heads

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

* ink-arrows-2: review fixes — recognise each stroke once, drawing-order pairing, arrow rect

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 04:24:15 -04:00
6311f9d411 AutoCorrect: replace the double-hyphen arrow (#2223) (#2263)
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:22:50 -04:00
e7f5d32c35 Numbered headings: heading-linked multilevel list presets keep the heading styles (#1793) (#2239)
* Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

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

* #1793: wording: other paragraph styles become Heading 1, not only body text

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

---------

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-18 04:22:12 -04:00