Commit Graph

192 Commits

Author SHA1 Message Date
Dmitrii Khlapov 55bfc33418
Undo history list beside the Quick Access Toolbar's Undo (#701) (#855)
* #701: Undo history list beside the Quick Access Toolbar's Undo

A drop-down arrow next to Undo lists recent steps, newest first; hovering a
row highlights it and every newer step, the footer reads "Undo N Actions"
(Cancel when none is highlighted), and a click undoes them all at once.

Engine: Session::undo_history (newest first, capped at UNDO_LIST_MAX = 100)
and Session::undo_steps; edit.undoTo {"count": n} (0, negative and non-number
counts rejected, counts past the depth clamped, stops at protection) and the
read-only edit.undoHistory for CLI and MCP. Catalog: Undo List.

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>

* #701: Bulgarian for the Undo history strings; drop a duplicate Turkish entry

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-12 10:05:06 -04:00
Brandon Thomas 5383d80f75
An empty continuous section mark takes no room (#940)
* R21: an empty continuous section mark takes no room

An empty paragraph that only carries a section break before a continuous
section takes no room in Word: the text after it follows right on, and
columns balanced above it don't count it. A break on a paragraph with text
keeps its line. Measured in Word for Windows: 10 synthetic cases. The SARP
form's fields drifted a line lower at each of its continuous breaks.

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

* ROADMAP: keep the progress log separator under its header

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 10:02:07 -04:00
Dmitrii Khlapov 8c67ef7c28
Start on File › Home when launched with nothing to open (#766) (#853)
* #766: start on File › Home (Start screen) when launched with nothing to open

Desktop and web start on Backstage Home (Blank document, templates, Recent)
when no file, --sample or --control is given; Esc/back leaves the empty blank
document. File › Options › General › Start-up checkbox (ui.startScreen, kept
between runs, default on). WordApp::new is unchanged; hosts opt in via
WordApp::start_screen. ui_shot: {"empty":true,"startScreen":true}.

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>

* #766: Bulgarian for the Start screen setting

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-12 10:00:28 -04:00
Brandon Thomas fc52079f58
R19: keep with next splits a paragraph that doesn't fit anyway (#933)
Word moves a "keep with next" paragraph to the next page only when it would
fit on this one by itself; one that doesn't fit anyway breaks as usual, its
last lines going over with the next paragraph (with keep lines together it
moves whole). A chain of kept paragraphs moves together. Measured in Word
for Windows: 20 synthetic cases. NIH's five-line kept paragraph no longer
leaves a third of a page empty.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:58:26 -04:00
Dmitrii Khlapov c9079196db
AutoCorrect: the English replacement list applies only to English text (#835) (#846)
* #835: AutoCorrect's English replacement list applies only to English text

Built-in word entries (teh, i, dont…) are replaced only when the word's
language (run w:lang, style, document default) is English or unset;
symbols, fractions and user entries apply in every language. Polish,
Croatian, Bosnian and Serbian "i" ("and") is no longer turned into "I".

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

* #835 review: untagged text follows the editing language; English as proofing decides it

- Text with no language at all (a .docx without w:lang) is in the editing language, so with a
  Polish interface `Ala i kot ` keeps its `i` there too.
- `wordcraft_proof::ProofLang::from_tag` decides what is English (it also takes `eng`), so
  AutoCorrect and proofing agree; the local `is_english` is gone.
- Tests through `set_editing_language` (the document-default path) and with no language at all.
- docs/typing-parity.md: the Croatian/Bosnian/Serbian case needs the text tagged, as those
  interfaces set no editing language yet.

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-12 09:56:29 -04:00
Brandon Thomas 7d37b14679
R16: list indents and style indents combine like Word (#927)
A numbered paragraph style's own indents (and those of styles based on it)
now beat the list level's, its base styles' don't, and the paragraph's own
list beats every style. A paragraph that switches its list off (numId 0)
drops the styles' indents, as Word does; the first Backspace in a List
Paragraph item makes the item's indent the paragraph's own so the text stays
put. Measured in Word for Windows: 27 synthetic cases, all match. NIH's
Heading 3s sit at their 0.9" and its "sample text" paragraphs at the margin.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:55:41 -04:00
Brandon Thomas 5aa8151a53
Text frames in headers, footers and cells, kept on save (#935)
Found in NIH's monitoring-plan template compared with Word for Windows:
its footer puts the page number in a text frame (w:framePr: centred,
text wrapping around it), and Word draws "NCCIH DSMP Template" ending
just left of the number on the same line.

Before: frames other than drop caps were ignored on import, so the
number took a line of its own above the footer text (making every page
a line shorter), and the frame was lost on save.

After: a paragraph's text frame is read (size, anchors, alignment,
offsets, wrap, distances) and written back. In headers, footers, table
cells and text boxes it is placed like a floating object, sized to its
text unless it has a width, and the text after it wraps around it; the
DSMP footer now matches Word's. Frames in the body text still lay out
in line.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:52:26 -04:00
Brandon Thomas 541e10e23a
R20: hidden end-of-cell marks (w:hideMark) (#939)
Read and write w:hideMark on table cells, and lay it out like Word: a cell's
empty last paragraph takes no room, spacing and all, so a row of only such
empty cells is just its borders; an ordinary empty cell keeps the row a line
tall. Measured in Word for Windows: 9 synthetic cases. NIH's Table A no
longer shows a blank row.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:45:40 -04:00
Dmitrii Khlapov 2f833b6acf
Sorting and table numbers follow the text's language (#836, #837) (#844)
* #836, #837: language-aware sorting and locale numbers in tables

Sorts (Table > Sort, Home > Sort, index and its letter headings, bibliography,
Table of Authorities) use the text language's alphabet via a small pure-Rust
collation (crates/doc/src/collate.rs). Table sort and formulas read numbers
with the cell language's decimal/group separators and write formula results
with its decimal separator (crates/doc/src/locale_number.rs). Sort comparators
are now total orders.

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

* #836, #837 review: ordinals, leading zeros, percentages; untagged text; decomposed letters

- parse_number: a trailing separator with no digits is the whole number (`1.`, a
  numbered "Lp." column, sorts as 1); a first group of `0` is never grouping
  (`0.125` in Polish is 0.125, not 125); a trailing `%` is ignored (`12 %` is 12);
  an en dash is a minus.
- Text with no language follows the document default, else the editing language
  (`cmd::default_lang`), as AutoCorrect does: a Polish interface reads `3,50` as
  3.5 in an untagged document. Table sort and formulas, paragraph sort, the
  index, the bibliography and the Table of Authorities use it.
- Collation composes a letter and a following combining mark first (table from
  Unicode NFC), so a decomposed `ż` (z + U+0307) sorts as `ż`.
- Tests: every Polish letter and its index heading, decomposed letters, the
  ordinal column, an untagged Polish SUM, Polish bibliography order.

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-12 09:43:01 -04:00
Brandon Thomas 2e66cbb261
R18: a list label adds ascent, not descent, to its line (#928)
Word sizes a list item's first line with the label's ascent when it is
taller, but keeps the text's descent below the baseline: a Symbol bullet's
deeper descent (and a Courier New label's) doesn't count. Measured in Word
for Windows: 6 synthetic cases. NIH's bulleted items were a fifth of a point
taller each, enough to push lines over a page bottom.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:41:37 -04:00
Brandon Thomas 99561097d5
DOCX: a list level without a list takes its style chain's list (#926)
Found in NIH's monitoring-plan template, compared with Word for Windows.

Before: a w:numPr that gives a level (w:ilvl) but no list (w:numId) was
dropped. Outline-numbered templates do this all the time: Heading 3 is
based on Heading 2 (which names the list) and only says "level 3", so
every Heading 3 numbered as a Heading 2 (6.15 where Word shows 6.4.5).

After: such a level takes the list of the nearest style in its based-on
chain that names one (ECMA-376 17.3.1.19), in styles and in paragraphs;
with no list anywhere in the chain there is no numbering. Saved files
carry an ordinary list reference.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:37:38 -04:00
Dmitrii Khlapov 45abb5ded3
#743: freeforms in groups keep their shape; text boxes keep their margins and Resize to fit (#843)
A Word 365 cover page lost its look. The missing fills came from
theme-coloured shapes (scheme colours and wps:style fill references),
which the reporter's 0.5.0 build didn't read; #611 fixed that on main.
Two causes were still open on main:

- A freeform (a:custGeom) inside a wpg group was drawn as a rectangle.
  read_wsp now reads custom geometry, so group members get it as well.
- Text boxes ignored wps:bodyPr lIns/tIns/rIns/bIns and a:spAutoFit.
  Layout always used Word's default margins, so a title box with no
  margins that was just tall enough for its text lost its second line.
  TextBody now carries the box's own margins and auto_fit. Layout uses
  those margins and doesn't cut the text of a box that resizes to fit.
  Both are written back on save.

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-12 09:37:13 -04:00
Brandon Thomas 906e0f8aca
.doc import: tab stops, and sections that end at their section marks (#925)
Found by comparing EPA's .doc templates with Word for Windows.

Before: custom tab stops in .doc files were skipped, so centred titles,
right-aligned dates and dot leaders set with tabs lost their alignment;
and a section mark (0x0C) at a section's end became a page break inside
a paragraph, so the file's sections (continuous breaks, footers) were
lost and every section break started a new page.

After: sprmPChgTabsPapx and sprmPChgTabs are read in styles and
paragraphs (removed stops clear inherited ones; each added stop keeps
its alignment and leader), and sprmPChgTabs' one-byte size is decoded
per [MS-DOC] (it was read as two bytes, swallowing the sprms after it).
A section mark at a section's end now ends that section's last
paragraph, so the section's properties and footers are kept. Both EPA
.doc templates in the comparison set now have Word's page count.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:34:10 -04:00
Brandon Thomas 64f656a8bc
Layout: spaces and tabs don't make a line taller, as in Word (#931)
Found comparing Microsoft's own specification documents with Word for
Windows: their tables of contents were a third taller in WordCraft
(13.4 pt per entry against Word's 10.9). Each entry's 9 pt text has tab
runs in an 11 pt font, and WordCraft sized the line by them.

Measured in Word with 13 synthetic documents: 11-20 pt tabs, spaces and
ideographic spaces next to 9 pt text leave the 9 pt line as it is,
wherever they are on the line; a line of only such whitespace takes the
paragraph mark's height; a big letter or no-break space does grow the
line. WordCraft now skips spaces and tabs when it sizes a line, and all
13 cases match.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:30:34 -04:00
Dmitrii Khlapov 6f35313f68
#819: Alt+Q moves to "Tell me" command search (#849)
Word for Windows' Alt+Q opens the "Tell me" box; in WordCraft it did nothing.
Interface commands (ui.*) aren't in the engine's keymap, so keys.rs gets a
small table of interface shortcuts, checked before the keymap from the page
and from the rest of the window. Alt+Q opens command search
(ui.dialog {"name": "commands"}) and its key text isn't typed. Not on macOS,
where Option+Q types a character.

Also fixes the ROADMAP progress log, whose separator row sat below two rows.

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-12 09:30:18 -04:00
Manuel Carmona 1677c2d9cf
Ribbon groups fit above their labels (View › Show, Developer › Controls, Layout › Paragraph) (#910)
View › Show stacked four check boxes in a column made for three: since
Hide White Space (#645) joined Ruler, Gridlines and Navigation Pane, the
fourth row was drawn over the "Show" group label. It now sits in a second
column.

A new test draws every tab in every interface language and fails on any
group taller than the ribbon's content area (CONTENT_H, 66 pt). It found:

- Developer › Controls, 75 pt: 3 pt after each row of small buttons. The
  rows now fill the height with no gaps, like every other stack.
- Layout › Paragraph (#654), which panicked in debug builds: `add_space`
  between grid cells trips egui's "add_space makes no sense in a grid
  layout" assertion. The 8 pt gap before the Spacing column now sits
  inside those cells, so it looks the same. The group was also 68.5 pt:
  1.5 pt between rows instead of 3 fits it.

- widgets.rs: under cfg(test), group_titled records any group whose
  content is taller than CONTENT_H.
- ribbon.rs: ribbon_groups_fit_above_their_labels.
- ROADMAP progress log and docs/ui-parity.md revision history.
- contributors/people.toml: my own entry.

Co-authored-by: Manuel Carmona <328347120+manucarcor@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 09:27:44 -04:00
Brandon Thomas 26cdcfd4c6
DOCX: table-of-contents links look like Word's (#930)
Found comparing Microsoft's own specification documents with Word for
Windows: their table of contents was blue and underlined in WordCraft
and plain in Word.

Measured with nine synthetic documents in Word: a run with the
Hyperlink character style, inside a hyperlink, inside a TOC field's
result, is drawn plain (with or without the TOC's \h switch). A
Hyperlink-styled run outside a hyperlink, another character style,
direct formatting, or a hyperlink in another field keep their look.

The import now drops the Hyperlink style from exactly those runs (the
links stay), so all nine cases render as Word does.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:26:56 -04:00
odedigo fccc09e4c9
fix(ui): draw non-Latin file names in the window caption (#840)
The painted title uses a Latin-only face, so names in other scripts were shown as question marks. A covering fallback face is now loaded for the caption.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 09:23:47 -04:00
Brandon Thomas 90515abd1e
Keytips: Word for Windows' tab letters (#922)
Observed in Word for Windows (Microsoft 365): pressing Alt badges the
tabs File F, Home H, Insert N, Design G, Layout P, References S,
Mailings M, Review R, View W, Help Y, and the Search box Q.

Before, WordCraft used Design L, References R, Review S and View V,
and File and Help had no letter, so Alt, W or Alt, R went to the wrong
tab for anyone used to Word. Now the letters match; Alt, F opens the
Backstage and ends keytips.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 09:23:21 -04:00
odedigo 0acf6bd512
fix(windows): start 32-bit builds on OpenGL so launch no longer exits (#839)
* fix(windows): start 32-bit builds on OpenGL so launch no longer exits

DirectX 12 graphics pipeline creation fails on 32-bit Windows, so the app quit before the window appeared.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add @odedigo to the contributor names list

The About window credits this username; no real name or display name was chosen.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 09:20:53 -04:00
MarekSpodBiedry bc60cbaadb
Zoom after One Page keeps one page per row (#768) (#832)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 09:05:40 -04:00
MarekSpodBiedry 7fbcd0643a
Keep the font table and embedded fonts when saving a .docx (#770) (#831)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 09:02:02 -04:00
Dmitrii Khlapov 00ed50515e
New documents follow the system region: A4, centimetres and decimal comma outside the US (#838) (#857)
* #838: new documents follow the system region (A4/cm/decimal comma outside the US)

- geom: Region (from a locale tag; CLDR Letter and US-measurement territories,
  decimal separator), Unit::format_with; parse_measure takes either separator
  and a Unicode minus.
- engine: Session.region (plain value, en-US headless), Session::units()
  (explicit Measurement units choice wins, else the region's),
  blank_document(); file.new blank uses the region's paper; file.options
  takes "region" and units "auto" and reports unitsFromRegion/region.
  Prefs.units is now Option and saved as measurementUnits (old saved values
  were the inch default, not a choice).
- ui: region from WORDCRAFT_REGION, LC_PAPER/LC_MEASUREMENT/LC_NUMERIC, the
  platform locale (browser on the web) and Windows' home location; length
  fields show and read the region's decimal separator (MeasureExt); Size
  menu lists sizes in the measurement unit.
- Tests: engine new_documents_follow_the_region, geom region/format/parse,
  ui length_fields_follow_the_region. Docs: localization parity, roadmap.

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

* Review fixes for #857: keep a measurement unit chosen before the rename

Settings saved before #838 kept the unit under `editing.units`, defaulting to inches. On load,
a value there other than inches was the user's own choice, so it now carries over to
`measurementUnits` (unless that key is already present); inches, junk and non-strings follow
the region. Test: `a_unit_chosen_before_regions_survives_the_rename`.

Also merged main (ROADMAP.md, engine lib.rs re-exports: `blank_document` and main's
`set_system_locale`). The Windows region code (`GlobalizationPreferences::HomeGeographicRegion`)
was cross-checked with clippy -D warnings for x86_64-pc-windows-gnu.

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

* #838 review: saved region choice, Unix conventions apart, the browser's locale

- File › Options › Advanced › Region: Automatic (the system's) or a chosen region, saved with
  the preferences (`Prefs::region`; `file.options {"region": "pl-PL" | "auto"}`). The session
  keeps the platform's region as `system_region`; `Session::region()` is the one in effect.
  Measurement units gains an Automatic entry (follows the region).
- Unix: numbers follow LC_NUMERIC (else LANG), paper LC_PAPER and measurement LC_MEASUREMENT,
  each on its own (`Region::with_paper_and_measurement`); WORDCRAFT_REGION and LC_ALL still set
  all three.
- Web: sys-locale's `js` feature, so the browser's language reaches the region (and the
  interface language, as its comment already said).
- Runs without preferences (WORDCRAFT_NO_PREFS) stay en-US unless WORDCRAFT_REGION is set.
- docs/localization-parity.md: where the region comes from, the Windows home location vs. Word's
  regional format, and where the decimal separator comes from.

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

* #838 review: rustfmt

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

* #838: rustfmt after merging main

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>

---------

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-12 08:23:43 -04:00
Dmitrii Khlapov 411ce31de7
Paste keeps other programs' formatting; clipboard pictures on Wayland (#687, #833) (#847)
* #687, #833: paste keeps other programs' formatting; Wayland clipboard pictures

- Paste (Ctrl+V, Home > Paste) reads the system clipboard's HTML, else RTF,
  and keeps its formatting; our own copy still wins while the clipboard holds it.
  Windows CF_HTML headers are understood; oversized or empty payloads fall back
  to the text.
- Merge Formatting inserts the content in the destination's font and paragraph,
  keeping bold, italic, underline and strikethrough (it did nothing before).
- Paste Special lists what the system clipboard holds (HTML, RTF, picture,
  text); Mod+Alt+V opens it even with only a picture there.
- Services gain clipboard_html, clipboard_rtf and clipboard_formats hooks; the
  host reads RTF on Windows (clipboard-win) and Wayland (wl-clipboard-rs).
- Linux: arboard's wayland-data-control feature, so pictures copied in a
  browser or Spectacle reach a native Wayland window (KWin only syncs to
  Xwayland while an X11 window has focus); other picture types are read
  from Wayland directly. A paste that finds nothing usable names the formats
  on the clipboard, or why its picture couldn't be read, instead of "empty".

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

* Review fixes for #847: translate the Paste Special picture strings; Windows/macOS unused import

- `Picture` and `Pastes the clipboard's picture.` translated in all 15 interface catalogs.
- clipboard.rs: `MAX_FILE_BYTES` is used only by the Linux/Wayland module, so it is named
  there; the top-level import was unused (a warning, and a clippy -D warnings error) on Windows
  and macOS.
- Merged main (ROADMAP.md, docs/gaps.md, docs/file-format-parity.md, main.rs services: keeps
  both the clipboard hooks and the default-app hook from #295). Cargo.lock adds only the
  wl-clipboard-rs set.

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>

---------

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-12 08:18:25 -04:00
MarekSpodBiedry 18e25d0883
ODT import reads page size, orientation and margins from styles.xml (#810) (#829)
* ODT import reads page size, orientation and margins from styles.xml (#810)

* Review fixes for #829: clamp ODT page size and margins

Page width/height from styles.xml are kept to 36..=1584 pt (the DOCX
reader's floor, Word's 22-inch maximum) and each margin is capped at the
page's longer side, like w:pgMar. Adds a hostile-values test and collapses
a nested if for clippy.

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-12 08:01:25 -04:00
Dimitar e619b12ceb
i18n: add Bulgarian (bg) interface translation (#825)
* i18n: add Bulgarian (bg) interface translation

A 2,386-entry Bulgarian catalog: every key of the reference catalog, the equation gallery's
labels and everything the interface audit finds. Written from the meaning of the English
labels in ordinary Bulgarian computing vocabulary; no other product's localisation and no other
catalog in this repository was used. Counts use count-neutral wording ("Думи: 21").

- bg, bg-BG, bg_BG.UTF-8 select it automatically; "Български" in Options and
  ui.language with {"value":"bg"}.
- The interface audit checks Bulgarian coverage the way it checks Russian.
- Tests: locales and saved preference, catalog coverage and key translations, count wording,
  and the bundled Inter/JetBrains Mono faces covering the Bulgarian letters.

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

* Review fixes for #825: Bulgarian built-in style names

Adds the built-in style names Russian translates (Normal Table, Default
Paragraph Font, Annotation Text/Reference/Subject, Envelope Address/Return,
Index Heading, Index {n}, Line Number, Normal Indent, Table of Figures, TOA
Heading, TOC {n}) and Good afternoon; updates the entry count in the docs.

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-12 07:56:30 -04:00
Eduardo Soares 1e53adf9d6
Portuguese proofing: pt-BR spelling, suggestions, grammar and hyphenation (#100) (#797)
* M15: Polish interface, and Polish spelling, grammar and hyphenation

Interface
- Polish is the tenth interface language ("Polski", pl.tsv, 1,045 entries);
  pl, pl-PL and pl_PL.UTF-8 system locales select it automatically.
- Right-click menu labels now go through translation in every language.
- Review > Language is a menu (English US/UK, Polski, Do not check spelling
  or grammar); the status bar shows the language at the caret.
- With a Polish interface, new blank documents and opened .txt/.md files
  default to pl-PL.

Proofing
- Each run is checked in its own language (w:lang, resolved through
  styles): squiggles, F7, review.issues, suggestions and hyphenation.
  Text in languages without proofing tools is no longer flagged as English.
- Polish spelling from the SJP.PL Hunspell dictionary (Apache-2.0 option),
  read by a new Rust affix engine (crates/proof/src/affix.rs); 875 KB asset,
  ~4.5M word forms. Regenerate with the pl_dictionary example.
- Polish suggestions: case, missing diacritics, rz/ż, ó/u, ch/h confusions,
  missing spaces (napewno -> na pewno), edit distance.
- Conservative Polish grammar rules: repeated words, spacing, doubled
  punctuation, sentence capitals, missing comma before że/który/ponieważ/
  aby/żeby/jeśli…, we/ze forms.
- Polish hyphenation with the hyph-utf8 hyph-pl.tex patterns (MIT option);
  pattern keys widened to 20 letters, TeX exceptions parsed; the heuristic
  no longer treats ł, ż, ś… as vowels.

review.language validates and normalizes tags, can set noProof alone and
the document default; format.state reports lang and noProof.

Tests for every part, docs and ATTRIBUTION.md/NOTICE updated;
cargo xtask ci passes (fmt, clippy, test, assets, layers, wasm).

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

* Layout: rustfmt the test module order left unformatted by #391

cargo fmt --check failed on main after #391 added mod tests_grid.

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

* Review fixes for #346: read Polish spelling from the installed Hunspell dictionary

- Polish spelling uses the Hunspell pl_PL dictionary installed on the
  system (OS packages, Homebrew, LibreOffice, ~/.local/share/hunspell, or
  WORDCRAFT_DICTIONARIES) instead of a bundled 870 KB SJP.PL file;
  without one, Polish text gets no spelling marks, like Word without the
  language's proofing tools. .aff/.dic are size-capped and decoded from
  UTF-8 or ISO 8859-2 (crates/proof/src/hunspell.rs).
- The dictionary can be replaced at runtime (install_dictionary) or
  re-searched (reload_dictionary); an empty one accepts every word.
- Tests use small synthetic dictionaries written for them, so they don't
  depend on what the machine has installed.
- The bundled pl.dic, its ATTRIBUTION/NOTICE entries and the generator
  example are removed; docs describe the installed dictionary.

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

* #100: affix — accept FLAG UTF-8 and DEFAULT flag modes

Per-character flag modes are what the reader already parses; only the
multi-character encodings (long, num) stay errors. VERO pt_BR declares
FLAG UTF-8.

* #100: affix — widen flag masks to u128 (128 flag capacity)

VERO pt_BR needs 106 distinct flags; the u64 bitmask capped at 64.
Serialization is unaffected: WCAFF1 stores flag characters and
re-derives the masks on load.

* #100: affix — support FORBIDDENWORD

VERO pt_BR marks spellings it must reject with a forbidden flag (ý).
Stems carrying it are listed but never correct and never inflect.

* #100: affix — continuation classes in check

SFX A 0 able/B: the form derived by A carries flag B, licensing a
further suffix of class B (workable -> workables) while the bare stem
cannot take one. form_has_flag walks the chain depth-bounded
(MAX_CHAIN = 3); with no continuations declared it degenerates to the
stem lookup, so existing dictionaries are unaffected. VERO pt_BR uses
26 continuation rules.

* #100: affix — continuation classes in forms

Enumerate chained suffix forms (workable -> workables) under the same
MAX_CHAIN bound the checker walks, so every form the checker accepts
is listed and vice versa.

* #100: affix — round-trip continuations and FORBIDDENWORD through WCAFF1

The compact format keeps its WCAFF1 magic: continuation classes ride
on the rule's appended field (as in the .aff source) and the forbidden
flag becomes a FORBIDDENWORD line. Old files read as before.

* #100: affix — strip a UTF-8 BOM from .aff/.dic input

VERO's files open with a BOM; glued to the count line it parsed as a
stem (one garbage entry per load) and to SET it hid the directive.

* #782: affix — the module doc still rejected what the code now reads

Continuation classes and FORBIDDENWORD are supported; the header said
Rejected for both.

* #100: pt — Portuguese spelling, following the Polish module

ProofLang::Pt resolves pt/pt-BR/pt-PT/por tags; the pt module reads the
installed Hunspell pt_BR dictionary (VERO) through the affix engine —
FLAG UTF-8 flags, continuation classes and FORBIDDENWORD spellings all
exercised by the synthetic test dictionary. Hyphenated compounds are
checked part by part (guarda-roupa, ex-marido); without a dictionary
installed, Portuguese text gets no marks. Spelling message in
Portuguese; suggestions and grammar land next.

* #100: pt — Portuguese suggestions

Rounds of rising cost, driven by the dictionary's own tables: missing
accents from MAP (coraçao -> coração, saude -> saúde), the REP
confusions (seje -> seja, excessão -> exceção), a missing space after a
short function word (nãoé -> não é, dagua -> da água), one typo over
TRY, and an accent-folding stem scan — the Polish rounds, retuned for
Portuguese.

* #100: pt — Portuguese grammar flags

Conservative rules with Portuguese messages: repeated words (except
the emphatic doubles Portuguese allows), space before punctuation and
double spaces, sentence capitals knowing the Portuguese abbreviations
and dialogue dashes, and doubled punctuation. No comma rule: que opens
a clause only sometimes, so a wrong flag would cost more than a missed
one.

* #100: pt — Portuguese hyphenation

hyph-utf8's hyph-pt.tex bundled unmodified (BSD 3-clause, ATTRIBUTION
row with source and hash): 426 Liang patterns and 2 exception words;
falls back to the generic heuristic outside their reach.

* #100: pt — Review › Language offers Português (Brasil), and a pt-br interface writes pt-BR

The menu's fourth entry sets the run language; the status bar names
Portuguese; editing_lang is now allowed for pt-br (wordcraft-proof
proofs it), so new documents under a Portuguese interface are
Portuguese by default.

* #100: pt — engine test: Portuguese proofing through the review commands

review.language pt-BR normalizes the tag, review.issues reports
Portuguese spelling and grammar with the lang field, F7 and Change
apply a suggestion, Add to Dictionary works for Portuguese.

* #100: pt — Portuguese in the mixed-language proofing tests and docs

check_text proofs a Portuguese span with the Portuguese message; the
never-panic loops and the module docs cover the third language.

* #100: docs — Portuguese proofing in the gap, parity and roadmap docs

Gap 8 narrowed (English, Polish and Portuguese), localization parity
gains a Portuguese row and a revision entry, target-app-parity's
Proofing row moves 40% -> 42%, and the ROADMAP progress log records
what landed.

* #100: hunspell — LibreOffice extension folders follow the language

The search paths hardcoded LibreOffice's dict-pl; a pt_BR user whose
only dictionary is LibreOffice's dict-pt-BR extension — on Windows the
only realistic on-disk source — got silently no spelling. Both the
primary-language folder and the dashed full name are now tried, so
Polish keeps dict-pl and Portuguese finds dict-pt-BR.

* #100: pt — review fixes

Suggestion ties break toward the change nearest the word's start
(saúde before saudê, proven against a fixture that has both); the
Language menu's label is the English source "Portuguese (Brazil)" with
translations in all twelve catalogs (as Polish is); the attribution
counts pt.pat's 2 exception words; the pt fixture drops a duplicate
stem; docs/roadmap.md catches up with the landing; the throwaway spike
is gone.

* Review fixes for #782: two-suffix chain limit, module doc

- MAX_CHAIN = 2 counts suffixes in a row, matching Hunspell's two-suffix limit
  (the old bound of 3 allowed up to four); test pins that a third is rejected.
- Module doc: say probes allocate small scratch strings instead of claiming none.

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

* Review fixes for #797: NOTICE for pt.pat, no indexing in the LibreOffice folder helper

- NOTICE reproduces hyph-pt.tex's BSD 3-Clause copyright notice, conditions and
  disclaimer, which the licence requires for binary redistributions.
- hunspell::lo_ext_dirs builds its list without indexing (never-crash rule).
- Catalogs: main already translates "Portuguese (Brazil)" in every language, so the
  duplicate rows the branch added are dropped.

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

---------

Co-authored-by: witkowski01 <konradwitkowski01@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 07:43:24 -04:00
Valentin Klein 2f9bf4e800
AutoCorrect: TWo INitial CApitals, cAPS LOCK and table-cell capitals (#544) (#545)
- Correct TWo INitial CApitals: a finished word of 3+ letters with two
  leading capitals and the rest lowercase loses its second capital
  ("WOrd" -> "Word"), before the replacement list ("TEh" -> "The").
  Built-in exceptions (IDs, CDs, PCs, TVs, ...) plus user exceptions.
- Correct accidental cAPS LOCK: "wORD" -> "Word" (not iOS, mRNA, ...).
- Capitalize first letter of table cells, under its own option.
- Session::autocorrect_caps (AutoCorrectCaps, all on by default);
  tools.autocorrect takes twoInitialCaps / capsLock / capCells /
  addException / removeException.
- Each fix is one undo step right after it (the existing AutoFormat
  snapshot); case changes replace letter by letter, keeping formatting.
- Tests in tests_typing.rs; docs/typing-parity.md and ROADMAP updated.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 07:35:11 -04:00
Rees 417896301b
M1: preserve native Word ink through DOCX saves (#592)
Co-authored-by: Brandon Thomas <brandon@storyteller.ai>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 07:30:49 -04:00
RegalDragoon200 b30cda1535
Persist the custom dictionary across sessions (#40) (#796)
* Persist the custom dictionary across sessions (#40)

* Review fixes for #796: session-only Ignore All, desktop-only persistence, capped atomic I/O

- review.ignoreAll no longer adds to (and saves) the custom dictionary: ignored words go to a
  separate session-only list, as Ignore All does in Word.
- Only the desktop app wires the dictionary file. Headless MCP and `wordcraft-cli run` keep
  words in memory, so an agent never reads or changes the person's dictionary (and nothing
  writes outside an automation write root, #769).
- Loading reads through `take(1 MB)`, so a huge file is never read whole; lines that aren't a
  single word (spaces, control characters, invalid UTF-8, over 64 characters) are skipped.
- review.addToDictionary applies the same word rule (proof::custom_word), so a word added is
  never dropped on the next load.
- Saving merges the words on disk first (another process's additions survive; words just
  removed stay out), creates the folder, and replaces the file atomically (temp + rename).
  The file I/O lives in the proof crate, so the engine doesn't touch std::fs itself.
- Tests for each.

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-12 07:23:51 -04:00
Isaac Levine 64319e0039
MCP: confine file access with --automation-read-root and --automation-write-root (#769) (#798)
* Engine: check automation read and write roots on every path a command reads or writes (#769)

* MCP: confine the headless session to the automation roots (#769)

* CLI: add --automation-read-root and --automation-write-root to mcp (#769)

* Docs: document --automation-read-root and --automation-write-root for mcp (#769)

* Review fixes for #798: confine file.printPdf; guard all of engine/src

- print.rs::print_pdf_to_file (file.printPdf, added on main) wrote with std::fs::write
  directly, so a confined agent could print a PDF anywhere. It now goes through
  io::write_file, which checks the automation write root.
- The guard test now walks every file under crates/engine/src (not only cmd/), except
  io.rs, file_access.rs and the tests*.rs modules, and also flags OpenOptions.
- Tests: an engine test that file.printPdf is refused outside the write root, works inside
  and is unchanged without roots; the MCP integration test covers it too.

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

* Review fixes for #798: list file.printPdf among the confined writes in docs/mcp.md

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

* Font files added by path go through io, inside the automation read root (#769)

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 07:18:00 -04:00
Ufuk Efe 691e887004
i18n: complete Turkish interface catalog with 2,170 entries and full … (#774)
* i18n: complete Turkish interface catalog with 2,253 entries and full parity

* Review fixes for #774: Turkish entry count after merging main (2,325)

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-12 07:04:50 -04:00
ripdog 325e5a6157
M8: Truncate long Navigation headings in resizable pane (#759)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:59:54 -04:00
Hevar Hemin 62a17b841f
Bidi: auto-detect RTL paragraph direction when typing Kurdish, Arabic and Hebrew (#713)
* Bidi: auto-detect RTL paragraph direction and keep typing caret advancing smoothly

When typing in Kurdish, Arabic or Hebrew in a new document, default
paragraph direction (bidi: None) was resolving to LTR. In an LTR
paragraph, visual reordering pinned newly typed characters and the
caret to the left margin (x = 72.0), resetting to the start of the line
with every keystroke.

- Add first_strong_is_rtl() following UAX #9 rules P2/P3.
- Auto-resolve unassigned paragraph direction to RTL in layout when the
  paragraph starts with an RTL script.
- Auto-promote paragraph to RTL (bidi = Some(true)) when typing text
  starting with an RTL character.
- Add regression test in wordcraft-engine.

* Review fixes for #713: RTL only when typing into an empty paragraph

- Drop the layout fallback that drew any paragraph without w:bidi as RTL when its first
  strong character is Arabic/Hebrew: opened DOCX paragraphs keep their direction, and a
  style that sets bidi=false is respected.
- type_text promotes a paragraph to RTL only when it had no letters before the insert and
  nothing (paragraph, style chain, document defaults) sets its direction; typing into a
  paragraph that already has text no longer flips it.
- docs/typing-parity.md: Text direction section; test in tests_typing.rs.

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-12 06:51:03 -04:00
Bihacsy László e22ce1d05e
i18n(hu): complete the Hungarian catalog again (#842)
* i18n: add Hungarian (hu) interface translation

- crates/ui-egui/src/i18n/hu.tsv: complete catalog, all 1,572 keys of
  es.tsv in the same order, written clean-room from the plain meaning
  of the English labels; placeholders, escapes and trailing ellipses
  kept. Commands are nouns, messages use the informal second person,
  and only the first word of a label is capitalised. A noun after a
  number stays singular in Hungarian, so the context-free format needs
  no plural forms.
- LANGUAGES gains `hu` (Magyar); `hu`, `hu-HU` and `hu_HU.UTF-8`
  resolve to it.
- The Font dialog's preview sample is "AaBbYyZz ŐőŰű", so All Caps
  shows the double acute capitals.
- Tests: locale resolution and saved preference, key parity with the
  Spanish catalog, sample translations, count wording, the sample's
  capitals and Hungarian letters in the bundled interface fonts.
- Docs: new localization-hu.md (conventions, terminology, scope);
  README, ROADMAP, localization-parity and control-protocol list the
  new language; ATTRIBUTION row for hu.tsv.

* i18n(hu): built-in style names, equation gallery and citation styles

- hu.tsv now carries every key of the Russian catalog: built-in style
  names (Normal, No Spacing, Subtitle, TOC {n}…), the equation gallery
  and structure labels, paper sizes, watermarks and the Backstage
  greetings, plus the citation style names (1,946 entries).
- The interface audit (untranslated_interface_text) checks Hungarian
  alongside Russian and reports every language's gaps in one run.
- Tests: Hungarian keys cover the Russian catalog; built-in style
  names and numbered style templates show in Hungarian.
- Docs: entry counts and scope in localization-hu, localization-parity
  and ROADMAP.

* Review fixes for #731: Hungarian stays a partial catalog

- The i18n audit requires completeness from Russian only again: hu.tsv lacks ~280 strings of the
  dialogs that landed since (Compare Documents, Math AutoCorrect, …), so it can't claim to be
  complete. The catalog test no longer asserts it holds every Russian/Spanish key.
- 43 Hungarian rows for tab and command labels that reached main since (charts, content controls,
  Developer tab, templates and the styles organizer, WordArt), which every_tab_and_command_is_translated
  requires.
- Docs say partial, with the entry count (1,989); localization-parity's header keeps its quote
  marker and the #505 note.

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

* Review fixes for #731: Hungarian rows for the Outlining tab

24 rows for Outline view's tab and commands, which landed on main meanwhile; 2,013 entries.

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

* Review fixes for #731: ROADMAP header keeps main's SmartArt note

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

* i18n(hu): complete the Hungarian catalog again

- hu.tsv: 374 new rows for the strings that reached main while #731 was
  in review (Compare Documents, Restrict Editing, Math AutoCorrect,
  charts, SmartArt, the Options sections, the print page and more).
  The catalog now holds every key of ru.tsv again: 2,397 entries.
- The completeness checks are back: the interface audit requires
  Hungarian alongside Russian, and the catalog test asserts hu.tsv holds
  every key of ru.tsv and es.tsv. The docs describe a complete catalog.
- Seven review rows follow the catalog's existing patterns: Text Pane
  (Szöveg panel, like the other panes), Design Mode (Tervezőmód, one
  compound), Picture and Date Picker Content Control (clearer compounds),
  Promote to Heading 1 / Demote to Body Text (style name after a colon,
  no case ending) and Reset Graphic (Ábra visszaállítása, shorter).

* Hungarian: translate interface strings added on main since this PR

Adds the 10 strings main gained with Polish proofing (spelling and grammar
messages, Do Not Check Spelling or Grammar, comment/browse buttons), so
hu.tsv again covers every key of the other catalogs (2,419 entries), and
drops the stale "Wildcards (regex)" row; updates the documented counts.

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>
Co-authored-by: Brandon Thomas <brandon@storyteller.ai>
2026-10-12 06:45:30 -04:00
pechnikov2026-star feaff0f22b
i18n: add French (fr) interface (#729)
* i18n: add French (fr) interface

A complete 1813-entry catalog with the same key set and order as
ru.tsv (the most complete reference), written from the meaning of the
English source. Registered in LANGUAGES after Turkish. The
locale-resolution tests that used fr-FR as the example of a language
without a catalog now assert the French mapping and use Italian,
which has no catalog, to keep testing the unsupported path.

* i18n: complete the French catalog and apply review fixes

Rebase onto main (1805 uk.tsv keys, up from 1812 rows at the original
PR): 357 new translations for the charts, Draw, content controls,
Caption/Index/TOC dialogs and formatting features that landed after
the PR was opened. Also applied the reviewer's five fixes: Bring
Forward → Avancer d'un niveau, Print Layout → Mode Page, Not used by
any command → N'est utilisé par aucune commande, Through → Au travers,
and consistent U+2019 apostrophes throughout.

* Review fixes for #729: attribution, French tests, language lists

- ATTRIBUTION row for fr.tsv, in the form the other catalogs use.
- French locale/saved-preference test and bundled-font coverage test (accents, œ, « », ’, and the
  no-break spaces in Inter).
- Tests that need a language without a catalog use a private-use tag (qaa-QM, qtz) instead of
  it-IT/de-DE, so they keep passing as real languages land.
- 11 French rows for commands that landed on main since (templates, styles organizer, Overtype,
  Move with Text), which every_tab_and_command_is_translated requires.
- fr in docs/control-protocol.md, README and localization-parity.

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

* Review fixes for #729: French rows for Outline view and SmartArt

34 rows for the Outlining and SmartArt Design tabs and their commands, which landed on main
meanwhile and every_tab_and_command_is_translated requires; 1,850 entries.

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

* French: translate interface strings added on main since this PR

Adds 174 French entries (fr.tsv now covers every key in the other
catalogs, 2,023 entries) and drops the stale "Wildcards (regex)" row;
updates the documented entry count.

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

* French: translate interface strings added on main since this PR

Adds the 10 strings main gained with Polish proofing (spelling and grammar
messages, Do Not Check Spelling or Grammar, comment/browse buttons): 2,033
entries; documented count updated.

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

* French: strings main added since the last merge (default app, numerals, KeyTips, Reading Mode)

---------

Co-authored-by: sanches <cfic34@ya.ru>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <brandon@storyteller.ai>
2026-10-12 06:38:53 -04:00
ripdog 241877d666
Add paginated Reading Mode with smooth column navigation (#740)
* M8: reflow reading mode into viewport-sized pages

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: navigate reading columns with wheel, keys and page controls

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: keep Outline in current view and add transient reading layout controls

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: replace reading ribbon and align navigation to columns

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: animate reading column turns and retain visible text through resize

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: name reading navigation Outline and complete its translations

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: consolidate Reading Mode progress notes

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: keep reading clicks from scrolling the selected column

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: reveal reading caret only when outside the viewport

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

* M8: hide floating formatting toolbar in Reading Mode

Co-Authored-By: ChatGPT (GPT-6) <noreply@openai.com>

---------

Co-authored-by: ChatGPT (GPT-6) <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:33:19 -04:00
zuzazzo 7cccdf0f38
KeyTips: Quick Access Toolbar badges, saved option and native Alt fix (#620) (#709)
* M8.1: Quick Access Toolbar KeyTips (#620)

* M8.1: Handle native Alt events for KeyTips (#620)

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:24:36 -04:00
Dmitrii Khlapov af622ac843
Layout › Paragraph: fields fit above the title and line up (#654) (#703)
* #659: one drop-down marker (the dropdown icon) on every ribbon button

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

* #658: menu buttons grey out while their command is disabled

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

* #653: large-button labels end above the group title row

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

* #654: Layout › Paragraph fields fit above the title and line up

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-12 06:16:15 -04:00
Dmitrii Khlapov 4a1acb6c3f
Ribbon: large-button labels end above the group titles (#653) (#699)
* #659: one drop-down marker (the dropdown icon) on every ribbon button

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

* #658: menu buttons grey out while their command is disabled

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

* #653: large-button labels end above the group title row

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-12 06:13:17 -04:00
Dmitrii Khlapov 3c8840556a
Menu buttons grey out while their command is disabled (#658) (#698)
* #659: one drop-down marker (the dropdown icon) on every ribbon button

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

* #658: menu buttons grey out while their command is disabled

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-12 06:09:16 -04:00
Dmitrii Khlapov c1e1c06297
#659: one drop-down marker (the dropdown icon) on every ribbon button (#697)
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-12 06:05:30 -04:00
RegalDragoon200 d4d28e01f4
Skip non-English runs in proofing instead of flagging them (#100) (#741)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 05:55:40 -04:00
Dmitrii Khlapov dd66d5171b
Dark theme: gallery previews no longer bright white (#663) (#706)
* #656: dialog buttons, Discord pill, eraser and search highlight use theme tokens

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

* #663: gallery previews dimmed in the dark theme; dark page under Switch Modes

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-12 05:42:58 -04:00
Dmitrii Khlapov d510d9a41a
#656: dialog buttons, Discord pill, eraser and search highlight use theme tokens (#705)
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-12 05:39:06 -04:00
osaym de8a3daf31
Fix paragraph alignment focus (#690)
* Fix paragraph alignment focus

Fixes #686

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Review fixes for #690: every ribbon command button returns focus to the document

Instead of four hard-coded alignment ids, big, small and split buttons and ribbon menu
items hand keyboard focus back to the canvas after running any engine command (ui.*
commands open dialogs and panes, which take focus themselves). The test also clicks Bold.
The ui-parity.md note moves into the change log.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 05:32:58 -04:00
ripdog 25048c8b9c
M7: ignore ellipses in sentence capitalization proofing (#742)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 05:29:57 -04:00
shirizhaki 1c188ba140
M1: preserve independent complex-script DOCX formatting (#366)
Keep inherited complex-script size, bold and italic independent from Latin
properties and retain explicit values during DOCX round trips. Preserve
ordinary formatting-command behavior and add regression coverage.
Resolve eight existing Clippy warnings without changing behavior so all
six required CI gates pass.

Co-authored-by: ChatGPT <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 04:55:44 -04:00
Valentin Klein ba9bbb48dd
Open Word documents with WordCraft by default (file associations + Options button) (#304)
* Open Word documents with WordCraft from the system (#295)

Register WordCraft for Word, RTF and ODT files on Windows and Linux without
taking over anyone's defaults, and add File > Options > General > "Make
WordCraft the default for Word documents..." where the system allows it.

- Windows MSI: a ProgId per type (.docx .docm .dotx .dotm .doc .dot .rtf
  .odt, plus .md and .txt as Open With candidates only) with the app icon
  and `"wordcraft.exe" "%1"`, OpenWithProgids, Applications\wordcraft.exe
  SupportedTypes, and Capabilities + RegisteredApplications so WordCraft
  shows in Settings > Default apps. New component with its own GUID.
- Linux: the desktop entry declares the macro-enabled, template and legacy
  Word types and text/rtf; AppStream lists the media types. deb, rpm,
  AppImage and both Flatpak manifests use this same file.
- macOS: Info.plist also lists legacy .doc.
- The Options button runs `ui.makeDefaultApp` through a new
  Services::make_default_app hook: Windows opens
  ms-settings:defaultapps on WordCraft's page; Linux and BSD run
  `xdg-mime default ai.storyteller.wordcraft.desktop <types>` (refused
  inside Flatpak or without an installed desktop entry); macOS shows the
  Finder Get Info hint; the web shows nothing. The status bar reports the
  outcome. Strings translated in every catalog.

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

* Review fixes for #304: keep Make default out of programmatic dispatch

ui.makeDefaultApp is refused when run programmatically (control channel, MCP, macros,
scripts); only a click on File > Options > General > Make WordCraft the default… reaches
the host's hook, so no agent can change the user's system default apps or open system
settings. Test: programmatic_calls_cannot_change_the_default_apps.

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

* Default-app strings in the newer catalogs; the button's test looks for a General-pane label

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 04:30:57 -04:00
DanielKnourek 199ac88a2e
i18n: add Czech (cs) interface translation (#387)
* i18n: add Czech (cs) interface translation

Translate the 1,246-entry interface catalog clean-room from the English source labels (cross-referenced with PdfCraft, VectorCraft, and PhotoCraft Czech catalogs) and register Czech (Čeština) for system locale detection and persisted selection. Add tests for Czech locale resolution, full catalog key parity, count-neutral word count formatting, and bundled UI font glyph coverage for Czech diacritics.

# Conflicts:
#	ROADMAP.md

* Czech: translate interface strings added on main since this PR

Adds 221 Czech entries so cs.tsv again has the full zh-hans key set
(2,021 entries) and drops the stale "Wildcards (regex)" row; updates the
documented entry count.

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>
Co-authored-by: Brandon Thomas <brandon@storyteller.ai>
2026-10-12 04:09:20 -04:00