Commit Graph
456 Commits
Author SHA1 Message Date
prxnvt 0df540f166 Merge #2151 (44a2f4e2, with #465 at 673af7ec, #462 at 712bb766 and main at 530a8cc8) into #2144
# Conflicts:
#	docs/macros.md
2026-10-23 22:36:10 -04:00
prxnvt 44a2f4e2f1 Merge #465 (673af7ec, with #462 at 712bb766 and main at 530a8cc8) into #2151
# Conflicts:
#	docs/macros.md
2026-10-23 22:08:05 -04:00
prxnvt 00b63468e6 Engine: macro tokens resolve only where they mean a reference, and refuse instead of guessing
Six fixes from a review of the resolver, each with a regression test that
fails without it:

- A bare Row or Column under a general reference key (to, from, at, area,
  source, target, destination, location) stays text: Change Spelling's
  replacement word and a pivot field's area were being rewritten into the
  current row's A1 range. Row.col(2), {{Row}} and {"$ref": "Row"} still
  resolve there, and the bare word still resolves under cell and range keys.
- {{{{ in a string is a literal {{, so text that needs the braces can be
  written; an unknown token is still an error.
- Input.data on a range that is only a header row, and Name: of a table
  with no data rows, are refused instead of reading the header.
- below(0), below(-3) and right(0) are refused like resize(0, 1) is, instead
  of becoming 1.
- A defined name on a sheet whose name holds a dollar sign resolves: the
  dollar anchors are stripped from the reference part only.
- quote_sheet is the engine's one rule (gridcraft_core::quote_sheet), which
  quotes a sheet named like a cell reference, an R1C1 token or a boolean and
  leaves a period unquoted.

docs/macros.md says which keys take a bare token and how to write a literal
brace.
2026-10-23 22:02:45 -04:00
prxnvt 673af7ecdc Merge #462 (712bb766) into #465 2026-10-23 22:00:39 -04:00
prxnvt 4672b6da51 Model: an input name that reads as a cell reference is refused
A macro could declare an input called Q1, AB12 or Sum1, and a step written
with plain A1 text, as a recorded one is, would then resolve to the input's
range instead of the cell. check_limits refuses such names; the docs say so.
Regression test.
2026-10-23 21:48:53 -04:00
prxnvt 7ee9d77483 Docs: list every paste that carries a file's trust
The architecture note named formulas and validation only; it now lists the
Paste Special kinds and linked pastes that write formulas, and the kinds that
carry nothing.
2026-10-23 21:36:09 -04:00
prxnvt 378ce3a5a0 Docs: the macro page describes this version
The inputs paragraph described how a run binds inputs and the message it
shows, which the runner adds in a later pull request. It now says what the
declaration is for and that this version stores and checks it.
2026-10-23 21:28:05 -04:00
prxnvt cef58da39e Merge #462 (d7c3c183, with main at 530a8cc8) into #465 2026-10-23 21:25:35 -04:00
prxnvt a3b5f8e45c Engine: a command that panics leaves the undo history as it found it
The panic guard restored the workbook and selection but not the history, so
a nested edit made before the panic left a no-op undo step and the redo
history it had cleared stayed lost. The guard now truncates the steps made
during the command and puts the redo history back. Regression test, and the
architecture note says what the guard restores.
2026-10-23 20:08:40 -04:00
prxnvt 7e383f460a Docs: undo groups at a command's boundaries, and the bound on steps made inside a command 2026-10-23 16:36:52 -04:00
prxnvt 524826687c Docs: the architecture revision row carries the date the change lands; document trust beside script trust
The header and the revision row said 2026-10-11, older than the row above them. The document trust paragraph now says how DocState::trust (provenance) differs from DocState::scripts_trusted (per-session consent for stored scripts, #2178).
2026-10-23 16:17:57 -04:00
prxnvt 602d4450a2 Merge main into #462 2026-10-23 16:10:43 -04:00
aiongg a7608ada6d CI: one test binary per crate, nextest, line tables only (#2372)
* CI: dev builds keep line tables only

* CI: one integration-test binary per crate

* CI: xtask runs tests with nextest, doctests apart, --keep-going on clippy and wasm

cargo xtask test runs the workspace tests (--lib --bins --tests) with cargo-nextest when it is installed, else cargo test, then the doctests. cargo xtask ci uses the same two steps.

* CI: docs name cargo xtask test

* CI: agent guides name the moved fuzz test

* CI: tests added on main join their crate's test binary
2026-10-23 12:59:46 -04:00
Brandon Thomas fe2f9a7582 Merge PR #2357
# Conflicts:
#	docs/ui-parity.md
2026-10-23 10:11:33 -04:00
Brandon Thomas a09454e250 Merge PR #2315
# Conflicts:
#	docs/ui-parity.md
2026-10-23 10:11:33 -04:00
Brandon Thomas bcf55f0f00 Merge PR #2274
# Conflicts:
#	docs/ui-parity.md
2026-10-23 10:11:33 -04:00
Brandon Thomas 27a33f1ee0 Merge PR #2260 2026-10-23 10:11:11 -04:00
RedBearAKandClaude Opus 5.5 8eda577545 Page Up into frozen rows scrolls the rows below back to the top
With row 1 frozen, Page Up could land on A1, which is always on screen, while the scrolled rows
stayed a page down (row 10, Page Down, Page Up, Page Up ends on row 1 with rows 2-9 hidden). The
same held for Ctrl+Up into frozen rows and Ctrl+Left / Alt+Page Up into frozen columns.

Arrow and paging keys now record the cell they moved from (`GridState::reveal_from`). When such a
move goes from the scrolled rows (columns) into the frozen ones, the scrolled area goes back to
its top (left). Other reveals (clicks, Find, Go To, Name Box, Undo, the control channel, formula
pointing) leave it unset and keep the view where the user scrolled it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 03:20:18 -08:00
xc4pr 7c1ec1df7d Fill handle: test the Auto Fill Options button on a right-to-left sheet, merge the duplicate fill handle row (#1403) 2026-10-23 02:37:49 +02:00
xc4pr d19f656014 Fill handle: test the Auto Fill Options button's workbook-changed rule, report an undo error, document it (#1403) 2026-10-23 02:17:38 +02:00
Higgs32584andClaude Opus 5.5 b5b3969377 scripts: trust gate review fixes (#2178)
- automate.trustScripts: only a missing `trusted` defaults to true; a
  non-boolean value is an error and leaves the workbook untrusted.
- The refusal message points at Trust Scripts in View > Macros (Alt+F8)
  and at automate.trustScripts.
- Catalog row for automate.trustScripts; parity checklist regenerated.
- Script steps run inside an io::ScriptSandbox (thread-local) so
  read_file/write_file refuse whatever the parameter is called, and a
  step that raises OpenUrl is dropped and stops the script. The id/param
  deny list stays as the up-front refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 12:43:48 -04:00
Dominik StrebelandClaude Opus 5.5 74f29a743f docs: Ctrl+Shift+A (argument names) is no longer listed as missing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:18:45 +02:00
Dominik StrebelandClaude Opus 5.5 e6ffca60bb view: hidden outline symbols answer no clicks; parity rows updated
With headings hidden too, a level button sat across the empty column band
at the grid's top edge, so a click there still ran it. Outline hit testing
now stops when both bands are empty. The parity doc no longer lists Ctrl+8
as missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:09:29 +02:00
Dominik StrebelandClaude Opus 5.5 840ba5c3a5 view: Show Outline Symbols (Ctrl+8), read and written
A sheet can hide its outline's level buttons and brackets while keeping
the outline (Excel's Ctrl+8, saved as showOutlineSymbols="0"). It wasn't
modelled, so such sheets showed a wide outline band Excel doesn't.

- model: Sheet::show_outline_symbols (default on, also for older JSON).
- xlsx: read and written on the sheet view.
- engine: view.showOutlineSymbols {on?} (Ctrl+8), undoable.
- ui: no outline bands while it's off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:54:06 +02:00
Dominik StrebelandClaude Opus 5.5 843c9b8404 ui: a too-wide number in a repeat-fill format shows ####
A number too wide for its column is drawn as ####. With a repeat fill
(`*` in the format, as in the Accounting format) the fill step then
rebuilt the text from the formatted value, so it overflowed and, being
right-aligned, lost its leading digits: 2,509.00 CHF in a narrow column
was drawn as "509.00 CHF". The fill now leaves #### alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:00:06 +02:00
prxnvt 38ad2dba83 Merge main into #2144
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-22 02:37:04 -04:00
prxnvt 3eed81318f Merge main into #2151 2026-10-22 02:36:09 -04:00
prxnvt faff24f3aa Merge main into #465
# Conflicts:
#	crates/engine/src/io.rs
2026-10-22 02:36:09 -04:00
prxnvt 66f7993ba5 Merge main into #462
# Conflicts:
#	crates/engine/src/lib.rs
#	crates/engine/src/tests.rs
#	docs/architecture.md
2026-10-22 02:30:25 -04:00
prxnvt c0079aabe9 Docs: a failed macro run rolls back workbook changes; a file it already wrote stays
The intro said a macro run rolls everything back on an error, but a step that exports or prints to a path writes the file before a later step can fail, and the Running section says that file stays. The intro now limits the guarantee to workbook changes.
2026-10-22 02:26:32 -04:00
prxnvt f1a46a2b53 Docs: the macro policy summary lists the file commands that do run
The policy summary said file commands never run in a macro, but File >
Properties runs, and exports and printing run: without a path they only
produce bytes, and with one they need the permission and approval. The
summary now names what is denied and what runs, and the paragraph is
wrapped to the file's line length.
2026-10-22 02:26:32 -04:00
prxnvt 0ea5d3ee33 Engine: a Name: token reaches a defined name that holds periods
`Name:` read a name only up to the first period, so `Name:Sales.Q1` looked up `Sales` and
treated `Q1` as a method, and a workbook name called Sales.Q1 could not be used in a macro,
alone or as `Name:Sales.Q1.cell(1,1)`.

The name now runs through periods, and the longest defined name or table that exists and ends
at a period (or the end) is used; what follows is read as methods. So `Name:Data.row` is a
name called Data.row, and `Name:Sales.offset(1,0)` still moves Sales. When no name matches,
the error names the text before the first method, and a bad method after a dotted name is
still refused. Tests cover direct resolution, reference parameters, `$ref` and `{{...}}`,
with and without a chained method.
2026-10-22 02:26:32 -04:00
prxnvt 77150be455 Engine: col("Header") is refused on a range without a header row
col("...") always matched against the first row of the range, whatever
its header flag. On an input declared without a header row,
Input.col("Amount") silently picked the first column whose first data
cell read "Amount". After .data, the natural Input.data.col("Amount")
failed, because the first row was then a data row. The header row is
now carried through data, and col("...") is refused with a message when
there is none (an input without a header, a Name: base, or after any
other method).
2026-10-22 02:26:32 -04:00
prxnvt 7d31c5a4ed Engine: a macro in a newer format is dropped with a warning, not saved back as version 1
Opening a workbook accepted a macro whose format version `v` was above MACRO_VERSION. Serde
dropped the fields this build doesn't know, and the next save wrote the reduced macro back
with `v: 2`, so a newer build would read it as a complete version 2 macro.

A version above MACRO_VERSION is now refused by Macro::check_limits, and parse_macro checks
the raw `v` before reading the steps. Such a macro takes the existing per-macro path: it is
left out with the usual single warning (which now names a newer format), and the rest of the
workbook opens. Tests cover JSON and xlsx hidden names, with current and missing versions as
controls.
2026-10-22 02:26:32 -04:00
prxnvt b51d588cac Engine: macros can't open, hide or show windows
The policy denies window.* commands, but the View tab's window commands
are view.*: a macro could run view.newWindow, which adds a window that
the run's rollback doesn't remove, or view.hideWindow and
view.unhideWindow, which change the session's hidden windows.

The policy now denies those three. Arrange All changes nothing in the
engine and Switch Windows only lists windows, so both stay allowed.
2026-10-22 02:26:32 -04:00
prxnvt ac7c1ae639 Engine: a reference on a sheet named like a token stays a reference
is_token looked only at the leading identifier, so on a workbook with a
sheet called Output (or Row, Column, or the name of a declared input),
"Output!A1:B2" was read as the Output token, and the step failed with
"the macro has no output anchor" or "unexpected '!A1:B2'". This hit
reference keys, $ref and {{...}} alike, including references the
recorder writes for other sheets. A base followed by '!' is now a sheet
name, and the text resolves as a plain reference.
2026-10-22 02:26:32 -04:00
prxnvt ee7040a340 Docs: macro format and storage 2026-10-22 02:26:32 -04:00
prxnvt bf456c9ff8 Engine: a macro's footprint dry runs keep to the run's timeLimit
footprint always ran its dry run with the default 60 second limit, so
macro.run with timeLimit 5 could run for over two minutes (a dry run,
then another after a shift) and fail with "ran longer than 60 seconds".

footprint now takes the run's clock and limit. make_way starts the
run's clock before the dry runs, so the checks and the run share one
limit, and macro.check takes timeLimit too.
2026-10-22 02:26:32 -04:00
prxnvt 7a0f591712 Docs: macro tokens 2026-10-22 02:26:32 -04:00
prxnvt 4c6962a97c Engine: a partial macro footprint no longer clears later writes; the run checks each step
The footprint dry run stops at an approved file step and at Solver, but
make_way took a partial footprint with no conflicts as proof that the
run was safe, also after a shift. A macro that exported a CSV and then
set B1 ran under onConflict fail or ask and overwrote B1 without asking.

When the footprint is partial and the rule is not overwrite, the run's
machine now checks every step as it runs: a step that writes over
cells, sheets or objects that held data when the run started stops the
run and rolls it back, with a confirmation under ask and an error
otherwise. make_way now returns the machine for the run along with
whether it shifted.
2026-10-22 02:26:32 -04:00
prxnvt d305566e57 Docs: running and checking macros 2026-10-22 02:26:32 -04:00
aiongg d5cdd2ea2b Integration: track t15
# Conflicts:
#	contributors/people.toml
#	crates/engine/src/tests.rs
#	docs/file-format-parity.md
#	docs/localization-parity.md
2026-10-22 03:05:39 +00:00
aiongg 561382cc6d Integration: track t14
# Conflicts:
#	ROADMAP.md
#	contributors/people.toml
#	crates/formula/src/tests.rs
#	docs/file-format-parity.md
#	docs/localization-parity.md
#	docs/ui-parity.md
2026-10-22 03:05:30 +00:00
aiongg ca1cdd4229 Integration: track t13
# Conflicts:
#	ROADMAP.md
#	contributors/people.toml
#	crates/engine/src/cmd/data.rs
#	crates/xlsx/src/tests/mod.rs
#	docs/chart-parity.md
#	docs/file-format-parity.md
#	docs/function-parity.md
#	docs/gaps.md
#	docs/localization-parity.md
#	docs/target-app-parity.md
2026-10-22 03:05:18 +00:00
aiongg c7fd66d807 Integration: track t12
# Conflicts:
#	ROADMAP.md
#	crates/calc/src/tests.rs
#	crates/chart/src/tests.rs
#	crates/engine/src/tests.rs
#	crates/xlsx/src/tests/mod.rs
#	docs/chart-parity.md
2026-10-22 03:05:03 +00:00
aiongg 9350ab1def Integration: track t11
# Conflicts:
#	ROADMAP.md
#	apps/gridcraft-web/Cargo.toml
#	crates/ui-egui/src/i18n.rs
#	docs/control-protocol.md
#	docs/gaps.md
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-22 03:04:52 +00:00
aiongg 4c5c345c31 Integration: track t10
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/tests/sheet_tabs.rs
#	crates/xlsx/src/tests/roundtrip.rs
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-22 03:04:30 +00:00
aiongg 6dda6be2c6 Integration: track t09
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/src/i18n/pt.rs
#	docs/file-format-parity.md
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-22 03:04:21 +00:00
aiongg d3201e7cea Integration: track t08
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/tests.rs
#	docs/file-format-parity.md
#	docs/localization-parity.md
2026-10-22 03:03:55 +00:00
aiongg a680ac59f0 Integration: track t07
# Conflicts:
#	crates/calc/src/tests.rs
#	docs/function-parity.md
2026-10-22 03:03:23 +00:00