Commit Graph
874 Commits
Author SHA1 Message Date
Fin WarmanandBrandon Thomas a492189a84 DOCX: preserve zero effect extents on rotated drawings (#2432)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:23:59 -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
Marco ArnulfoandBrandon Thomas 8f0000de63 Text boxes: framed paragraphs run with the box's text, not drawn over each other (part of #2357) (#2383)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:23:27 -04:00
Marco ArnulfoandBrandon Thomas 9bed0156df OpenType ligatures follow w14:ligatures: model, DOCX read and write, shaping (#2351)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:23:12 -04:00
Marco ArnulfoandBrandon Thomas f7de98a711 DOCX: a w:u without w:val draws no underline (fixes #2362) (#2380)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:22:57 -04:00
d6f20f93fd Tables: at-least rows taller than a page start on a fresh page; header rows follow (#1742) (#2004)
* WIP for #1742

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

* #1742: parity doc separates the Word-observed case from synthetic-test behaviours

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:57:47 -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
b8279c4da5 #1960: add editable table cell margins dialog (#1988)
Co-authored-by: justinjohn0306 <babyjjbabyjj549@gmail.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:56:48 -04:00
SlavenDjandBrandon Thomas 2caa9db109 #1903: undo-history footer Cancel closes the popup (#1916)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:56:34 -04:00
Fin WarmanandBrandon Thomas 4dcd4749ca Layout: align behind-text cell pictures (#1871) (#1871)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:56:19 -04:00
d4a3292834 Proofing: -ically adverbs such as "specifically" are no longer flagged (#1694) (#1854)
* #1694: -ically adverbs are no longer flagged as misspelled

English spelling accepts "-ally" adverbs built on an "-ic" adjective in the
word list (specific → specifically, scientific → scientifically), as Word does.

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

* #1694: only -ic adjectives take -ally

Review (FredApps): the "-ally" → stem rule applied to every known word,
so "desktopally" was accepted. The rule is now "-ically" → "-ic"
(specifically → specific); other words don't take "-ally".

Test: non_ic_words_do_not_take_ally (desktop, house, final, green).

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 09:56:04 -04:00
7f4b649f6f RTF export: sections are saved (gap 19) (#1776)
* rtf-sect-export: WIP

* Gap 19: RTF export writes sections

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

* Gap 19: RTF export writes sections — review fixes

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

* odt-sect-export: WIP

* Gap 19: ODT export writes sections

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

* Gap 19: ODT export writes sections — review fixes

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

* gaps log: RTF and ODT section export both done

* Gap 19: ODT continued lists share the earlier list's style; one RTF and ODT row in the parity table

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>
2026-10-18 09:55:42 -04:00
0c8399896f cli: open a password-protected Word file with --password (#1770)
info, text, convert, render and inspect took no password, though file.open
understood one, so an agent driving the CLI could not open a protected
document at all. --password, --password-file and WORDCRAFT_PASSWORD, in
that order.

The file form exists because a password on a command line is readable by
every other process on the machine; a trailing newline is dropped so a
file written by echo works. Never logged, never named in an error.

Rebased onto current main, which moved `open` from &str to &Path so that a
file name that isn't valid Unicode no longer crashes the CLI (#1440). Both
changes touch the same function, so the resolution keeps their shape: the
closure that substitutes the real path still stands, and it takes the
password as a second argument.

Co-authored-by: Bra1nZ <bra1nz@astraoffice.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:55:26 -04:00
69c2414615 Fonts: bold Arial Black is not emboldened again, as in Word (#1750)
Old releases of heavy faces (the core-fonts Arial Black) claim weight 400 in
OS/2, so bold text in them was drawn with synthetic bold. Current releases say
900 and Word draws bold Arial Black unchanged. A static face whose file says less
than semibold now takes the weight its family's last word names: Black/Heavy 900,
ExtraBold/UltraBold 800. Files that already declare a heavy weight keep it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 09:55:11 -04:00
Diego GueriniandClaude Opus 5.5 879e688fec File › Close closes the document and keeps the window (#1712) (#1996)
* File › Close closes the document and keeps the window (#1712)

File › Close (Mod+W, Mod+F4) quit the whole app. In Word it closes the
document and the window stays. WordCraft already has that state from
the Start screen (#1129): no page, the ribbon greyed out but for Help,
File › New and Open to go on.

`WordApp::execute` now handles `file.close` itself. After the usual
Save / Don't Save / Cancel, the document is replaced by the placeholder
blank document that marks "no document open" and the Backstage closes.
The window's close button passes `{"quit": true}`, so it still asks and
then quits. The parameter travels with the prompt, so a Cancel leaves no
state behind. With no document open, Close has nothing to close.

Tests: the Close tests that used `quit_requested` as "Close went through"
now check that the document closed and the window stayed. Closing from
the empty window asks nothing, File › New goes on from there, and the
window's close button still quits after Don't Save.

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

* Close keeps the window for programmatic closes too (#1712, #1391)

#1391 landed on main meanwhile: a programmatic `file.close` on unsaved
work needs `{"force": true}`. Its tests, and the save prompt's focus
test, took "Close went through" to mean `quit_requested`. With #1712 a
close, forced or not, closes the document and keeps the window, so they
now check that the document closed and the app is still running. The
`force` guard itself is unchanged.

docs/control-protocol.md: a closed document leaves the window open, and
`file.new` or `file.open` goes on from there.

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

* #1712: a direct file.close never discards unsaved changes unless forced; Don't Save forces it

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 09:38:16 -04:00
.CooCoo f5b3c5d069 Contributors: dotCooCoo's entry shows the GitHub profile name again (#1982)
The merge of main into #1250 (ea0d27a6) resolved its conflict in
contributors/people.toml without the sync_github_name = true line that
#1250 added to [people.dotCooCoo]. The line is back, so the credits
show the name on the GitHub profile as this entry's display name
(crates/ui-egui/build.rs).
2026-10-18 09:38:11 -04:00
Ian Holloway f8ffab72e2 Tests: keep font-cache misses independent of optional Thai fonts (#1981)
Assisted-by: GPT-6

Signed-off-by: IanHollow <72767437+IanHollow@users.noreply.github.com>
2026-10-18 09:38:06 -04:00
NetterSilverandClaude Haiku 5.5 0b1c957233 Escape block syntax after manual line breaks in Markdown export (#1980)
Found while testing crates/formats/src/markdown.rs:1222

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 09:38:01 -04:00
Wade 999e2ae896 PDF tests read ActualText spans, so RTL extraction no longer depends on the installed Arabic font (#1773) (#1973) 2026-10-18 09:37:56 -04:00
.CooCoo 438dec0d61 Fonts: the font scan leaves out faces with no outline or color bitmap tables (#1972)
The system font scan (file_face_names) also catalogs faces with none of
the tables skrifa reads glyph outlines from (glyf, CFF, CFF2, VARC) and
none of the color bitmap tables the renderer draws (sbix, CBDT). On
macOS 27.0.1 the scan of /System/Library/Fonts catalogs "GB18030 Bitmap"
(Supplemental/NISC18030.ttf), and the font list shows it. The face
stores its glyphs as bdat bitmaps and maps 27,544 characters.
FontDb::outline returns an empty path for each of them, and the face has
no color glyph tables. The renderer draws none of them.

file_face_names now leaves out a face whose table directory has none of
those six tables. It reuses OUTLINE_TABLES from the interface CJK
fallback (#1250). VectorCraft's font scan checks the four outline tables
(storytold/vectorcraft#781). WordCraft's renderer also draws sbix and
CBDT bitmaps (#1504). Noto Color Emoji has CBDT and none of the outline
tables, and the scan keeps listing it.
2026-10-18 09:37:50 -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
NetterSilverandClaude Haiku 5.5 d04d756c4e Grey out and guard ribbon split buttons when disabled (#1918)
Fixes #1908

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 09:37:31 -04:00
SlavenDj 85c7d1214b #1895: recovery page buttons keep theme text colors (#1898) 2026-10-18 09:37:27 -04:00
SlavenDj 5e751c848b #1873: Backstage back chevron uses plain inset in macOS full screen (#1879) 2026-10-18 09:37:23 -04:00
Bra1nZandBra1nZ 2707ac403f mcp: let open_document take a password (#1796)
The engine has read passwords since the support landed — file.open pulls
`password` out of its parameters and hands it to open_path_in. The UI asks
and retries, the CLI has --password. The MCP tool never passed it on, so an
agent driving the server or the app could not open a protected document by
any route.

Advertise it in the schema, keep it optional, forward it.

Without a password the parameter goes over as null, not "": file.open reads
an empty string as "no password given", so collapsing the two would open a
protected document with an empty password instead of failing.

Three tests. The first I wrote expecting file.open as the backend method
and it failed — exec wraps everything as engine.execute with the command
under params. The test was wrong about the code.

13 lib + 5 integration tests, clippy -D warnings and fmt clean.

Co-authored-by: Bra1nZ <bra1nz@astraoffice.com>
2026-10-18 09:37:17 -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
da607a00ee ODT export: sections are saved (gap 19) (#1777)
* odt-sect-export: WIP

* Gap 19: ODT export writes sections

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

* Gap 19: ODT export writes sections — review fixes

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

* ODT export: a list cut by a section continues with text:continue-list; drop duplicate parity rows

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>
2026-10-18 09:37:06 -04:00
JoaoAugusto00andBrandon Thomas 4a251d4b9c docs: how to install spelling dictionaries (pt_BR example) (#2510)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:57:46 -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 c92d120098 Honor table row keep-next during pagination (#2494)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:57:07 -04:00
86ad3ddb63 DOCX: two lines in one and horizontal in vertical (w:eastAsianLayout) survive a save (#2486)
Read w:eastAsianLayout (ISO/IEC 29500-1 §17.3.2.10) into a new
CharProps::east_asian_layout and write it back after w:lang, in runs and
styles. Values outside the schema are left unset. Layout is unchanged.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:56:48 -04:00
Fin WarmanandBrandon Thomas fc08b0e4f6 Fix PDF outline targets after leading page breaks (#2484)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:56:29 -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
Fin WarmanandBrandon Thomas 56d0a162b3 Share AutoFit donor reductions equally (#2464)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:55:37 -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
divyanshu2074 1880f6162c fix(formats): support html entities, wbr zero-width break, and page-break-after (#2400) 2026-10-18 04:54:50 -04:00
Marco ArnulfoandBrandon Thomas 61ad110e9f Layout: automatic space between Asian text and Latin text or digits (autoSpaceDE, autoSpaceDN) (#2358) (#2397)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:54:39 -04:00
fa755e9de4 Fonts: restore missing strokes in hint-reliant Chinese fonts (#2389)
Co-authored-by: xyz9516 <19662679+xyz9516@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:54:20 -04:00
Marco ArnulfoandBrandon Thomas d2321d05d9 DOCX: positional tabs (w:ptab) keep their alignment, base and leader and go to the margins or indents, as in Word (#2367) (#2387)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:54:01 -04:00
7c95f02050 #1743: Ctrl+wheel zoom no longer scrolls the document (#2386)
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 04:53:42 -04:00
2db55b5498 fix(smart_art): normalize layout and color identifiers and preserve item text with leading whitespace (#2365)
* fix(smart_art): normalize layout and color identifiers and preserve item text with leading whitespace

* Use Iterator::find (clippy manual_find)

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:45:17 -04:00
341f370368 fix(pdf): scale bookmark destination coordinates with page Fit and support case-insensitive bookmark lookup (#2364)
* fix(pdf): scale bookmark destination coordinates with page Fit and support case-insensitive bookmark lookup

* 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:45:06 -04:00
divyanshu2074 09f14d5a5e fix(math): parse array column specs, support starred operatorname and tag, preserve delim sep in latex (#2353) 2026-10-18 04:44:55 -04:00
NetterSilverandClaude Haiku 5.5 088156d4ca Keep spaces that follow a tab in the ODT round trip (#2317)
Found while testing crates/formats/src/odt.rs:347 (writer, `plain_inlines`) and crates/formats/src/odt.rs:1550 (reader, `text`)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 04:44:44 -04:00
divyanshu2074 e1b39cd41d fix(docbin): correct sprmTCellWidth operand parsing and handle percentage widths (#2312) 2026-10-18 04:44:34 -04:00
Marco Arnulfo d32119c377 Copying a picture or shape replaces the clipboard's old text, so Paste duplicates it (#2306) 2026-10-18 04:44:23 -04:00
6b3de1c4dc fix(docbin): handle default codepage, VT_I4, multiple property sets, and FILETIME dates (#2304)
* fix(docbin): handle default codepage, VT_I4, multiple property sets, and FILETIME dates

* 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:44:13 -04:00
Marco ArnulfoandBrandon Thomas 5e2b63b710 Contributors: add Marco Arnulfo (#2302)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 04:44:03 -04:00