Commit Graph
687 Commits
Author SHA1 Message Date
Dylan M. Taylor ab0eccd254 Merge pull request #4377 from storytold/sonar/newcode-s3776-a
Sonar: reduce cognitive complexity in four engine commands
2026-10-26 01:14:55 -04:00
aiongg 503a533e65 Merge branch 'w3' into w6
# Conflicts:
#	crates/engine/src/lib.rs
2026-10-26 03:40:48 +00: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 16f6145cd3 Merge branch 'w1' into w2 2026-10-26 03:38:38 +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 b9c074a543 W6: a window's input method joins and equation session stay with that window 2026-10-26 03:26:01 +00:00
aiongg e900513104 Merge branch 'w3' into w6
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/lib.rs
#	crates/engine/src/session.rs
#	crates/ui-egui/Cargo.toml
#	crates/ui-egui/src/lib.rs
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/ui-parity.md
2026-10-26 03:22:33 +00: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 645cbe52d4 Merge branch 'w1' into w2
# Conflicts:
#	ROADMAP.md
2026-10-26 03:04:40 +00:00
aiongg 4576b8e624 W1: a command that ends in another document counts as a state change for the input method 2026-10-26 03:04:24 +00:00
aiongg 5e7790ea85 W1: requests a command makes in another document keep their document id when the queue is full 2026-10-26 03:03:36 +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
Dylan M. Taylor 282ebedc85 Merge branch 'main' into sonar/newcode-s3776-a 2026-10-25 22:47:08 -04:00
aiongg 3c25061bab Merge remote-tracking branch 'upstream/main' into panes-trial 2026-10-26 02:44:26 +00:00
Dylan M. Taylor adf33b6ba7 Merge branch 'main' into sec/j 2026-10-25 22:01:43 -04:00
Dylan M. Taylor 4fd9075e99 Sonar: split flood fill, CSV separator, noise collapse and numbered backspace
Extract helpers with unchanged behaviour to bring these functions under the
cognitive-complexity limit (S3776):
- engine cmd/objects.rs clear_background: border_pixels, run_span, push_open_runs.
- engine cmd/tools.rs collapse_noise_matches: flatten_region (Kind is now module-level).
- engine cmd/mailings.rs parse_csv: csv_separator, push_csv_row.
- engine cmd/text.rs backspace_inner: remove_number.
2026-10-25 21:30:49 -04:00
Martin BallandClaude Opus 5.5 bcce02ab36 #3692: confined automation adds or removes fonts only when the font store is inside its write root
Finding 44: font.add stored the file in the user font folder and
font.remove deleted stored files directly, bypassing the automation
write root (#769). Both now check the user font folder against the
write policy in force before touching the database or the disk; with no
folder (headless) a font still lasts for the session only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 21:02:01 -04:00
Dylan M. Taylor e5cffe7641 Merge pull request #4233 from VoiceLessQ/fix/small-cleanups
Small fixes: MERGEFIELD in any case, 18 SonarCloud closures, one unused constructor
2026-10-25 16:45:39 -04:00
Dylan M. Taylor 5dd5e8b31b Merge pull request #4241 from storytold/codex/egui-037-wordcraft-20261023
Port WordCraft to egui 0.37 with current-main editing changes
2026-10-25 13:30:14 -04:00
Martin BallandClaude Opus 5.5 4095cc3413 Security: bounded file reads, Read Aloud and macOS signing temp file (#3680, #3666) (#3877)
* #3680: Read Aloud tidies in one linear pass and cuts space-free sentences

Finding 56. tidy() repeated whole-string replacements until nothing
changed; each pass removed one level of nested empty brackets, so 40,000
pairs took ~50 s in a debug build. It is now one pass that drops a closing
bracket's empty pair as it goes, checked against the old algorithm on
20,000 generated strings. Sentences with no space to split at are cut at
MAX_UTTERANCE (1,200) characters, and each sentence is sliced from a char
vector instead of skipping from the paragraph's start.

Fixes #3680

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

* #3692: Paste Special reads only a regular picture file, bounded

Finding 24. A copied path naming a device such as /dev/zero reports a
length of 0, so the size check passed and std::fs::read read forever.
The path and the opened handle must both be regular files, and at most
the picture limit + 1 bytes are read. A named pipe swapped in between the
check and the open can still block the open (no portable non-blocking
open without platform flags); noted in the code.

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

* #3692: macOS signing import decodes the certificate into a private temp folder

Finding 25. The .p12 bundle was written to a predictable name in the
shared temp folder, where a planted link could redirect it. It now goes
into a mktemp -d folder under the same temp root, removed on exit. The
keychain is unchanged.

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

* #3666: engine file reads open once and check the handle; a FIFO is refused without blocking

read_file_capped checked the path's metadata and then read the path
again, so a file swapped or grown after the check was read whole;
read_file_head opened the path with no type check, so saving to a FIFO
.xml path (the Word 2003 sniff) blocked until a writer appeared. Both
now go through open_regular_file (path checked before opening, handle
checked after, opened once) and a bounded read; read_regular_file uses
the same pieces. Tests: both helpers refuse a FIFO without blocking
and a folder; read_file_capped refuses content over the cap.

Fixes #3666

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

* #3692: Paste Special reads picture files through the engine's bounded read

Ultrareview finding 9: paste_picture kept a third copy of the regular-file
bounded read; it now calls wordcraft_engine::io::read_regular_file (public,
with a wasm stub).

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

* #3666: open a checked file non-blocking so a swap to a named pipe can't hang

CodeRabbit: a path replaced by a FIFO between the regular-file check and
File::open blocked in open, before the handle check could refuse it. On Unix the
open now uses O_NONBLOCK (no effect on regular files; libc is already in the
lockfile) and the handle check refuses the pipe. The FIFO tests' cleanup writers
open non-blocking too, so a regression fails the test instead of hanging it.

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

* #3666: review — Paste Special refuses a picture file whose handle reports more than the cap before reading it

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

* #3692: review — macOS signing keychain lives in the private mktemp folder too; removed if the import fails

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

* #3666: review — libc comes from the workspace dependencies

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

* #3680: review — Read Aloud logs a warning when its sentence cap leaves text unread

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

* #3692: review — engine speech timing test gets a margin a busy CI machine can't break

tidy_is_linear_on_nested_brackets: 2 s -> 10 s. The one-pass tidy takes ~13 ms on a loaded
machine; tidy_by_replacing (the old tidy, kept in the tests) took 293 s on the same input.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 12:32:19 -04:00
skylar taylor-barrick ea541fe66d Merge current WordCraft main while preserving egui 0.37 migration 2026-10-25 17:30:11 +01:00
skylar taylor-barrick fe9f6dbcc9 M0: reconcile current-main dialogs and canvas changes with egui 0.37 2026-10-25 17:03:15 +01:00
ea5780d2ab Gap 9: open AES-encrypted Word files (Standard encryption) (#2628)
* Gap 9: open AES-encrypted Word files (Standard encryption)

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

* Gap 9: restore progress-doc rows lost in the main merge

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

* Gap 9: Standard package layout test built from the spec

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:48:13 -04:00
skylar taylor-barrick 42477bd806 M0: reconcile current main and classify double-space rewrites for egui 0.37 2026-10-25 16:47:30 +01:00
Max MurphyandClaude Opus 5.5 49731f3faa #2982: File ▸ Info Custom Document Properties dialog (#2997)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:44:31 -04:00
MexandClaude Opus 5.5 40a7fe6be2 Make three-column header/footer presets editable tables (#2197) (#2266)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:34:23 -04:00
NetterSilverandClaude Opus 5.5 d5f23907dc Bound total LCS work per review.compare (#4006)
Fixes #3632

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:15:42 -04:00
skylar taylor-barrick f7c49cb0f8 egui-037: reconcile main and protect IME undo and wrapped layout 2026-10-25 16:15:05 +01:00
0cb2af4f4b AutoFormat As You Type: optional "Add a period with double-space", and an AutoCorrect Options button in Options › Proofing (#2848) (#3318)
* AutoFormat As You Type: optional period with double-space, off by default (#2848)

* Test the double-space option through the AutoCorrect dialog (#2848)

* File > Options > Proofing: an AutoCorrect Options button opens the dialog (#476)

* #2848: report doubleSpacePeriod in tools.autocorrect's params doc and result

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-25 11:11:20 -04:00
Dmitrii KhlapovandDmitrii Khlapov 50a1c34647 #1475: Scale all style font sizes at once (#2620)
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
2026-10-25 11:06:42 -04:00
NetterSilverandClaude Opus 5.5 b638caa2d2 Keep a document's own styles and defaults when applying a style set (#4013)
Fixes #3650

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 11:01:31 -04:00
Martin BallandClaude Opus 5.5 85db9cfef5 #4177: regex Replace expands capture groups (#4201)
* With Regular expressions on, Replace with reads $1…$n, ${n}, ${name}, $name,
$0/${0}, $$, \1…\9, \n (paragraph mark, splits the paragraph through the ^p
path), \t and \\, alongside the ^ codes. Named groups resolve through
meta::Regex::group_info(); missing, unknown and out-of-range groups expand to
nothing. Plain and wildcard Replace are unchanged.

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

* #4177: review — special:false keeps regex group references

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

* #4177: review — \$ and \^ in regex Replace keep the character as typed

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-25 10:53:13 -04:00
skylar taylor-barrick 5b46f9ba4d M-egui037: fix fontless tests and document migration behavior 2026-10-25 15:24:23 +01:00
NetterSilverandClaude Haiku 5.5 77200f9c13 Indent a whole selected paragraph on Tab instead of replacing it (#4291)
Fixes #4285

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-25 10:04:21 -04:00
skylartaylor 5d428e408f M-egui037: reconcile upstream and document migration review fixes 2026-10-25 06:42:20 +01:00
aiongg 400bd131d3 Merge PR #4224: Fields: \* Upper, \* Lower, \* Caps and \* FirstCap change the result, and CardText is lowercase
# Conflicts:
#	crates/engine/src/cmd/references.rs
#	crates/engine/src/cmd/table_formula.rs
#	crates/layout/src/fields.rs
2026-10-25 04:54:09 +00:00
VoiceLessQ f3961d74d9 Mail merge: an IF is a merge rule only when it tests a MERGEFIELD
Preview Results and Finish & Merge took any IF whose code held the word
MERGEFIELD anywhere, and with the type now matched in any case, a quoted
value counted too: IF { PAGE } = "mergefield" "yes" "no" was evaluated
as a rule on an empty field and showed "no". Both guards now ask what
condition() already reads: the first nested field, through
mergefield_name. An IF on other fields keeps its result.
2026-10-25 02:37:43 -02:00
aiongg ba3e3d9e7c Convert to Text: paragraph marks drop a cell's section break too
The tab and comma separators already cleared it (#4155).
2026-10-25 03:51:11 +00:00
aiongg c2d2251328 Fields: one unquoted word sets a summary property
SUBJECT Draft sets the subject to Draft, as the field-argument rules
allow a value without quotes when it has no white space (#4217). A
switch alone, as in TITLE \* Upper, still sets nothing.
2026-10-25 03:51:09 +00:00
aiongg 8c035fbb2c Fields: \* ArabicDash formats any number field
It is a general format switch, so NUMPAGES, PAGEREF, SEQ and formulas
read it as PAGE does (#4226).
2026-10-25 03:51:09 +00:00
VoiceLessQ 944c67ba89 Mail merge: MERGEFIELD in any case is a merge field, MERGEFIELDX is not
`mergefield_name` matched with `strip_prefix("MERGEFIELD")`. A field typed as `mergefield City` was therefore no merge field at all: Check for Errors skipped it, and Preview Results and Finish & Merge left it alone. A code such as `MERGEFIELDX a` went the other way and was read as a merge field named `X`.

Field-type names ignore case (ECMA-376 Part 1, 17.16.1: "The field-type names DATE, Date, dAtE, and date are equivalent"). The other keywords in this file already go through the upper-cased `keyword()`. Now the type ends at the first space or quote and is compared ignoring case, which is the rule the shared HYPERLINK parser in #4222 follows. The two IF checks for a nested MERGEFIELD ignore case as well, so `IF { mergefield X } = ...` merges like its upper-case form.

Old and new compared on 5,940 generated codes: 2,760 give the same name, 960 are case variants that are now found, and 2,220 start with a longer word such as `MERGEFIELDX` that no longer counts as MERGEFIELD.

Test: merge_field_types_ignore_case.
2026-10-25 01:21:48 -02:00
dotCooCoo 52c88567b8 Fields: a count past its number format's range keeps its digits
NUMWORDS, NUMCHARS and REVNUM wrote a count past what the field's \*
number format covers as the format's last value, so a revision number
of 1,000,000 under \* ROMAN showed 50 M's. Such a count now keeps its
digits, as a table formula result does.
2026-10-24 19:52:32 -07:00
aiongg 36d7650d3e Convert to Text: drop the unused VMerge import 2026-10-25 02:44:24 +00:00
dotCooCoo d9d61ee8da Fields: several capitalization switches apply in the order they appear
A field with \* Lower \* Caps applied only \* Lower, so a title of
WEEKLY REPORT showed as weekly report. Every capitalization switch in a
field code now applies in turn, and the example shows Weekly Report.
2026-10-24 19:39:35 -07:00
dotCooCoo 21d96baf98 Merge branch 'feat/document-information-fields' into fix/field-text-format-switches 2026-10-24 19:37:41 -07:00
aiongg 8432e5fbb4 Read Mode catalog: Page Color is live
#4182 was written before view.readPageColor (#4172) landed, so the
progress log listed Page Color as missing. The catalog test checks it
is live.
2026-10-25 02:35:37 +00:00
aiongg 0ce539ca5e Convert to Text cuts the table with Table::split_off
A row content control that the cut crosses reopened below the
converted rows with its w:id, so the saved file had two controls with
the same id. Table::split_off (#4162) clears the id and ends the
vertical merges the same way, so Convert to Text and Split Table
follow one rule. Rows without cells leave an empty paragraph.
2026-10-25 02:35:37 +00:00
aiongg 6f6ff64af1 Merge PR #4205: Track Changes: Accept and Reject can move to the next change or stop tracking
# Conflicts:
#	docs/ui-parity.md
2026-10-25 02:23:07 +00:00
aiongg bc4a69b17d Merge PR #4182: Parity catalog: the checklist counts Read Mode's Column Width, Page Color and Layout
# Conflicts:
#	ROADMAP.md
#	docs/ui-parity.md
2026-10-25 02:23:02 +00:00