Commit Graph
334 Commits
Author SHA1 Message Date
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
divyanshu2074 8cdd85f7e7 fix(engine): support none in wordart reflection and outline color (#2238) 2026-10-18 04:21:53 -04:00
1d37043128 AutoCorrect: reversing a capitalisation adds an automatic exception, as in Word (#1857) (#2227)
* Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

* #1857: forget the capital when a command fails; INitial CAps auto-add checked in Word

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:21:42 -04:00
f354e7fc9b fix(engine): support nested quotations and opening delimiters in smart quotes (#2176)
* fix(engine): support nested quotations and opening delimiters in smart quotes

* docs: typing-parity line for smart quotes after guillemets, low quotes and nesting

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 04:02:37 -04:00
540692515b fix(engine): resolve section and section pages context when unlinking fields (#2156)
* fix(engine): resolve section and section pages context when unlinking fields

* cargo fmt

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 04:01:48 -04:00
Marco ArnulfoandBrandon Thomas cdb13144b3 Lists: Enter on an empty nested item numbered by its paragraph style moves it up a level (#2143) (#2151)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:01:19 -04:00
8812fe068d fix(engine): support switches and quoted bookmarks when updating REF and PAGEREF fields (#2149)
* fix(engine): support switches and quoted bookmarks when updating REF and PAGEREF fields

* cargo fmt

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 04:01:00 -04:00
Marco ArnulfoandBrandon Thomas 7bd3eb8ca7 Backspace and Delete remove a section break, imported or not (#2133)
* Backspace and Delete remove a section break, imported or not (fixes #2127)

* Delete removes a section break on the last paragraph too (#2127)

A continuous break on the mark of the document's last paragraph, with the
last section holding no paragraph (as in the file attached to #2127), had
nothing for Delete to join, so it stayed. Delete at the end now removes it.
The text takes the last section's setup, as in Word, and the headers and
footers that section showed by linking to the removed one stay, here and
when the break goes by joining two paragraphs. Undo brings it back.

* Deleting over several section breaks keeps the headers they linked to (#2127)

A range across two or more breaks dropped the paragraphs in between with
their sections, so only the first section's headers and footers were carried
over. The joined section now takes those it leaves out from every removed
section, nearest first, as "link to previous" resolved them before the delete.
The typing-parity row says that Delete with Track Changes on still leaves a
break on the last paragraph alone.

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:00:49 -04:00
357deba3c2 fix(engine): use table_formula parse_number for table sorting (#2126)
* fix(engine): use table_formula parse_number for table sorting

* contributors: drop the duplicate entry (already listed)

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

* cargo fmt

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 04:00:30 -04:00
divyanshu2074 35fb78f0cc fix(engine): exclude carriage returns from word count character statistics (#2116) 2026-10-18 03:59:49 -04:00
a93932d491 fix(engine): ensure nextFootnote navigates only footnotes and skips endnotes (#2114)
* engine: filter note_refs in nextFootnote to skip endnotes

* Collapse the nested if (clippy collapsible_if)

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 03:59:37 -04:00
AlikandBrandon Thomas d8b11c69d3 Columns on selected text go in their own section (#2024) (#2071)
With text selected, Layout > Columns used to change the whole section. As in
Word (observed black-box), a continuous section break now goes where the
selection starts and one where it ends, splitting a paragraph there, unless that
end already meets a section boundary (the document's start or end, or an
existing break); the columns go on the section between, in one undo step.
`layout.columns` gains `apply: "selection"`, its default when text is selected
in the main text. More Columns... offers "Selected text" and picks it then.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 03:59:01 -04:00
8fb4d44d2c Different First Page: page 1's header can be edited and inserted (#2826) (#2833)
With Different First Page on, page 1 shows the first-page header, but
Insert > Header/Footer/Page Number always wrote the default one (which
page 1 no longer shows), Edit Header without a page went to the default
too, and a double-click in page 1's header area was ignored while
another header was being edited (the usual case: edit the header, tick
Different First Page, double-click page 1). Now hf_part and edit_hf use
the slot of the caret's page, and a double-click in a header/footer
zone switches to the one that page shows even from another header.

Fixes #2826
Fixes #2811


Claude-Session: https://claude.ai/code/session_013kKPnx8r1vcYumjyL3kcuz

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 03:47:13 -04:00
abb36aceb2 #1270: pasted HTML blockquote is an indented paragraph, not Quote (#2737)
LibreOffice puts a paragraph indented on both sides on the clipboard as
<blockquote>, its margins in the page's stylesheet. Paste mapped it to the
centred, italic Quote style. On paste only, it now becomes a Normal
paragraph indented by the blockquote's stylesheet margins (else 0.5 in each
side). Opening .html files still maps blockquote to Quote.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 03:46:54 -04:00
ce38b0c372 #1297: copied equations go in the MathML clipboard formats Word reads (#2614)
A copy or cut of one equation on its own now also puts its MathML in the
platform's MathML clipboard formats, beside the HTML (with MathML, #816) and
the linear text: "MathML" and "MathML Presentation" (UTF-16LE) on Windows,
public.mathml.presentation and public.mathml on macOS. These are the names
W3C MathML 3 section 6.2.4 registers, and Microsoft's "MathML Support in
Microsoft 365" doc says Office checks them first when it pastes math. No
public clipboard format carries OMML. A copy with text around the equation
doesn't offer them, so Word keeps the text.

Not yet verified in Word: the parity docs say MathML clipboard formats, not
an editable paste.


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 03:46:15 -04:00
4d8204c2f2 #2634: a table inserted in right-to-left text is right to left, so Tab moves left (#2688)
Tab already follows reading order (next logical cell) and right-to-left
tables (w:bidiVisual) already lay the first cell out at the right. The
bug was that insert.table ignored the caret paragraph's direction, so a
table made while writing RTL text was a left-to-right table and Tab went
rightwards. Like Word, insert.table now makes a right-to-left table when
the caret's paragraph reads right to left.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 03:43:47 -04:00
Charan Rathore 5b322e1530 fix(commands): Export PDF and PNG without a path ask where to save (#2665)
Signed-off-by: Charan Rathore <180254320+charan-rathore@users.noreply.github.com>
2026-10-18 03:43:27 -04:00
NetterSilverandClaude Haiku 5.5 70c5c44f01 Promote the cell below when deleting a vertical merge's first row (#2649)
Found while testing crates/doc/src/table.rs:129 (Table::delete_row), called from crates/engine/src/cmd/table.rs:526 (del_row)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 03:43:16 -04:00
4950690479 #498: Indonesian (id-ID) spelling proofing (#2576)
Indonesian spelling reads the installed Hunspell id_ID dictionary at runtime
(Debian/Ubuntu hunspell-id, LibreOffice dict-id, the Dictionaries folder or
WORDCRAFT_DICTIONARIES), like Czech, Polish and Portuguese: nothing is bundled,
and without a dictionary Indonesian text gets no spelling marks.

- ProofLang::Id for id, id-ID, ind and the legacy in tag
- suggestions reuse the dictionary-driven Czech ranking (MAP/REP/TRY/KEY of
  the loaded dictionary), nothing Indonesian hard-coded
- hyphenated reduplication accepted whole or by parts (kupu-kupu, anak-anak);
  hyphenated clitics after capitals/abbreviations (KTP-nya, se-Indonesia)
- generic grammar only: repeated word (offers anak-anak first), space before
  punctuation, double space, with Indonesian messages
- Review > Language, status bar, Set Proofing Language, File > Options >
  Proofing list Indonesian; name translated in every catalog
- tests use a hand-written synthetic dictionary; engine end-to-end test

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 03:42:52 -04:00
4442390213 DOCX: keep the glossary document (building blocks) (#2631)
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 03:23:25 -04:00