Commit Graph
89 Commits
Author SHA1 Message Date
FredApps 0655e651fb Merge upstream control delivery changes 2026-11-08 17:35:06 +01:00
FredApps be75ee90e3 Merge upstream main and reconcile control documentation 2026-11-08 17:22:59 +01:00
FredApps 480511eaa5 Merge upstream main into control delivery changes 2026-11-08 17:15:38 +01:00
vangel76andClaude Sonnet 5.5 1c7c4e66e0 Merge upstream/main into control-mcp-delivery-1326-1331
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 11:38:09 +01:00
vangel76andClaude Sonnet 5.5 875a62043a Merge upstream/main into feat/322-view-windows
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 11:37:52 +01:00
Martin Ballandmatstrange ef35d79cb8 Control channel: a command that discards unsaved work is refused, not carried out (#3284)
Lands #3284.

Co-Authored-By: matstrange <54028700+matstrange@users.noreply.github.com>
2026-11-06 11:44:29 +01:00
vangel76andClaude Sonnet 5.5 4e334166e5 Merge upstream/main into control-mcp-delivery-1326-1331
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 01:10:42 +01:00
vangel76andClaude Sonnet 5.5 4ac7292d62 Merge upstream/main into feat/recent-remove-2716
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 01:09:58 +01:00
8c57b0775c Status bar: the live count shows words, characters, or characters without spaces (#3187)
Lands #3187.

Co-Authored-By: vangel76 <271991477+vangel76@users.noreply.github.com>
Co-Authored-By: SlavenDj <53652906+SlavenDj@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
2026-11-06 00:27:28 +01:00
28925fac8c Linux: a setting chooses the display server (Wayland / X11) (#3189)
Lands #3189.

Co-Authored-By: Yasas-Sri <164534752+Yasas-Sri@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: vangel76 <271991477+vangel76@users.noreply.github.com>
2026-11-06 00:04:18 +01:00
vangel76andClaude Sonnet 5.5 401e7c9169 Merge upstream/main into feat/322-view-windows
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 04:13:02 +01:00
vangel76andClaude Sonnet 5.5 951b255b80 Merge upstream/main into control-mcp-delivery-1326-1331
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 03:26:18 +01:00
vangel76andClaude Sonnet 5.5 d5495ea4f8 Merge upstream/main into feat/recent-remove-2716
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 00:12:16 +01:00
LQRDandClaude Opus 5.5 604ac6ddb2 #641: print N-up sheets and folded booklets (#3916)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:29:12 +01:00
Martin BallandClaude Sonnet 5.5 c45945a2ea CP4.3: Options > Language: Your languages with proofing status, Add a language picker, Set as default
The Dictionaries folder moves here from Proofing with the Dictionary files list (#1063) kept. Set as
default sets only the saved default proofing language (the new pure review.language.preferred command), and
proof.packs returns the languages rows.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCYmv6UJmY2QcuhfXco
2026-11-03 23:59:42 +00:00
1ff68d64e3 i18n: Arabic interface with mirrored RTL shell (+ parity docs) (#5370)
* Arabic interface: mirrored right-to-left window and Arabic UI fonts

Adds the Arabic (`ar`) interface language's code: its catalogs are craft-i18n's
`locales/ar`, so this changes no catalog.

- `ar` is registered in `i18n::LANGUAGES` and `Lang::rtl()` says it is written
  right to left; its translations are used as written (egui's text layout
  orders each line's bidi text itself). A ribbon location reads from the right
  with a leftwards mark.
- `rtl.rs`: the window is mirrored. Containers open in `rtl::root`; columns,
  grids, checkboxes, radio buttons, menus, rows, panels, the dialog tab strip
  and the ribbon's scrolling row follow the language's direction. Title bar,
  status bar, ribbon tabs and groups, File pages (including Print, with the
  settings on the right and a solid scrollbar gutter), dialogs, menus and the
  task panes (their docking edge swaps) are laid out from the right. egui's
  `Grid` panics in a right-aligned layout, so grids go through `rtl::grid`.
- Arabic UI font fallback: the craft-fonts Arabic face, else an installed
  Arabic font, loaded when the interface is Arabic.
- The "Auto (200%)" size label keeps its percent sign inside the isolated
  number.
- Tests: Arabic locale, saved preference and lookup order on fixture catalogs;
  an interface audit (skipped without the craft-i18n Arabic catalog) that lays
  the app out right to left at several widths, checks tab, group, pane, Print
  and Go To positions and that nothing panics.

The Arabic work builds on Abdelhaq El Amraoui's mirrored-interface PR (#737).

Co-Authored-By: Abdelhaq El Amraoui <abdelhaqelamraoui@gmail.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: pin craft-i18n at a commit with the Arabic catalog; review fixes

- craft-i18n.rev and the Flatpak manifest pin 19358491 (craft-i18n main), the
  first commit line that has locales/ar/wordcraft.tsv. The old pin had no
  Arabic catalog, so `ar` was registered but not embedded and two i18n tests
  (the_language_setting_is_a_ui_command_and_persists,
  the_languages_offered_are_the_embedded_ones_of_the_list) failed in CI.
- The Arabic font fallback is requested for any right-to-left interface
  (`Lang::rtl()`), not only after the language picker sets the flag, so an
  automatic or saved Arabic gets the installed Arabic face.
- The file browser, the update window and Reading Mode's toolbar run their
  bodies in `rtl::root`, so their far-side buttons and rows are mirrored.
- A group in a right-to-left ribbon row is measured from the right edge: the
  cursor's left edge is negative infinity there, so its width was NaN and the
  ribbon planner dropped every group, never compacting a narrow Arabic window.
  A narrow window now folds groups into drop-downs.
- The mirrored checkbox and radio marks are labelled by their text, so screen
  readers name them.
- Tests: group width in a right-to-left row; the Arabic interface audit checks
  Reading Mode's toolbar.

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

* Arabic interface: ask for the installed Arabic font separately from the CJK one

A previous commit made every right-to-left interface request the installed CJK
fallback font (`system_cjk`) so that the installed Arabic font would load. That
also made every Arabic launch read a large system CJK font file when no
craft-fonts input is embedded (the Flatpak build has none).

`install_ui_fonts` now passes a separate `system_arabic` flag (`Lang::rtl()`):
the installed Arabic font is read for it, and `system_cjk` is again set only
by a CJK interface or by CJK text on screen. `WordApp::fonts_system_arabic`
remembers what was installed, so a language change reinstalls the fonts.

Tests: the_installed_arabic_font_is_asked_for_by_arabic_alone (the Arabic flag
adds the installed font only when none is embedded, and the CJK request alone
adds no Arabic font). Checked a headless screenshot of the Arabic interface
without craft-fonts: the installed Arabic font draws the labels.

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

* Fix the AutoSave switch knob: on is at the right, mirrored in Arabic

The title bar's AutoSave knob was placed with `lead_x(rtl == on, ..)`, which
reverses main's mapping in both directions: left to right it drew the knob at
the left when the switch was on, and right to left at the right. main draws it
at the right when on and at the left when off, so the mirrored interface must
draw it at the left when on: `rtl != on`.

The position is now `autosave_knob_x(rtl, on, track)`, pinned by a test for all
four cases. A headless screenshot of the off switch shows the knob at the left
in English and at the right in Arabic.

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

* Arabic interface: file names and paths in right-to-left lines; kerning row order

Tester feedback on the Arabic interface:

- File > Open's Recent list, the built-in file browser and the title bar drew
  file names and paths raw, from the left edge. In an Arabic line the marks of
  a name ("(نهائي) 2.docx") and the folders of a path with Arabic parts were
  scrambled. Rows now start at the side reading starts from (`rtl::lead_x`),
  names go through `i18n::isolate` (a first-strong isolate, with a left-to-right
  mark before the extension so `2.docx` stays `2.docx`) and paths through
  `i18n::isolate_path` (a left-to-right isolate with a mark after every
  separator, so neighbouring Arabic folders do not swap). Other languages get
  the text untouched; saved and spoken text never carries the marks.
- Font dialog, Kerning row: the dialog's grid is drawn left to right inside a
  right-to-left window, so "Points and above" came after its number; in an
  Arabic interface it now comes first, so the line reads "14 نقطة فأكثر" from the
  right. (The grid's columns themselves still keep their left-to-right order.)

Tests: names_and_paths_are_isolated_in_a_right_to_left_interface.

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

* Arabic interface: mirror through craft_ui::direction and Style::right_to_left

The suite's craft-ui now has the direction helpers (`craft_ui::direction`) and
its egui fork a `Style::right_to_left` that mirrors egui's own chrome. Use them
instead of our parallel wrappers:

- `rtl::sync(ctx)` applies the interface direction every frame the language's
  changes (`direction::apply`): it sets the shared direction state and
  `Style::right_to_left` on every theme, which draws check boxes and radio
  buttons with the mark at the reading start, mirrors submenus, scroll bars,
  title bars and the combo boxes' arrows (the Print page's choice lists, the
  font list) and opens combo menus from the right.
- `rtl::checkbox`, `radio_value`, `radio` and `indeterminate_checkbox` are
  gone: about 200 call sites use plain `ui.checkbox`, `ui.radio_value`, ... and
  egui does the mirroring (and names the control by its text, as a plain widget).
- `lead_x`, `lead_center`, `lead_top`, `start_panel` and `end_panel` delegate to
  `craft_ui::direction`. `root`, `flows`, `island`, `grid`, `menu`, `vertical`,
  `far_side` and the other layout helpers stay: the shared crate has no
  equivalent that fits them.

Visual changes: the combo boxes' drop-down arrows and lists are mirrored in
Arabic; nothing changes in left-to-right languages (checked headless
screenshots of the English main window, Font dialog and Print page).

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

* Recent files and the file browser: full path on hover, long names keep their start

Review feedback:

- Each row of File > Open's Recent list shows the document's full path as its
  tooltip (the path line under the name can be longer than the row).
- A long name in the built-in file browser is laid out in one row, with an
  ellipsis at its end, from the side reading starts from, instead of being
  clipped at the row's edge: in a right-to-left interface the old text anchored
  at the right edge cut the end of an Arabic name and the start of a Latin one.
  The whole name is the row's tooltip when it was shortened.

Checked headless screenshots of the file browser with a long English and a long
Arabic name.

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

* Font combos in a right-to-left row: the arrow joins its field on the left

The ribbon's font name and size boxes are drawn from a field and a separate
arrow box that share one outline: the field is square and the arrow's box is
rounded on the side where the arrow goes, painted a border width under the
field. That assumed the arrow is right of the field. In a right-to-left row
(the Arabic ribbon) the arrow comes after the field on its left, so the field
was square on the wrong side and the arrow box rounded on the side facing the
field: two boxes with a gap-like seam, the arrow looking outside the frame.

`arrow_box_shape(rtl, ..)` mirrors the radii and the underlap, and the field's
square corners are chosen by the row's direction (the nw/sw pair in right to
left). Left-to-right rows are drawn exactly as before (English before/after
crops are identical).

Test: the_arrow_box_is_rounded_away_from_its_field.

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

* Pin craft-i18n 4612850 (merged Arabic WordCraft rows, craft-i18n#76)

The pin and the Flatpak manifest commit move from 1935849 to 4612850, which is on
craft-i18n main and adds the 70 Arabic rows this branch relies on.

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

* Pin craft-i18n cac2cf0 (Arabic number agreement and status-bar rows)

Moves the pin and the Flatpak manifest commit from 4612850 to the current craft-i18n
main, which includes craft-i18n#95 (48bed03) and #81 (ef58ff3).

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

* Arabic: isolate paths shown beside labels; mirror the Print page zoom

File > Info shows Location as its own left-to-right path label (cut short with the full path on hover, not wrapped), and the open-failure, Exported and dictionary-file messages isolate their paths. The Print preview zoom puts minus at the slider's left end and plus at its right in Arabic, as the status bar does.

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

* Arabic: mirror the label/field rows of the Font, Info, Paragraph, Page Setup, Insert Table and Options forms

rtl::Table lays a form out as an egui Grid in a left-to-right interface (same id, columns and spacing, so the output is unchanged) and, where the interface is mirrored, with each row's cells running from the right, every column as wide as its widest cell. File > Info puts Properties at the right and Statistics after it, and the Font dialog's kerning row reads 14 points and above.

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

* docs: record Arabic mirrored interface landing (#1195)

Update the language counts, Arabic parity row, gap #11, and UI/ROADMAP
status so they match the craft-i18n catalog and mirrored shell already
on this branch.

* Fix Organizer Copy arrow in RTL and refresh roadmap status.

Point the Copy glyph at the Document column when the shell is mirrored,
and bump docs/roadmap.md status/revision history for Arabic UI (#1195).

* fix(ui): keep pane dock left/right physical in RTL

ui.paneDock and view.stylesPaneDock now store and report physical window sides; only unset defaults still open on the reading-start edge. Also wrap the language-packs grid for RTL, document the contract, and load a system Arabic face for Arabic names in LTR UIs.

* docs: clarify mirrored default pane edges in RTL

Start-default panes open on the physical right in Arabic; end-default
panes open on the physical left — not every never-docked pane on the right.

* refactor(ui): one PaneState for a saved pane place

The four saved-dock arms built the same PaneState; only the place and
whether it was set explicitly differ.

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

* style(ui): rustfmt the panes re-exports

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

---------

Co-authored-by: The Legend Of MTS Dev <tlo.mts.tsh@gmail.com>
Co-authored-by: Abdelhaq El Amraoui <abdelhaqelamraoui@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: email <email@email.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-03 15:00:45 +01:00
vangel76andClaude Sonnet 5.5 45cfc55116 Merge upstream/main
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 23:54:30 +01:00
Martin BallandClaude Opus 5.5 c1490c5ba9 CP4.3: review — a click from the control channel never turns on downloading; installs and refreshes run in the background in the app; parked documents proof again after a pack change
- Install, Show available languages and Refresh turn on the font store's downloading only on the
  person's own click (input_from_control, as in #959); a faked click says why instead.
- proof.installPack and proof.packs {refresh} run on the engine's thread in the app ("started"),
  with progress, results and errors in proof.packs; the CLI and headless MCP stay synchronous.
- A session's layout is keyed on the dictionaries' generation, so parked documents proof again.
- proof.removePack refuses while that pack installs; pack commands that need a locale are left out
  of Search; options text names Refresh; licence tooltip says Source; errors go through tl!;
  the bar rescans at most once a second while typing; English names for every pack language and
  sr-latn; About has one Close button; xtask doc comment back on cmd_i18n_report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:04:00 +00:00
Martin BallandClaude Opus 5.5 e5d46bb242 CP4.3: Language packs: proof.packs, proof.installPack, proof.removePack; Options › Language list, missing-pack bar, About › Language data
- engine `packs`: the packs Backend (the font store on the desktop and CLI, a fixed list in tests
  and ui_shot), the pinned index, installs and removals through craft-font-store's
  `language-pack` kind, craft-proof reading the store's `language-packs/` folder at once.
  Commands open nothing and never turn downloading on (only an Install click in the app does);
  confined automation can't write the packs folder outside its write root.
- ui-egui `language_packs`: File › Options › Language › Language packs (name, size, licence,
  source, Install/Remove, progress, errors), the missing-pack bar (dismissible per document,
  never for a language without a pack), About › Language data (full licence texts).
- CP4.4: `cargo xtask language` (in `ci`): the default build embeds only en-* Language data.
- CP4.5: docs (help, MCP, control protocol, gaps #8, localization parity, roadmap).
- Path deps to Lane 4's worktrees while developing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 01:03:59 +00:00
vangel76andClaude Sonnet 5.5 1bbced51a4 Recent list: saved is null when no preferences were written
The desktop hook returns Ok(false) when preferences are switched off or there is
no settings folder; the commands report that like a host without a hook. Also
move add_saved out of works_without_document's doc comment.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 13:53:50 +01:00
vangel76andClaude Sonnet 5.5 9de2227af2 Report a failed preferences save from ui.recentRemove and ui.recentClear
The save_prefs hook now returns a Result; both commands add saved/saveError to
their result and the status line says when the write failed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 13:33:45 +01:00
vangel76andCodex 0e7dc8da53 fix(control): prevent ambiguous mutation replay (#2596)
Propagate accept-thread startup errors and remove the key file. Keep image exports from being retried and continue stdio after invalid UTF-8.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-31 22:12:18 +01:00
vangel76andClaude Sonnet 5.5 841dd538dc Merge upstream/main into feat/322-view-windows
Main now gives every document its own native window in one process, with Switch Windows and
New Window. Drop the one-process-per-window registry and peer channel and build Arrange All,
View Side by Side and Synchronous Scrolling on those windows: the drawn window sees the others
by window id, tiles and halves are placed through the windows' viewports, and the scrolling is
handed to the partner window in document points.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 19:46:57 +01:00
vangel76andClaude Sonnet 5.5 c85d454e09 Merge upstream/main into feat/recent-remove-2716
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 19:27:54 +01:00
aiongg 27068500dd Merge branch 'w2' into w3
# Conflicts:
#	crates/ui-egui/Cargo.toml
#	crates/ui-egui/src/panes.rs
2026-10-26 03:40:18 +00:00
aiongg 7d512a6905 Merge remote-tracking branch 'upstream/main' into w1
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	NOTICE
#	apps/wordcraft/Cargo.toml
#	crates/engine/src/lib.rs
#	crates/ui-egui/Cargo.toml
#	docs/control-protocol.md
#	docs/shared-pdf.md
2026-10-26 03:38:36 +00:00
aiongg 6dca584bbd Task panes: drop a pane outside or inside a docked pane to order a side (#4386)
* Task panes: a pane dropped over a docked pane's outer or inner third docks outside or inside it, and the order is kept (craft-libs#357)

* Pin craft-libs at b74f1b6 (pane order on an edge, craft-libs#357)

* Pin craft-libs at b926b5c (craft-libs main)
2026-10-25 23:29:51 -04:00
aiongg 15090b9d81 Merge pull request #3109 from aiongg/panes-trial
Task panes: draw them with craft_ui::panes; Styles docks left or right or floats
2026-10-25 23:13:49 -04:00
aiongg 5632755be4 Merge branch 'w2' into w3
# Conflicts:
#	Cargo.lock
#	ROADMAP.md
#	apps/wordcraft/src/main.rs
#	crates/ui-egui/Cargo.toml
#	crates/ui-egui/src/backstage.rs
#	crates/ui-egui/src/control.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/keys.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/panes.rs
#	crates/ui-egui/src/previews.rs
#	docs/ui-parity.md
2026-10-26 03:09:46 +00:00
aiongg 4029a4e6fc Merge remote-tracking branch 'upstream/main' into w1
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/lib.rs
#	crates/engine/src/session.rs
#	crates/mcp/src/tools.rs
#	crates/ui-egui/src/control.rs
#	crates/ui-egui/src/i18n/bg.tsv
#	crates/ui-egui/src/i18n/cs.tsv
#	crates/ui-egui/src/i18n/da.tsv
#	crates/ui-egui/src/i18n/de.tsv
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/et.tsv
#	crates/ui-egui/src/i18n/fr.tsv
#	crates/ui-egui/src/i18n/hr.tsv
#	crates/ui-egui/src/i18n/hu.tsv
#	crates/ui-egui/src/i18n/it.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/ko.tsv
#	crates/ui-egui/src/i18n/nl.tsv
#	crates/ui-egui/src/i18n/pl.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/ro.tsv
#	crates/ui-egui/src/i18n/ru.tsv
#	crates/ui-egui/src/i18n/sl.tsv
#	crates/ui-egui/src/i18n/sr-latn.tsv
#	crates/ui-egui/src/i18n/sr.tsv
#	crates/ui-egui/src/i18n/sv.tsv
#	crates/ui-egui/src/i18n/tr.tsv
#	crates/ui-egui/src/i18n/uk.tsv
#	crates/ui-egui/src/i18n/vi.tsv
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/i18n/zh-hant.tsv
#	crates/ui-egui/src/lib.rs
#	docs/gaps.md
#	docs/mcp.md
#	docs/parity-checklist.md
#	docs/ui-parity.md
2026-10-26 03:01:45 +00:00
aiongg f501f7cb5f Task panes: Dock Left, Dock Right and Float run ui.paneDock for every pane but Styles 2026-10-24 23:43:01 +00:00
vangel76andClaude Sonnet 5.5 d7c7889c82 Merge upstream/main into feat/recent-remove-2716
Interface catalogs now live in craft-i18n; the PR's tsv rows are dropped.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 14:18:34 +02:00
vangel76andClaude Sonnet 5.5 28b5cba00c Merge upstream/main into feat/322-view-windows
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 13:53:17 +02:00
Martin BallandClaude Opus 5.5 08da5c5433 #3699: MCP bridge sends the control key only to 127.0.0.1, where the app listens
Audit finding 9 (CWE-522). The bridge sent the reusable control key to any
loopback peer (127.0.0.0/8, ::1) and tried every address `localhost`
resolved to, while the app binds only 127.0.0.1. Another local user could
listen on ::1 or 127.0.0.2 and receive the key. Now `localhost` connects to
127.0.0.1 only, and the key goes only to a 127.0.0.1 peer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 20:19:49 +01:00
Gabriel Luís da Silva 05839461af #3734: ui.resize refuses sizes that aren't positive and clamps to the GPU's limit (#3920)
* #3734: ui.resize refuses sizes that aren't positive and clamps to the GPU's limit

The control channel forwarded any width/height to the viewport. Zero, negative and huge sizes now get an error or a size the window can have: the app's minimum and the largest texture the GPU draws (at most 16384 points). The reply carries the size asked for.

* #3734: refuse non-finite sizes, and let the GPU limit win over the minimum

Review follow-up: an infinite side (1e300 once read as f32) is refused rather than clamped, and a GPU limit below the app's minimum caps the size instead of being raised to it.
2026-10-23 12:03:33 -04:00
vangel76 c488558a1c Merge upstream/main into feat/recent-remove-2716 2026-10-22 19:10:34 +02:00
aiongg 3a6f3fbb17 W3b: docs: one window per document (control protocol, UI parity, progress log) 2026-10-22 16:54:37 +00:00
vangel76 65f36f9b8a Merge upstream/main into feat/322-view-windows 2026-10-22 18:53:05 +02:00
aiongg a2ca57ca3f W1: MCP, control channel and CLI address an open document by id
- MCP: execute, batch, type_text, select_text, get_text, inspect_document,
  render_page and save_document take an optional doc (an open document's
  id); the headless server runs them through Session::with_document and
  the bridge passes doc to the app. New list_documents tool; new_document
  replies with the new document's id. Tool descriptions and the server
  instructions say that file.new and file.open open another document.
- Control channel: engine.execute, document.inspect and ui.render take
  doc and work on that document while the window keeps the active one;
  file.close on an addressed document refuses unsaved changes unless
  forced; ui.* commands need the document on screen. ui.inspect reports
  document and documents. Unknown or malformed ids are errors.
- CLI run starts with one open document; help and docs describe how
  file.new, file.open and view.switchWindows work in a run.
- docs/mcp.md and docs/control-protocol.md describe document ids and doc.
2026-10-22 14:53:21 +00:00
aiongg 0b81f22d5b Merge PR #3258: Docs: control protocol's Methods table renders again
docs/control-protocol.md: one engine.execute row, main's current text (the template save command, focusRibbon) with the PR's \| escapes and its ui.contextMenu entry
2026-10-22 01:22:01 +00:00
5a6d2b6070 File › New: personal templates from a user templates folder (#2852) (#3133)
* #2852: personal templates in File › New, Save as Word Template

File › New lists the .dotx/.dotm files in the user templates folder under
Personal (a subfolder per category, search covers them); a click makes an
untitled document attached to the template. Save As › Save as Word Template
starts in that folder (<settings>/Templates, made on first use; File ›
Options › Advanced › File locations › User templates overrides it).
Engine: file.listTemplates (bounded, network folders refused, read root
applies), file.newFromTemplate sets the attached template, file.options
userTemplatesFolder, file.saveTemplate keeps a .dotm name. UI:
ui.saveAsTemplate; Save dialog requests carry a start folder.

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

* #2852: review — a personal template asks about unsaved changes; network templates folder refused before it's looked at; New lists the folder once per visit with Refresh; .dotx/.dotm labels alike

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: aiongg <aiongtaigi@gmail.com>
2026-10-21 20:18:50 -04:00
726652f088 Focus fills the screen; Full Screen View is a bindable command (#1678) (#1733)
* #1678: Focus fills the screen; Full Screen View is a bindable command

View › Focus goes full screen with the document on black and a slim bar
whose "⋯" drops the ribbon over the page. Full Screen View
(view.fullScreenView, no default key; bind one in Customize Keyboard)
shows the pages alone with the search box above them; the two turn each
other off. Full Screen (view.fullScreen, F11, #980) keeps its whole-window
behaviour. Escape leaves Focus or Full Screen View, then Full Screen, once
nothing nearer takes it; the system leaving full screen ends all three.
Ctrl+F1 collapses the ribbon (not on macOS). Immersive Reader no longer
turns Focus on. The page widget keeps a fixed id so it keeps focus when
the rulers hide.

Fixes #1678

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

* #1678: one Focus path after the rebase; pin the dropped ribbon staying down on a ribbon click

main's Focus (#1017) consumed Escape in WordApp::ui before
leave_full_screen, so Escape would leave Focus even when it should first
collapse a selection or close a popup. That handler is removed: Focus,
Full Screen View and Full Screen are left through leave_full_screen
only. main's focus_hides_the_ribbon_and_escape_brings_it_back still
pins the panes coming back. Full Screen View and Show the ribbon added to
the hr, ko and sv catalogs, which main gained since.

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

* #1678: Show the ribbon is a named button; a bound Ctrl+F1 wins; Esc in Read Mode leaves a dialog's Escape alone

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

* #1678: parity checklist regenerated after the rebase (Full Screen View counted)

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

* #1678: harness tests for the one Escape path and Ctrl+F1 through the app

In Focus with text selected on the page, the first Escape collapses the
selection and keeps Focus; the second leaves Focus (fails if the old
focus_mode Escape handler in WordApp::ui comes back). Ctrl+F1 sent as a
key event collapses the ribbon when unbound, and runs the user's command
when bound in the keymap, leaving the ribbon alone (not on macOS).

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

* #1678: review — a click on the dropped Focus ribbon gives the page the keyboard; only Ctrl+F1 yields to a binding

The ribbon dropped over the page in Focus lies over the canvas viewport and
in a Middle-order area, so refocus_after_chrome_click skipped clicks on it
and typing went nowhere until the page was clicked (which also put the
ribbon away). Clicks on the focus_ribbon layer now count as chrome. The
Focus test asserts the page has the keyboard after a ribbon click and that
typing reaches it with the ribbon still down.

dispatch checks the keymap ahead of an interface shortcut only for Ctrl+F1;
Alt+Q and Cmd+Option+R keep their place ahead of user bindings, as before
#1678 (test: a_bound_alt_q_still_opens_command_search).

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

* #1678: review — Ctrl+F1 (⌘⌥R on macOS) collapses or expands the ribbon; a shortcut of your own on Ctrl+F1 wins

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

* #1678: review — ui-parity's Word column gives Word for Mac's ribbon shortcut (⌘⌥R)

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

* #1678: review — Focus's dropped ribbon is a command, ui.focusRibbon; "⋯" and a click on the page run it

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

* #1678: review — the Focus UI test turns Focus on from the status bar's Focus button

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: aiongg <aiongtaigi@gmail.com>
2026-10-21 19:09:36 -04:00
Mikael Tollefsen 51ef9b9ebc Docs: control protocol's Methods table renders again
The engine.execute row listed the UI commands with unescaped "|" inside
code spans ("system"|"on"|"off", true|false, ...). GitHub-flavoured
Markdown splits table cells on every unescaped pipe, code spans
included, so the row came out as 32 cells in a 3-column table and was
cut off. A second, older engine.execute row duplicated it with a
shorter command list.

The two rows are now one: the current row, with ui.contextMenu (only in
the older row) added. Every "|" inside its code spans is escaped as
"\|", which GitHub shows as "|". Every row of the file's tables now has
its header's number of cells. Nothing else changes.
2026-10-20 11:31:07 +02:00
vangel76andClaude Sonnet 5.5 ab3ad718a0 feat(ui): remove documents from the recent list, one by one or all (#2716)
Hovering a row in File > Home/Open > Recent shows a Remove button at its
right end, and a Clear all button under the list empties it. The commands
behind them, ui.recentRemove and ui.recentClear, work the same for the
CLI, the control channel and MCP. On the desktop the new list is written
to the preferences at once, so a removal survives the app being killed
before a normal close.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 01:34:12 +02:00
vangel76andClaude Sonnet 5.5 ede933dcc2 Merge upstream/main into feat/322-view-windows
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 02:09:57 +02:00
c91c1793a3 #2108: File › Print scales pages to another paper size (#2699)
* #2108: File › Print scales pages to another paper size

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

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

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:48:17 -04:00
Antoine BoxhoandBrandon Thomas 0f5e945a69 #1945: Hide the Quick Access Toolbar and show it again (#2089)
The Quick Access Toolbar's menu ends with Hide Quick Access Toolbar, as Word's does. Show Quick Access Toolbar brings it back from the ribbon's right-click menu and from a check box on Customize Ribbon's Quick Access Toolbar page. The setting is kept between runs, and keytips skip the toolbar's digit badges while it is hidden. The UI command ui.quickAccessToolbar drives it from scripts and MCP. Regenerates docs/parity-checklist.md, which was behind the catalog. Adds my contributor entry.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 11:34:10 -04:00
ReesandBrandon Thomas ff39a5c357 fix(ui): deliver control input in inactive windows (#2420) (#2530)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-18 10:28:37 -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
vangel76andClaude Sonnet 5.5 a912aacf73 Merge upstream/main into feat/322-view-windows; translations for hr, ko, sv, vi; catalog 493/504
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 23:11:06 +02:00