Commit Graph
152 Commits
Author SHA1 Message Date
prxnvt 06bbcb504a Engine: macro approvals are keyed on the macro's canonical JSON, not a 64-bit hash
Approvals were stored as (document, FNV-1a hash of the macro's JSON).
FNV-1a is not collision resistant, so a crafted workbook could hold a
harmless macro and a different one with the same hash, and approving
the first would let the second run without asking.

The key is now the macro's canonical JSON text itself (object keys
sorted), so two different macros never share an approval.
macros::hash is replaced by macros::fingerprint.
2026-10-22 02:26:32 -04:00
prxnvt 45e580ad91 Engine: macro.debug steps through a macro as one undo step
macro.debug runs a macro one step at a time. start checks the macro as
macro.run does (policy, approval, inputs, footprint and output rule)
and pauses before the first step; step runs one step; continue runs to
the next breakpoint; runTo runs to a chosen step path, stopping at
breakpoints on the way; stop ends the run and keeps its changes or
rolls them back; state reports where it is. Breakpoints are the steps'
own flags plus a list of paths given with any action (breakpointsOnly
makes the list replace the flags), and they stop in every pass of a
Repeat.

The run lives on the session between calls, inside an undo group that
spans them (group_begin and group_end), so a debugged run is one undo
step "Run Macro: <name>", as a normal run is. A failing step ends the
run and rolls it back; so does a Stop step that asks for a rollback.
While a macro is being debugged, edits of the workbooks the run touched
(its own, and any other a step changed) are refused at the top level
with "Finish or stop the macro first"; other workbooks stay editable,
and selecting and queries still work. Every answer gives the next
step's path, kind, command, parameters as they would run now (tokens
resolved), the Repeat pass, the parameters of the step that just ran,
the steps executed and the cells changed so far. Each action gets its
own time limit.

If a command panics while a step runs, the session's panic guard rolls
the debugged run back as well, so its undo group never stays open.
2026-10-22 02:26:32 -04:00
prxnvt b2740bdf33 Engine: macro recorder and macro.list, get, save, delete, rename, record
Commands: macro.list, macro.get, macro.save (a macro object or its
fields; replace defaults to true), macro.delete, macro.rename and
macro.record, beside macro.run, macro.check and macro.debug. Saving,
renaming and deleting are undoable. The catalog gains View › Macros ›
Record Macro (parity 275 / 291).

The recorder builds on the recording buffer of top-level commands, so
nested commands are never recorded twice and trimming the journal loses
nothing. When it stops, commands a macro may not run are left out and
listed; a macro run while recording is replaced by its steps when it
has no inputs, and an Automate script run by the script's steps;
sheet.activate and selection.set steps are added where the sheet or
selection changed between commands without one, and runs of them
collapse to the last. With relative references (the default) the
selection when recording started is the example input: references in
and near it become tokens (Input.col(2), Input.rows(2..),
Input.col(2).below, Input.row(4).right, Input.cell(r,c)), exact
references in formulas become {{...}}, and the input's width, header
and column types are inferred from the example. A recording replayed on
a longer block of data writes in the matching places.

A toggle such as Bold is recorded with the state it set ("on": true),
as Excel records Bold = True, so a replay sets it instead of flipping
it again.

Automate scripts are unchanged: automate.* keep their commands,
parameters, storage and results, and View › Macros still lists the
scripts and a preserved VBA project.
2026-10-22 02:26:32 -04:00
prxnvt 54c08645b9 Engine: macro.run and macro.check: input checks, footprint dry run, policy
macro.run runs a macro as one undo step ("Run Macro: <name>"); an error
at any step rolls everything back and names the step and its path (3,
2.1 inside a Repeat, 4.then.1 inside an If). It works in four parts:

- Policy (macro_policy). File, app, window, automate and macro commands
  and Undo and Redo never run in a macro. Reading or writing files
  (data.getData, data.fromTextCsv, insert.picture, Page Layout
  Background, or an export with a path) needs the command in the
  macro's permissions and the person's approval. A macro in a workbook
  opened from a file asks before it runs. Approval holds for the
  session until the macro's content changes; it is asked for with the
  new EngineError::Approve and given with approve: true. A step that
  would open a dialog or a web page fails instead.
