mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-30 05:37:00 -06:00
# Conflicts: # crates/engine/src/lib.rs # docs/macros.md
This commit is contained in:
+33
-15
@@ -1,6 +1,6 @@
|
||||
# Architecture
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-23 · **Change:** minor (engine building blocks for multi-command actions) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-24 · **Change:** minor (engine building blocks for multi-command actions) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
|
||||
How GridCraft is built today. Rules for contributors are in [`AGENTS.md`](../AGENTS.md).
|
||||
|
||||
@@ -34,7 +34,9 @@ including tests, 2026-10-10.
|
||||
enabled, run, journal, undoable }`; ids follow Excel's ribbon (`home.bold`, `insert.chart`,
|
||||
`data.sortAscending`) plus primitives (`cell.set`, `selection.set`, `range.setValues`).
|
||||
`Session::execute` catches escaped panics and restores the workbook, its selection and its
|
||||
undo and redo history as they were before the command (never-crash guard).
|
||||
undo and redo history as they were before the command (never-crash guard); a group that was
|
||||
open before the command and that the command ended or rolled back stays ended and keeps a
|
||||
step from its start to the restored workbook, so Undo still returns to the state before it.
|
||||
2. **Edits** change the model through copy-on-write bands; undo keeps the previous snapshot.
|
||||
Undo retains at most 100 steps and trims older steps when its estimated retained cell storage
|
||||
exceeds 128 MiB. The newest step remains undoable even if that step alone exceeds the budget.
|
||||
@@ -59,24 +61,40 @@ Actions made of many commands (macros, a debugger that runs one step per call) u
|
||||
closes its own groups still makes one undo step for itself, covering its edits inside and outside
|
||||
the groups. A command that ends a group open before it leaves the group its step and makes one
|
||||
of its own for what it changes after the end; a group a command opens and leaves open starts
|
||||
where the command did. The history limit is applied when the outermost command finishes; until
|
||||
then the steps made inside it are bounded on their own.
|
||||
where the command did, but only when the command succeeds: a command that fails rolls back
|
||||
every group it opened, as `group_rollback` does. `Session::abort_groups(doc)`, and the command
|
||||
`automate.stopAction` on the active workbook, roll back the groups left open on a document (a
|
||||
debugger the person abandons, a caller that dropped its token), so Undo works there again. The
|
||||
command runs on its own: a step of a script or macro may not stop the action it is part of, and
|
||||
a recording leaves it out, so playing the recording back never stops the run. The
|
||||
history limit is applied when the outermost command finishes; until then the steps made inside
|
||||
it are bounded on their own.
|
||||
- **Recording buffer** (`record.rs`). `Session::start_recording` collects each successful
|
||||
top-level command with the document, sheet and selection it ran in, without secret parameters.
|
||||
Commands run by other commands are not recorded, and the buffer is independent of the journal
|
||||
Commands run by other commands are not recorded, nor is a menu-style call that only opened a
|
||||
dialog (the dialog's confirming call is the step; a run that changed the workbook before a step
|
||||
of it opened a dialog is recorded), and the buffer is independent of the journal
|
||||
(Automate › Record Actions still records through the journal).
|
||||
- **Document trust.** `DocState::trust` is `Local` for workbooks made in the session and
|
||||
`FromFile` for workbooks opened from a file, and for workbooks that received a paste from one
|
||||
that writes formulas or validation: Paste, Paste Special › All, All Except Borders, Formulas,
|
||||
Formulas and Number Formats or Validation, and any linked paste other than column widths or
|
||||
notes. Values, formats, column widths and notes carry nothing active. Active content in a
|
||||
`FromFile` workbook asks before it runs. This
|
||||
is provenance, which no decision changes; `DocState::scripts_trusted` is the separate
|
||||
per-session consent for stored `automate.*` scripts (`automate.trustScripts`).
|
||||
`FromFile` for workbooks opened from a file. `Trust` has no default: `DocState::new` takes it,
|
||||
so every way of making a document says where its content came from. It is also `FromFile` for
|
||||
workbooks that received a paste from one that writes formulas or validation: Paste, Paste
|
||||
Special › All, All Except Borders, Formulas, Formulas and Number Formats or Validation, and any
|
||||
linked paste other than column widths or notes. Values, formats, column widths and notes carry
|
||||
nothing active. Active content in a `FromFile` workbook asks before it runs. This is provenance,
|
||||
which no decision changes; `DocState::scripts_trusted` is the separate per-session consent for
|
||||
stored `automate.*` scripts (`automate.trustScripts`).
|
||||
- **Workbook data in hidden names** (`cmd/stash.rs`). An item is split over hidden
|
||||
workbook-scope names `_gc_<key>_0`, `_gc_<key>_1`, … of string literals within Excel's 255- and
|
||||
8,192-character limits, so it survives an xlsx round trip. The older single-name `_sc_<key>`
|
||||
items are read as well.
|
||||
8,192-character limits, so it survives an xlsx round trip. Characters XML can't carry (controls
|
||||
other than tab, line feed and carriage return, U+FFFE, U+FFFF) are stored as the noncharacter
|
||||
U+FDD0 and four hex digits, as is U+FDD0 itself, and read back as they were. `stash::items`
|
||||
and `stash::keys` list the items under a key prefix in one pass over the names, at most
|
||||
10,000 of them (`stash::MAX_ITEMS`) with a count of the rest, so a caller can say what it did
|
||||
not list. The older single-name `_sc_<key>` items are read as well.
|
||||
`formulas.defineName` and `formulas.deleteName` refuse a name the workbook holds such an item
|
||||
under (a hidden workbook-scope name of either shape; a visible one is the person's own), and
|
||||
`formulas.createFromSelection` skips such labels, unless `force: true` is passed.
|
||||
|
||||
## Agent control
|
||||
|
||||
@@ -103,6 +121,6 @@ rpm, tarball), FreeBSD, and web (WASM; WebGPU or WebGL2). Release workflows in
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-23 | minor | Engine building blocks for multi-command actions: undo groups, recording buffer, document trust, chunked hidden-name storage |
|
||||
| 2026-10-24 | minor | Engine building blocks for multi-command actions: undo groups, recording buffer, document trust, chunked hidden-name storage |
|
||||
| 2026-10-14 | minor | Document Undo's retained-cell-storage budget and latest-step guarantee |
|
||||
| 2026-10-10 | major | Created from the code on main: crates, layers, data flow, agent control, known gaps |
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
# Gaps
|
||||
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-20 · **Change:** minor (the Japanese catalog covers the dialogs, messages and menus) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-23 · **Change:** minor (§8: PivotTable Show Details) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
|
||||
Every known shortfall against Excel, one entry each, ranked by user impact (what blocks someone
|
||||
using GridCraft for real work first). This is the work list: pick from the top, check the open
|
||||
@@ -84,7 +84,8 @@ No alpha blockers: every core workflow passes the [alpha gate](roadmap.md#alpha-
|
||||
### 8. PivotTables: no slicers, calculated items, PivotCharts; unverified in Excel (F)
|
||||
- **Evidence:** `parity-checklist.md` missing `insert.slicer`, `insert.timeline`,
|
||||
`insert.pivotChart`, `table.insertSlicer`; calculated items and GETPIVOTDATA missing (calculated fields
|
||||
and values on rows done).
|
||||
and values on rows done). Show Details (double-click a value, subtotal or grand total cell) lists
|
||||
its source records on a new sheet; the "Enable show details" option isn't modelled yet.
|
||||
- **Impact:** pivots are the analyst's main tool.
|
||||
- **Estimate:** 20–30 h for beta (25–40 h full).
|
||||
|
||||
@@ -178,6 +179,7 @@ No alpha blockers: every core workflow passes the [alpha gate](roadmap.md#alpha-
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-23 | minor | §8: PivotTable Show Details: double-clicking a value cell lists its source records on a new sheet (#2364) |
|
||||
| 2026-10-20 | minor | §11: the Japanese catalog covers the dialogs, messages and menus — 943 keys (~43%), matching the pt-BR coverage; a test keeps the two catalogs in step |
|
||||
| 2026-10-17 | minor | §6: the five reports it tracked are closed and their PRs merged (#57, #133, #139, #140, #134; PRs #148, #155, #156, #157); the entry stays open for §15's oracle suite |
|
||||
| 2026-10-15 | minor | §13: Solver prepares reports before committing the solution, model and report sheets together; report refusal preserves the workbook and Undo/Redo (#1050) |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Localization parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-21 · **Change:** minor (the Japanese catalog covers the dialogs, messages and menus; Dutch interface language; Romanian interface catalog) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-23 · **Change:** minor (missing translations are listed by `cargo xtask i18n-report` and never fail a check) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
|
||||
Per-language status against Excel, which ships its UI in dozens of languages (Windows language
|
||||
packs cover 100+), with localized function names, argument separators, number and date formats,
|
||||
@@ -96,8 +96,9 @@ language (none so far) and of localized function names.
|
||||
## Infrastructure (do first)
|
||||
|
||||
1. Extend the catalog from the ribbon to every user-visible string (dialogs, menus, task panes,
|
||||
status and error messages, command labels, function descriptions), with a missing-key check
|
||||
in `cargo xtask ci`. Language switching and the system-language default already exist (#31).
|
||||
status and error messages, command labels, function descriptions). A string a catalog lacks
|
||||
shows in English and never fails a check: `cargo xtask i18n-report` lists the missing strings
|
||||
per language, and `cargo xtask ci` runs it first. Language switching and the system-language default already exist (#31).
|
||||
2. Locale-aware formulas: localized function-name tables and separators at the formula-bar
|
||||
boundary only (files keep en-US invariant names), locale number and date formats, list
|
||||
separators in CSV.
|
||||
@@ -109,6 +110,7 @@ language (none so far) and of localized function names.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-23 | minor | Missing translations are reported, never a failure: `cargo xtask i18n-report` prints, per language, the strings other catalogs translate and it lacks (plus Spanish function help rows keyed by English the function catalog no longer has) and always passes; `cargo xtask ci` runs it first. Coverage and per-language parity tests and tests of one language's exact wording are gone; UI tests take the expected text from the catalog. Duplicate-key, placeholder, context-prefix and line-shape checks stay |
|
||||
| 2026-10-21 | minor | Romanian interface (`ro`, Română): 970 labels covering every key of the other catalogs (`crates/ui-egui/src/i18n/ro.rs`), `ro-*` system locales, the View-tab switcher and `app.language.set`; context keys show no prefix (File › Options test). English formulas and formats; AI-assisted draft pending native-speaker review |
|
||||
| 2026-10-20 | minor | Japanese: furigana (`rPh` phonetic runs and `<phoneticPr>` in `xl/sharedStrings.xml`) is no longer deleted by an open + save; it is kept on the workbook and written back (a `<phoneticPr>` without runs is kept too, while duplicate texts with different readings keep only the first, reported on open). Display of the readings is still missing (`crates/xlsx/src/tests/phonetic_tests.rs`) |
|
||||
| 2026-10-20 | minor | Japanese catalog (`i18n/ja.rs`) covers every key the Brazilian Portuguese catalog translates: the 398-label shared core moved verbatim plus 545 dialog, message, Backstage and menu strings — 943 keys, ~12% → ~43%. A test parses `pt.rs`'s source, so the two catalogs can't drift apart again. Portuguese re-measured at 943 (was 923) |
|
||||
|
||||
+31
-15
@@ -40,16 +40,28 @@ no macro debugger, recorder or management commands in this version, and no macro
|
||||
`{"command": "cell.set", "params": {…}}` is accepted for a command step.
|
||||
- **Inputs**: `kind` (`cell` or `range`), `rows` and `cols` as `[min, max]` (0 for no maximum;
|
||||
rows exclude the header), `header`, `colTypes` (`number`, `text`, `date`, `bool`, `any`),
|
||||
`nonEmpty` and `defaultRef`. An input's name is letters, digits and `_`, starting with a letter,
|
||||
and is neither a token of its own (`Output`, `Row`, `Column`, `Name`) nor something that reads
|
||||
as a cell reference (`Q1`), so a step written with plain A1 text keeps meaning the cell. A run
|
||||
binds each input to the range it is given, its default, or (for the first input) the
|
||||
selection, and refuses with messages that name the cells: "Input column 2 (Amount) must hold
|
||||
numbers; C4 holds text."
|
||||
- **Limits**: 1,000 macros a workbook, 10,000 steps a macro, Repeat and If nested 4 deep,
|
||||
100,000 steps executed per run and 60 seconds a run, both shared by the footprint dry runs and
|
||||
the run itself (`timeLimit` to change the time; the web build has no clock, so there only the
|
||||
step limit applies).
|
||||
`nonEmpty` and `defaultRef`. These declare what a range must look like for the macro to work
|
||||
on it. An input's name is letters, digits and `_`, starting with a letter, and is neither a
|
||||
token of its own (`Output`, `Row`, `Column`, `Name`) nor something that reads as a cell
|
||||
reference (`Q1`), so a step written with plain A1 text keeps meaning the cell. The declaration
|
||||
is checked as a whole: neither `rows` nor `cols` may have a least above its most, a `cell` input
|
||||
has one row and one column (`[1, 1]`, or the default `[1, 0]`), no header and at most one column
|
||||
type, and no input lists more column types than it allows columns. A run binds each input
|
||||
to the range it is given, its default, or (for the first input) the selection, and refuses
|
||||
with messages that name the cells: "Input column 2 (Amount) must hold numbers; C4 holds text."
|
||||
- **Limits**: 1,000 macros a workbook, 10,000 steps a macro, Repeat and If nested 4 deep, and 64
|
||||
inputs a macro. Names (of macros and inputs) and command ids are at most 255 characters;
|
||||
descriptions, step notes, Stop messages and If values (as JSON) 4,096; references and tokens
|
||||
(`output.anchor`, `defaultRef`, a Repeat's `over`, an If's `cell`) 1,024; a shortcut 64. A
|
||||
macro lists at most 256 permissions, each a command id, and an input at most 16,384 column
|
||||
types. One-line fields hold no line breaks or other control characters, and a command id is
|
||||
letters, digits, `.` and `_`. A command step's `params` are bounded only by the size of the
|
||||
whole macro (4,194,304 characters of JSON). A macro read from a file that breaks any of these is
|
||||
left out with a warning; it is never changed to fit. When a macro runs, a Repeat whose range has
|
||||
more rows or columns than its `max` is refused, and a run executes at most 100,000 steps (each
|
||||
pass through a Repeat counts) and takes at most 60 seconds, both shared by the footprint dry
|
||||
runs and the run itself (`timeLimit` to change the time; the web build has no clock, so there
|
||||
only the step limit applies).
|
||||
|
||||
## Tokens
|
||||
|
||||
@@ -118,13 +130,17 @@ approval needed and the footprint, without changing anything.
|
||||
|
||||
Macros are saved in the workbook: as a field in GridCraft's JSON format, and in xlsx as hidden
|
||||
defined names (`_gc_macro_<n>_<k>`, the macro's JSON split into string literals within Excel's
|
||||
limits), which other spreadsheet applications keep but do not run.
|
||||
limits), which other spreadsheet applications keep but do not run. A visible name of that shape
|
||||
is someone's own name: opening a file leaves it alone, and saving stores the macros under indices
|
||||
it does not use.
|
||||
|
||||
Each macro carries its format version, `v` (1 in this version; a missing `v` reads as 1). When a
|
||||
file is opened, a macro that is damaged, over the limits or in a newer format (a `v` above 1) is
|
||||
left out with one warning, and the rest of the workbook and its other macros open. A newer
|
||||
macro is never read in part, so a save can't write it back with its newer fields missing; a
|
||||
macro that was left out is not in the saved file.
|
||||
file is opened, a macro in a newer format (a `v` above 1) is kept unread, with a warning: this
|
||||
version can't show or run it, and saving writes it back unchanged, so the newer
|
||||
version gets it back whole. It is never read in part. Kept macros count toward the 1,000-macro
|
||||
limit after the readable ones, and one too large for an xlsx file is left out. A macro that is
|
||||
damaged or over the limits is left out with one warning, and the rest of the workbook and its
|
||||
other macros open; a macro that was left out is not in the saved file.
|
||||
|
||||
## Automate scripts and VBA
|
||||
|
||||
|
||||
Reference in New Issue
Block a user