- Inputs. Each declared input is bound (given, its default, or the
  selection for the first one), whole columns shrink to the used range,
  and the shape and column types are checked with messages that name
  the cells: "Input column 2 (Amount) must hold numbers; C4 holds text".
- Footprint. Unless the macro may overwrite, it first runs in dry-run
  mode on the real workbook inside an undo group that is rolled back,
  with the session's clipboard, journal, windows and the document's
  trust put back. CellStore::diff on every sheet, plus the cells
  commands wrote (DocState::touched), sheets and objects, gives what it
  would write outside its inputs; cells that only recalculated do not
  count. Writing over data, deleting a sheet or deleting an object is a
  conflict: ask (the new EngineError::Confirm, so programmatic runs fail
  unless they pass onConflict or overwrite), fail, overwrite, or shift
  the data down or right with Insert Cells and check again. A step that
  would fail, for example past the edge of the sheet, fails the run
  before anything changes. File steps and Solver stop the dry run early
  and are reported.
- Steps run on a machine with an explicit frame stack: Repeat over the
  rows or columns of a range with Row or Column bound, If on one cell
  with Excel's comparisons, and Stop, which keeps the changes or rolls
  them back. A run executes at most 100,000 steps within a time limit
  (60 s by default, timeLimit to change; the web build has no clock, so
  only the step limit applies there).

macro.check reports the bound inputs, the output anchor, the approval
needed, the footprint and the conflicts without changing anything;
nothing from an unapproved macro runs, not even as a dry run.
2026-10-22 02:26:32 -04:00
prxnvt a4b4872602 Model: macros as typed command lists, saved in the workbook
A macro is plain data in the model (model/src/macros.rs): a name, a
description, an optional shortcut, declared inputs (shape, header,
column types, non-empty, default reference), steps, an output rule
(anchor and what to do on a conflict) and the commands it may run that
read or write files. A step runs a command (id and params) or is one of
three bounded control steps: Repeat over the rows or columns of a range,
If on one cell's value, and Stop with a message. Every step carries
enabled, breakpoint and note flags. These are GridCraft macros, not VBA;
a VBA project in a file stays preserved and is never run.

Workbook::macros holds them. The JSON format keeps the field. In xlsx,
io::save_bytes writes each macro as one chunked hidden-name item,
_gc_macro_<n>, and io::open_bytes takes the items back out of the names,
so the names never linger in the open document.

Limits are checked whenever a macro is read from a file or a command:
at most 1,000 macros, 10,000 steps each, Repeat and If nested 4 deep,
names and notes of bounded length, and at most 4,194,304 characters of
JSON, so that saving a workbook never fails because of a macro; nesting
is checked before the steps are deserialized. What is over or damaged
is dropped with one warning, and clashing names get a suffix.

Automate scripts keep their own storage (_sc_scripts) and are neither
read nor changed by this.
2026-10-22 02:26:32 -04:00
prxnvt 2287f63a95 Engine: a group rolled back inside a command keeps the redo history
A command that changed the workbook cleared the redo history even when an open group owned
its step. When the group was then rolled back inside the same command (the debugger's Stop
with Undo Changes), the rollback put the redo history back and the command's bookkeeping cleared
it again. Now only a command that makes a step of its own clears the redo history; a group
clears it when it ends as a step, and a rollback restores it.
2026-10-22 02:00:54 -04:00
prxnvt eb3eaa052d Engine: a command keeps its group's name only for a group it ended itself
The record of the last group step (document, history length, epoch) outlived the Undo of that
step. A later command that opened and closed its own groups at the same history length, after
rolling one back, passed the epoch check (the record's epoch merely differed from the one the
command started with) and took the name of the nested edit it had made instead of its own.

The step must now come from a group ended during the command (an epoch past the command's
starting one), and a rollback drops a record of a step it truncated away.
2026-10-22 01:36:01 -04:00
aiongg 1794c389e5 Keep the cell draft in its own workbook; Switch Windows lists open workbooks
A cell being typed when File > New ran (macOS menu, control channel) stayed
open over the new workbook, and Enter wrote it there; the first workbook
stayed clean and nothing in the UI reached it.

- Every file.* and window command (window.activate, view.newWindow,
  view.hideWindow, view.unhideWindow, view.switchWindows with a doc) first
  commits the cell and text-box drafts as Enter would, or drops a draft its
  workbook refuses, still reporting why. Finder, argv and dropped opens go
  through file.open and get the same.
- The cell editor records its workbook's uid; the grid draws a draft only
  over that workbook, and a commit always goes into it.
- view.switchWindows takes a `doc` uid to bring that workbook forward and
  lists index, doc, title, dirty, active and hidden. Menu-style calls with
  no doc open the View tab's new Switch Windows dropdown.
- macOS: the Window menu lists the open workbooks (unsaved bullet, active
  check), and Quit closes the window so unsaved workbooks are asked about.
2026-10-22 05:01:47 +00: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 0118413c77 Merge PR #2080: HTML export: place pictures and charts at their anchors
crates/engine/src/tests.rs: kept both sides' new tests (journal tests from #1230, HTML export tests from the PR).
docs/file-format-parity.md: header Last updated 2026-10-21 with both change clauses; both revision-history rows, newest first.
2026-10-22 02:35:32 +00:00
aiongg 43cd35d4bd Merge PR #1263: Bound Undo history growth after bulk edits
crates/engine/src/lib.rs: kept both the journal caps (#1230) and the undo byte budget; separate constants and call sites.
crates/engine/src/cmd/edit.rs: undo pushes through push_history; the redo entry keeps the undone edit's selection (#1855 behaviour).
crates/engine/src/tests.rs: kept both tests (redo_selects_the_redone_cell and the two history-bound tests).
2026-10-22 02:35:17 +00:00
Higgs32584andClaude Opus 5.5 5392d95bf8 scripts: require workbook trust before running embedded scripts (#2178)
A workbook opened with GridCraft scripts (`_sc_scripts`) starts untrusted:
automate.runScript refuses them until the user trusts the workbook for the
session (Macros dialog > Trust Scripts, i.e. automate.trustScripts) or the
caller passes `trusted: true` for that one run. Workbooks without scripts,
and scripts written in the session, are unaffected.

Whatever the trust, a script whose steps reach outside the workbook
(file.*, link.*, or any `path` param: Get Data, From Text/CSV, Insert
Picture) is refused before any step runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:13:13 -04:00
prxnvt ab27d35386 Engine: a full undo history keeps one step per command that runs its own undo groups
When the history held 100 steps, group_end pushed its step and dropped the oldest one at once,
so execute's collapse compared against a length that no longer matched. A command that was one
group kept the group's step and added its own, losing two old steps. After test.editThenGroup,
the second Undo brought back the intermediate state after the outside edit.

The history limit now applies after the outermost command has collapsed its steps, and when a
group ends outside any command. A document with an open group is trimmed when the group ends.
2026-10-21 17:25:45 -04:00
prxnvt f4e05534a3 Engine: a command that runs its own undo groups makes one undo step for itself
execute treated any change in the group epoch as 'the group owns the step'. A command that edited outside its own group, or whose group rolled back before it edited, left that edit with no undo step or only part of it. Now only a group that was open before the command (or is still open after) owns the step; a command that opened and closed its own groups replaces their steps with one entry for the command.
2026-10-21 15:23:08 -04:00
prxnvt b7bce3bc09 Engine: document trust for workbooks opened from files
Active content such as macros must not run only because a workbook was
opened. DocState gets a trust state: Local for workbooks made in the
session (new workbooks and samples) and FromFile for anything opened
with file.open. Active content in a FromFile workbook asks before it
runs. A second window on a workbook shares its trust.

The clipboard carries the trust of its source document. Pasting
formulas, formats (conditional formats hold formulas) or validation
from a FromFile workbook into another workbook makes that workbook
FromFile too; pasting values, column widths or notes carries nothing
active and changes nothing. Sheet moves and copies stay inside one
workbook, so its trust is unchanged. document.inspect reports the trust.
2026-10-21 14:05:48 -04:00
prxnvt d4f1e61c99 Engine: a recording buffer of top-level commands, apart from the journal
A macro recorder needs more than a journal index: the journal is
trimmed past 10,000 entries, it also holds the commands that other
commands run (so playback would run them twice), and it keeps no
selection, which relative references need.

Session now tracks how deeply execute calls are nested. While recording,
a buffer (record.rs) keeps each successful, journaled top-level call with
the document uid, the active sheet (index and name) and the selection it
ran in, then its id and parameters without secrets, as the journal
stores them. Queries, failed commands and the command that starts
recording are not kept. The buffer holds up to 100,000 steps and counts
any it drops. Session::start_recording, stop_recording, is_recording and
depth are the interface.

Automate › Record Actions keeps recording through the journal as before.
2026-10-21 14:05:41 -04:00
prxnvt acfd38f309 Engine: undo groups make several commands one undo step
Session::grouped(label, f) runs f as one undo step on the active
document. On success the group leaves exactly one undo entry holding the
workbook from before the group; on error it restores the workbook,
selection, undo and redo stacks as they were and returns the error.
group_begin, group_end and group_rollback do the same across separate
calls, for an action that runs one step per call.

While a group is open on a document, undoable commands on it add no
undo steps of their own, so a long group neither grows the history nor
pushes older entries past the undo limit, and Undo and Redo are
disabled there. Groups nest: the outermost one makes the step, and a
failing inner group rolls back only its own changes. Closing a document
drops its groups, and a command that panics drops the groups it opened.
history.list reports whether a group is open.

Insert Copied Cells folds its nested steps into one undo step by
counting revisions; inside a group the nested steps push no entries, so
it now leaves the history alone there instead of removing entries from
before the group.
2026-10-21 14:05:41 -04:00
Mirza Bilal feac1679a1 HTML export: place pictures and charts at their anchors
Save as Web Page wrote only the cell table, so pictures and charts on a sheet
were dropped. A sheet that has either now keeps its own geometry and draws them:

- The table gets the sheet's column widths and row heights (`table-layout:fixed`,
  a `<colgroup>`, a height per row); hidden columns and rows take no room and
  merged-cell spans count only visible lines.
- A picture is an `<img>` with a `data:` URI, a chart is inline SVG built from
  the chart crate's drawing primitives (titles, axes, legends and data labels
  included), each absolutely positioned at its anchor cell plus offset.
- Sheets without pictures or charts write byte-identical HTML.

Adds contributors/people.toml entry for bilalmughal.
2026-10-21 01:35:58 +05:00
Marco Arnulfo f36bc100d4 AutoFit measures each distinct text once, and quickly on large columns (#1316) 2026-10-14 18:14:09 +02:00
Marco Arnulfo f92b4d30cb AutoFit Column Width measures text in the font the grid draws it with (fixes #1316) 2026-10-14 18:01:11 +02:00
derechopiano 72db972de3 fix(engine): bound Undo history by retained cell storage (#1227) 2026-10-14 08:23:57 +01:00
Marco Arnulfo 9f11e26e78 Journal: cap by serialized size and keep a recording's start through trims (part of #1228) 2026-10-14 05:10:19 +02:00
Brandon Thomas 2d0a3f8a47 Merge main into #780
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/insert.rs
#	crates/engine/src/tests.rs
2026-10-13 01:02:28 -04:00
Marco Arnulfo 522ede0fca Save an XLSX opened under an unknown extension back to its own file as XLSX (#878) 2026-10-13 05:14:30 +02:00
vangel76andClaude Sonnet 5.5 2797d468c5 Security: cell hyperlinks open only http, https and mailto, after a confirmation (#777)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 20:17:30 +02:00
James cd5f3f0a71 T6: pending keytips resolve at runtime and go live when their command lands
- Action::Pending now consults the engine catalog at fire time: silent
  no-op while the command is missing, runs it once it exists - no table
  edit needed when a future feature lands.
- Stripped stray backticks from 7 pending target ids so catalog lookup
  can ever match them.
- gridcraft-engine: doc(hidden) register_test_command hook so UI tests
  can prove the go-live path without touching production code.
- Tests: pending_sequences_are_silent_no_ops (no dialog/toast/journal),
  pending_sequences_go_live_when_the_command_lands (fake command fires
  via its reserved sequence), every_sequence_terminates_without_panicking
  (all 413 sequences pressed end-to-end).
2026-10-11 23:40:04 +03:00
Brandon Thomas b2101947ca Merge branch 'land' into fix-388
# Conflicts:
#	docs/ui-parity.md
2026-10-11 16:01:53 -04:00
Fabio LussiandClaude Opus 5.5 535c502fe7 Draw the outline band for grouped rows and columns
Grouped rows and columns now get Excel's outline band beside the headers:
a bracket per group, a -/+ button on the summary line and level buttons
in the corner. The buttons run data.hideDetail / data.showDetail and the
new data.showLevels, so they undo. Hide Detail marks the summary line
collapsed, Show Detail keeps inner groups that were collapsed on their
own, and Group / Ungroup take by: rows|cols. Show Detail and Hide Detail
are on the Data tab and in the Data menu, the group shortcuts are listed
as Alt+Shift+Right / Left, and shortcut lookup reads navigation keys by
their logical key so the numpad arrows work.

Fixes #373

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:29:03 +02:00
vangel76andClaude Opus 5.5 04001fd943 View: restore and save the scroll position (sheetView topLeftCell) (#378)
The model read topLeftCell but the grid always opened at A1 and never wrote
the current scroll back. Sheets now open scrolled to their saved first
visible cell; saves record the current one (and the active cell) without
dirtying the workbook. Frozen panes use the pane's topLeftCell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:11:23 +02:00
Brandon ThomasandClaude Opus 5.5 4a55aa3e34 Merge main into page-layout-view: pages keep the gliding selection (#266), frozen-pane clipping (#217), right-to-left mirroring and freeze handles (#310, #309); es/de/cs strings for headers and footers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:39:07 -04:00
Brandon Thomas 9cb6cb2384 Merge branch 'land' into fix-288
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/edit.rs
#	docs/target-app-parity.md
2026-10-11 13:01:23 -04:00
Brandon Thomas 141fef26e8 Merge remote-tracking branch 'origin/main' into fix-286
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/review.rs
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/target-app-parity.md
2026-10-11 12:52:12 -04:00
Brandon Thomas 685802ee9f Merge pull request #306 from vangel76/feat/pivot-calculated-field
PivotTables: calculated fields (pivot.calculatedField) (#304)

# Conflicts:
#	ROADMAP.md
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/target-app-parity.md
2026-10-11 12:05:52 -04:00
Brandon Thomas 2af0984af0 Merge pull request #308 from vangel76/feat/review-allow-edit-ranges
Review: Allow Edit Ranges with Excel-compatible password hashes (#307)

# Conflicts:
#	ROADMAP.md
#	crates/xlsx/src/sheet_write.rs
#	crates/xlsx/src/tests/malformed.rs
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/target-app-parity.md
2026-10-11 12:05:30 -04:00
Brandon Thomas f8903c9e98 Merge pull request #353 from LloydNicholson/fix/copy-multiple-ranges
Issue #348: copying multiple selections works when the areas line up, and explains when it can't

# Conflicts:
#	crates/engine/src/tests.rs
#	crates/ui-egui/tests/clipboard.rs
2026-10-11 12:04:15 -04:00
Brandon Thomas ea3e0ce0c5 Merge pull request #355 from LloydNicholson/fix/journal-redact-passwords
Journal: sheet protection passwords aren't recorded in plain text

# Conflicts:
#	crates/engine/src/tests.rs
2026-10-11 12:04:12 -04:00
Brandon Thomas 4f7144d753 Merge pull request #295 from vangel76/feat/view-formula-bar-zoom100
View: Formula Bar and Zoom 100% as engine commands (#289)

# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/src/control.rs
#	crates/ui-egui/src/lib.rs
#	docs/target-app-parity.md
2026-10-11 11:45:32 -04:00
lloydandClaude Opus 5.5 c1a500c5b9 Journal: leave sheet protection passwords out
Protect Sheet and Unprotect Sheet were journaled with their `password`
param, so the password showed in plain text in the journal dialog and
`engine.journal`, and a recorded script (Automate > Record Actions)
saved it in the workbook's hidden `_sc_scripts` name.

Session::execute now journals the params without secret ones
(`password`, or a name ending in `Password`). A replayed entry runs
without that param: Protect Sheet protects with the same options but no
password, and the matching Unprotect Sheet still succeeds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:17:30 +02:00
lloydandClaude Opus 5.5 d665499055 Clipboard: copy lined-up multiple selections; say why others can't be copied (#348)
Copying a multi-area selection always failed in the engine, and the UI
dropped the error, so Ctrl+C did nothing and Ctrl+V had nothing to
paste. Now, as in Excel:

- Areas that cover the same rows (or the same columns) and don't
  overlap are copied as one block, slid together left to right (top to
  bottom). The clipboard keeps a snapshot with the block packed at the
  first area's place; formulas travel as their values, and column
  widths or row heights, comments, pictures and merges come along.
- Other layouts, Cut of several areas and Paste Link of a multi-area
  copy are refused with "This action won't work on multiple
  selections."; Copy and Cut from the keyboard, ribbon and context menus
  now show that message instead of failing silently.
- The marching ants go around each copied area.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 17:02:39 +02:00
vangel76andClaude Opus 5.5 001f025119 View: Page Layout view with rulers and in-place headers and footers (#329)
View › Page Layout (and the status-bar button) now shows the sheet as printed
pages on a desk instead of overlaying page outlines on the grid.

- Model/XLSX: per-sheet view mode (normal / pageLayout / pageBreakPreview),
  saved as <sheetView view="…"> and read back. view.* commands set it per
  sheet ({sheet?}) without an undo step or dirtying a clean workbook.
- Engine: paper::PageGrid paginates the sheet from A1 with the print
  pagination (print::split_bands, shared with PDF export and printing) and
  maps cells to pages and back; header/footer section helpers
  (split/join, &[Page] field names) shared with the PDF header code.
  pageLayout.headerFooter takes {part, section, text} for one section and a
  sheet; header/footer strings are capped at 255 characters.
  view.ruler toggles the rulers.
- UI: Geo carries the page grid, so painting, hit-testing, selection,
  editing, objects and scrolling work through the page transform; frozen
  panes are ignored in this view. Pages with margins and gaps, "Click to add
  data" pages, rulers in inches (English) or centimetres, headers/footers
  drawn on printed pages, click a margin section to edit it in place; a
  click elsewhere commits (one undo step), Escape cancels. Header & Footer
  contextual tab: presets, Page Number, Number of Pages, Current Date/Time,
  File Path, File Name, Sheet Name, Go to Header/Footer. View › Ruler.
- New strings in every catalog; new code-drawn icons; desk colour token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:24:06 +02:00
vangel76andClaude Opus 5.5 3b918ada2c Review: Allow Edit Ranges with Excel-compatible password hashes (#307)
- Model: Sheet.edit_ranges (title, ranges, optional password hash,
  security descriptor) and gridcraft_model::password: the ECMA-376 legacy
  16-bit hash and the salted, iterated SHA-2 hash (SHA-512/384/256; other
  algorithms, damaged hashes and spin counts over 10,000,000 are refused).
  New passwords use SHA-512, spin count 100000. Adds the sha2 crate.
- XLSX: <protectedRanges> read and written; an unreadable password keeps
  the range locked.
- review.allowEditRanges {action: list|add|modify|delete|unlock, ...}: empty
  params list; ranges can't change while the sheet is protected; unlock
  verifies the password for the session. Not journaled (passwords).
- Locked-cell checks (commit guard, cell.set, picture in cell) let edits
  through in open or unlocked ranges; ranges move with structural edits.
- Ribbon button and a form dialog (menu invocation only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:26:14 +02:00
vangel76andClaude Opus 5.5 400ab591cb PivotTables: calculated fields (pivot.calculatedField) (#304)
A value field can be a calculated field whose formula is evaluated on
the sums of the fields it names for each report cell (Excel's documented
semantics). Command to add/change/delete, dialog from the field pane,
XLSX cacheField formula round trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:50 +02:00
vangel76andClaude Opus 5.5 be028cc6cc View: Formula Bar and Zoom 100% as engine commands (#289)
- view.zoom100 sets the active sheet's zoom to 100% (the ribbon's 100%
  button runs it).
- view.formulaBar {on?} toggles a formulaBar preference (Prefs, saved in
  prefs.json on desktop; an application option, not in the file). The UI
  shows the formula bar from it; the ribbon checkbox, native menu and
  ui.set {formulaBar} go through the command.
- The UI-only interceptions and their entries in engine.commands are gone,
  so the CLI and MCP can run both. Parity checklist regenerated (260 / 290).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:09:30 +02:00
vangel76andClaude Opus 5.5 33afc7d3a5 Clipboard: Insert Copied Cells and Insert Cut Cells (#21)
New command home.insertCopiedCells: makes room at the active cell and
pastes the clipboard there, as one undo step. Whole copied rows or columns
insert whole rows or columns; a copied block shifts the cells down or right
(Insert Paste dialog from the menu). A cut of whole rows or columns moves
them and closes the gap (Insert Cut Cells). The cell and header context
menus show the entry while the clipboard holds a copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:04:52 +02:00
vangel76andClaude Opus 5.5 6f47a8b463 Review: Previous/Next Comment, Show Comments, Show All Notes, Convert to Comments (#281)
- review.previousComment / review.nextComment select the previous/next
  threaded comment in reading order (row by row), across visible sheets in
  tab order, wrapping around; disabled when the workbook has no comments.
- review.showComments {on?} toggles the Comments pane as session state, so
  the CLI, MCP and control channel can drive it; the UI pane follows it.
- review.showAllNotes {on?} displays every note (session display setting,
  not saved in the file).
- review.convertToComments turns every note in the workbook into a threaded
  comment with the same author and text, as one undoable edit.
- Ribbon: Previous/Next and a Show Comments toggle in the Comments group;
  Show All Notes and Convert to Comments in the Notes menu. Strings in all
  catalogs. Parity checklist regenerated (263 / 290).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:04:03 +02:00
vangel76andClaude Opus 5.5 b6618aee8e Clipboard: pasted currency cells keep the number from the clipboard HTML (#257)
Spreadsheets put an HTML table next to the tab-separated text; Excel
(x:num) and LibreOffice Calc (sdval) record each cell's number there.
Paste now reads the HTML flavour (new paste_html host service, arboard on
desktop) and edit.paste takes an optional html param: a field that would
paste as text becomes the recorded number when the HTML cell shows the
same text, with an inferred format ("Rp"#,##0.00) that renders it back
identically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:03:46 +02:00
MarekSpodBiedry fe162f8f23 Report an error when file commands get no file in MCP and CLI (#135) 2026-10-10 19:05:56 +02:00
Brandon ThomasandClaude Opus 5.5 488e12de31 Rename SheetCraft to GridCraft everywhere (crates, apps, bundle ids, packaging, docs)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:39:08 -04:00
Brandon ThomasandClaude Opus 5.5 f76a0beca3 M8: Draw tab — pen, highlighter, eraser, ink strokes and Ink to Shape
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:20:40 -04:00
Brandon ThomasandClaude Opus 5.5 168b8ec8b7 M4–M10: PivotTables, PDF export & printing, what-if analysis, spelling, more commands
- PivotTables: engine (grouping, date groups, multiple values, show-as, filters, layouts,
  refresh, recommended pivots) + PivotTable Fields task pane
- sheetcraft-pdf (dependency-free PDF writer, core-14 fonts) + file.exportPdf/print/
  printPreview/pageLayout.pageSetup with pagination, headers/footers, charts, images
- What-if: Goal Seek, Scenario Manager, data tables, advanced filter, consolidate
- Page Break Preview rendering; view mode buttons
- Spelling (system dictionary), icons library, cell checkboxes, recorded scripts,
  chart design/format commands, arrange, custom views, watch window, Get Data from CSV/JSON
- Native macOS menu bar
- UI interaction tests (kittest): fixed arrow keys losing grid focus and Escape not cancelling
- Perf: FxHash in calc, sparse range reads, Arc'd formula ASTs, fast auto row heights
- Parity 254/290 (87.6%)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:04:46 -04:00