Files
gridcraft/docs/macros.md
T
PranavandFredApps 25881a8e03 UI: an unsaved macro-editor draft counts as unsaved work when its workbook closes (#492)
* UI: an unsaved macro-editor draft counts as unsaved work when its workbook closes

Closing a workbook (File > Close, Cmd+W, the Backstage Close, a window's
close button) while the macro editor holds unsaved changes now asks about
the draft first, with the editor's own Save changes to macro question,
even if the workbook itself is saved. Before, the workbook closed and the
draft was discarded without a question. Save or Don't Save goes on to
close the workbook, which then asks about its own unsaved changes (a
saved macro is one); Cancel keeps both open. A draft that cannot be
saved keeps its workbook open with the reason shown. A new macro that
has not been edited does not ask, and a close that leaves the workbook
open (one of several windows) or a forced close goes ahead as before.

* UI: a new macro's name change alone counts as an unsaved macro-editor draft

The check compared the draft with an untouched new macro that took the
draft's current name, so a new macro whose only change was its name
compared equal, and closing its workbook discarded the name without
asking. It now compares with the name the editor opened with.

* UI: Quit asks about an unsaved macro-editor draft before quitting

Quit (Cmd+Q, the macOS Quit menu, a quit from the Dock) went straight to
the unsaved workbooks and never consulted the macro step editor, so with
every workbook saved the app quit and discarded the editor's unsaved
steps. It now lets the editor ask first, as the window's close button
already does: Save or Don't Save goes on with the quit, Cancel stops it.

With one native window per workbook, the editor goes on with the app's
quit directly once it has closed: a close sent to the window it is drawn
in would close only that workbook's window.

* UI: a refused macro save while quitting stops the quit

When the macro editor's Save changes question was answered Save during
a quit (the window's close button or Quit) and the save was refused (a
new macro with a name already in use, a limit), the editor stayed open
with the reason shown but kept its quit intent. Closing the editor later
on its own then quit the app. A refused save now stops the quit, as
Cancel does.

* UI: a quit takes over a workbook close waiting on the macro editor

When File > Close was waiting on the macro editor's question and Quit
came in (or the other way round), closing the editor went on with the
quit and then replayed the close. With one native window per workbook,
the quit had already moved to the next unsaved workbook's window, so the
replayed close acted on that workbook and replaced the quit's Save
Changes question with an ordinary close question. The quit now takes
over: it asks about every unsaved workbook itself, and the waiting close
is dropped.

* UI: an untouched new macro closes without asking, however the editor closes

Closing a workbook already left an untouched new macro alone, but the
editor's own close checks still read its dirty flag, which a new macro
starts with: its close button, a quit, the control channel's cancel and
the close after a stopped debug run asked Save changes to macro (or
refused) for a macro nobody had edited. Every close check now asks
whether the draft has unsaved changes, so all of them agree.

* UI: closing the window that shows the macro editor asks about its draft

The editor's unsaved draft was consulted only when its workbook would
close. Closing the window that shows the editor while the workbook
stayed open in another window (window.close, or File > Close in that
window) went ahead: the window's dialog went with it, and the editor's
state was left behind with no window to show it, so the next macro
opened in the editor replaced the draft without asking. That close now
asks first, like a workbook close.

An editor left with no window to show it (a saved one, or a forced
close) is now dropped, as when its workbook closes. A window that has
closed no longer counts as showing a dialog while its parked state is
still kept.

* UI: a close waiting on the macro editor runs in the window it was asked in

A workbook or window close that waited on the editor's Save changes
question was replayed with the command and its parameters alone, so
file.close acted on whichever window was the session's active one when
the editor closed. The editor is drawn with its own window active, but
nothing tied the replay to it. The pending close now records the
editor's window and enters it before running again; if that window has
closed meanwhile, nothing else is closed and a message says so.

* UI: a close asked while the macro editor is asking waits for the answer

A second file.close or window.close for the editor's workbook or window
while its Save changes question stood replaced the pending close with
the new one: the answer then closed whatever the last request asked for,
not what the question had been opened for. A further request for the
same close now waits on the open question (no second question, and the
close runs once); a request for a different close (the workbook while
only the editor's window was closing, or the reverse) is refused with
the reason until the question is answered. A quit keeps taking over as
before.

* UI: test the quit with a macro draft in one window and unsaved cells in another

The quit asks about the editor's draft first, in its window, then about
each unsaved workbook in its window; Cancel at either question stops it
with every window and workbook open, and a draft discarded with Don't
Save before the quit was cancelled stays discarded. Covered in the
single-window harness, which presses the real buttons, and in the
native-windows harness, which now takes a key press in the root window.

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-02 07:04:10 +01:00

339 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Macros
> **Last updated:** 2026-11-01 · **Change:** minor (a close that waits on the step editor's question runs in the editor's window, and a further close asked meanwhile waits for the answer or is refused; earlier: closing a workbook or quitting asks about the step editor's unsaved draft first; recording macros and the management commands; Record Macro takes a name, shortcut and description; the macro interface: Automate › Macros, the Macros and Record Macro dialogs, the step editor, shortcuts)
GridCraft macros are typed, declarative lists of commands, not VBA. Every step runs a GridCraft
command (the same ids the ribbon, CLI and MCP use) or one of three bounded control steps. A macro
declares the inputs it works on, runs as one undo step, rolls all workbook changes back on an
error (a file it already wrote stays), checks where its results will land before it writes them,
and does not touch files without permission.
Agents run macros with `macro.run` like any other command.
This page describes the engine, its commands and the macro interface in the window.
## A macro
```json
{
"name": "Totals",
"description": "Adds a total next to the amounts",
"inputs": [{"name": "Input", "header": true, "cols": [2, 2], "colTypes": ["text", "number"]}],
"output": {"anchor": "Input.right(2).cell(1,2)", "onConflict": "ask"},
"steps": [
{"type": "command", "id": "cell.set", "params": {"cell": "Output", "input": "Total"}},
{"type": "command", "id": "cell.set", "params": {"cell": "Output.offset(1,0)", "input": "=SUM({{Input.data.col(2)}})"}},
{"type": "repeat", "over": "Input.data", "of": "rows", "max": 1000, "body": [
{"type": "if", "cell": "Row.cell(1,2)", "op": "gt", "value": 100,
"then": [{"type": "command", "id": "home.bold", "params": {"range": "Row"}}]}
]},
{"type": "stop", "message": "Done."}
],
"permissions": []
}
```
- **Steps**: `command` (`id`, `params`), `repeat` (each row or column of `over`, at most `max`
times), `if` (`cell` compared with `value` by `eq`, `ne`, `gt`, `ge`, `lt`, `le`, `empty`,
`notEmpty` or `contains`; `then` and `else` lists) and `stop` (`message`; `rollback: true`
undoes the run). Every step can carry `enabled`, `breakpoint` and `note`. The short form
`{"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`. 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), passes its commands at most 256 MB of parameters, all steps
together, and takes at most 60 seconds, all three 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 and
parameter limits apply). The debugger gives each of its actions the time limit on its own.
## Tokens
References in step parameters can be tokens, worked out when the step runs:
| Token | Means |
|---|---|
| `Input`, or another input's name | the range the input is bound to |
| `Output` | the output rule's anchor |
| `Row`, `Column` | the current row or column of the Repeat around the step |
| `Name:Total` | a defined name, or a table's data |
Methods narrow or move a range and chain: `col(2)` or `col("Amount")`, `row(1)`, `cols(2..3)`,
`rows(2..)`, `cell(r,c)` (relative to the top-left cell; `cell(0,1)` is the cell above),
`offset(r,c)`, `resize(h,w)`, `data` (without the header row), `below(n)` and `right(n)`.
`col("Amount")` looks the name up in an input's header row, directly or after `data`; on a range
without a header row it is refused. A defined name can hold periods: `Name:Sales.Q1` is the name
`Sales.Q1`, and `Name:Sales.Q1.cell(1,1)` its first cell, because the longest name or table that
exists is used and methods follow it.
Write a token as the whole value of a reference parameter (`cell`, `range`, `target`, keys ending
in `Cell` or `Range`…), as `{"$ref": "Input.col(2)"}` anywhere, or as `{{Input.col(2)}}` inside
any string, such as a formula; `{{{{` in a string is a literal `{{`, and `{"$text": "Output"}`
anywhere is the text as it is, never read as a token or for `{{…}}` (a defined name called
`Output`, or `Dear {{name}}`). Under the general keys that
other commands use for plain words (`to`, `from`, `at`, `area`, `source`, `target`,
`destination`, `location`), a bare `Row` or `Column` stays text (a replacement word, a pivot
area); write `Row.col(2)`, `{{Row}}` or `{"$ref": "Row"}` there. Plain A1 references stay
absolute; a `Name:` anchor follows inserted rows. A reference with a sheet name is never a token,
so `Output!A1` is a cell on a sheet called Output, even when a token or input has that name.
`Input.data` on a range that is only a header row, and `Name:` of a table with no data rows, are
refused rather than read as the header.
## Running
`macro.run {name, inputs?, onConflict?, overwrite?, approve?, timeLimit?}`:
1. **Policy.** File commands other than Properties, exports and printing (such as Open, Save
and Close), app, window (including New Window, Hide and Unhide), automate and macro commands,
and Undo and Redo, never run in a macro. File › Properties runs, and so do exports and
printing (`file.exportPdf`, `exportCsv`, `exportHtml`, `print`, `printPreview`, `saveBytes`)
that only produce bytes. Reading or writing a file (`data.getData`, `data.fromTextCsv`,
`insert.picture` or `pageLayout.background` with a `path`, or an export or print with a
`path`) needs the command in the macro's `permissions`. Any `path` other than `null` counts,
including a blank one and a token, and the policy is checked again on the parameters as they
are when the step runs. A macro that touches files, or that came with a workbook opened from
a file, runs once the person approves it: the call fails with `approve: …` and runs with
`approve: true`. Approval lasts for the session, until the macro changes. Every step other
than an approved file step runs inside the file sandbox that scripts use, so no other
parameter reaches a file either.
2. **Footprint.** Unless the conflict rule is `overwrite`, the macro first runs in dry-run mode on
the real workbook, and everything is put back. Cells it would write outside its inputs that
hold data, and sheets and objects it would delete, are conflicts, handled by `onConflict` (or
the macro's `output.onConflict`): `ask` (the call fails with `confirm: …`; `overwrite: true`
answers it), `fail`, `overwrite`, `shiftDown` or `shiftRight` (Insert Cells makes room, then
the footprint is checked again). Steps that touch files, and Solver, end the dry run early;
the footprint then says it is partial. Unless the rule is `overwrite`, the run also checks
every step as it goes, since the footprint can miss a write: it is partial, or a value such as
RAND or NOW sends the run another way than the dry run. A step that writes over cells, sheets
or objects that held data when the run started stops the run and rolls the workbook back (a
file already written stays): it asks (`confirm: …`) under `ask` and fails otherwise, since
shifting can't make room that late. Moving cells that hold data, as inserting or deleting rows
or cells above them does, counts as writing over them, in the footprint and in this check, and
so does a formula whose references such a move rewrites: both compare cells by place, so they
may ask about data that only moved, never the other way.
3. **Run.** One undo step, "Run Macro: Totals". Any error rolls the whole run back and names the
step: `Step 3.1 (cell.set): …` (paths are 1-based; `2.1` is inside a Repeat, `4.then.1` inside
an If). The message ends "Nothing was changed.", or names the files the run already wrote,
which stay. An input the macro doesn't have, an input that isn't reference text, and
`onConflict`, `overwrite`, `approve` or `timeLimit` of the wrong kind are refused rather than
ignored. When a step inserts, deletes or moves sheets, rows, columns or cells, the inputs, the
output and the range of a Repeat in progress move with their cells, as references in formulas
do; a step that deletes one of them, or changes the size of a range a Repeat is going over,
stops the run.
`macro.check {name, inputs?, onConflict?, overwrite?, timeLimit?}` reports the bound inputs, the
output anchor, any approval needed and the footprint, and puts back everything the dry run
changed. `ok` says whether `macro.run` with the same parameters would go ahead without a question;
when it wouldn't, `errors` says why: the run would fail at a step, a Stop step rolls it back, it
would write over data under `ask` or `fail`, shifting can't make room (the check shifts and
checks again, then puts everything back), or the run would go past
the step or parameter limit counting the dry runs before it. The random numbers RAND gives move
on, as after any recalculation.
## Debugging
`macro.debug {action, …}` runs a macro a step at a time. The actions are:
- `start` with `name` and the options of `macro.run` (`inputs`, `onConflict`, `overwrite`,
`approve`, `timeLimit`), refused as `macro.run` refuses them when they are of the wrong kind. The
checks, the approval and the footprint come first, as for `macro.run`; then the run pauses
before its first step.
- `step` runs the next step; `continue` runs to the next breakpoint or the end; `runTo` (`step`:
a path) runs to that step, stopping at a breakpoint on the way.
- `stop` ends the run: `keep: true` keeps the changes as one undo step, otherwise they are rolled
back.
- `state` answers without running anything (the default while a macro is being debugged).
`breakpoints` (a list of step paths of the macro, at most 10,000) can be given with any action and
replaces the list set before; `breakpointsOnly: true` makes the list replace the steps' own
breakpoint flags, also when it is given without a list. An unknown action, a breakpoint or `runTo`
path the macro doesn't have, and `keep` or `breakpointsOnly` that isn't `true` or `false` are
refused before anything changes. The time limit applies to each action on its own (`start` with
its dry runs, and each `step`, `continue` or `runTo`); the step and parameter limits apply to the
whole run, counting the dry runs.
Each answer gives the next step with its parameters as they would run (a Repeat over whole rows or
columns shows the part of the sheet in use, as the run goes over it), the parameters of the step
that just ran, the steps the run has executed (the dry runs not counted), and what the run has
changed in its workbook: `changed` lists at most 500 entries (cell ranges, and sheets added,
deleted or renamed) and `changedCells` counts the changed cells on the sheets it had at the start. `shifted` names the rule that made
room at the start, and `wroteFiles` the files the run wrote, which stay when the run is rolled
back; the answer to a rolled-back run says so in `message`. A run that ends (its last step, a
Stop step, or a failed step, which rolls it back) or is stopped answers with `state` `finished`,
`stopped` or `failed`.
While a macro is being debugged, its workbook is locked between steps: only `macro.debug`, queries
(commands that only read), commands that look around (`selection.*`, Select All, `sheet.activate`,
`sheet.next` and `sheet.previous`, Go To, Go To Special, Find, Copy and the zoom commands), Switch
Window, Close (which ends the run with its workbook) and Automate › Stop Action run there.
Everything else, undoable or not, saving included, is refused with "Finish or stop the macro
first", also when another command runs it (stopping Record Actions saves a script), and so is
`macro.check`, whose dry run runs the macro's steps. Other
workbooks stay editable. The person may look around between steps: before the next step runs, the
debugger puts the active sheet and the selection back where the run left them, so the run goes on
as `macro.run` would run it. A zoom change made meanwhile is part of the run, and is undone with
it. Stop Action rolls the run back and ends it, and its answer names the macro. The debugger runs
on its own, never as a step of a script or macro, and is never recorded.
## Recording
`macro.record` toggles recording. Starting takes `relative` (default true; `false` for absolute
references) and, from the Record Macro dialog, `name`, `shortcut` and `description`: the macro's
name, its Ctrl+Shift shortcut letter (`"Ctrl+Shift+M"` or `"M"`) and its description. They are
checked at once, so a name that is taken (a kept one included), too long or holds line breaks, or a
letter that GridCraft or another macro uses, is refused before anything is recorded. Without a name
the macro is called `Macro1`, `Macro2` and so on. A `name` or `description` given when stopping wins
over the one given when starting; a name that another macro has by then gets a suffix, such as `Tidy
(2)`, so stopping never replaces a macro, and a shortcut another macro took meanwhile is left off,
which the result says in `shortcutDropped`. `cancel: true` ends a recording without saving it, the
way out of one whose macro can't be saved. A parameter the call would ignore is refused: `relative`
or `shortcut` when stopping, `stop: false` while recording, anything beside `cancel: true`, and one
of the wrong kind. The macro is saved in the workbook where recording started, even if another one
is active; if that workbook was closed, stopping ends the recording without saving it. When saving
the recording fails (a name the check refuses, a workbook at its macro limit, a macro being debugged
in that workbook), recording goes on, so stopping again keeps what was recorded. The person recorded
the macro, so in a workbook opened from a file it runs without the approval a macro that came with
the file needs, until it changes.
A recording keeps up to 100,000 commands and 64 MB of them as JSON, and a macro holds up to
10,000 steps and 4,194,304 characters of JSON. The steps past any of these limits, and steps
recorded in another workbook, are left out and counted in `dropped`.
With relative references the selection when recording starts is the example input: references in
and near it on its sheet become tokens (on another sheet `C4` stays that sheet's `C4`), and the
input's shape, header and column types are inferred from it as it was when recording started,
before the recorded steps changed it. Recorded text that playback would read as a token stays
text: a reference parameter that reads as one (a defined name called `Output`) is written
`{"$text": "Output"}`, and `{{` in a string is written `{{{{`. Toggles such as Bold are recorded
with the state they set (`"on": true`), also inside a script run, so playing them back sets them
rather than flipping them.
Commands a macro may not run are left out and listed in `skipped`, also from the steps of a macro
or script run while recording. A macro run while recording is replaced by its steps when it has
no inputs, no output and only plain commands (otherwise it is left out and listed), and an
Automate script run by the steps it ran, without a step that only opened a dialog (a menu-style
call without its parameters). Both are kept as they ran, so editing or deleting the macro or
script before the recording stops changes nothing; a run whose steps did not fit in the
recording's 64 MB is left out and listed.
Undo while recording works as in Excel: `edit.undo` is left out (a macro never runs it), and the
step it undid stays in the recording, so playing the recording back makes that edit again.
GridCraft keeps the Ctrl+Shift letters it uses itself on some platform: F, G, H, J, K, L, R, S, T
and Z (`macros::RESERVED_SHORTCUTS`). A shortcut a file brings with it on one of these letters is
kept but does not run the macro.
## Other commands and storage
`macro.list`, `macro.get`, `macro.save {macro, replace?}`, `macro.delete` and `macro.rename
{name, to}`. Saving under a name a macro has is refused unless `replace: true` is passed, and
renaming to one is refused; names compare ignoring the case of the letters A to Z. A renamed macro is checked
against every limit again, its size included. Saving, renaming and deleting are undoable.
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. 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 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. They count when a
macro is added too (saving, or stopping a recording, is refused once readable and kept macros
together reach 1,000, and the message says how many are kept), so a save holds no more macros
than the next open keeps. Their names are taken: saving or renaming a macro to one is refused, and
a recording gets a suffix. 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.
## In the window
- **Automate › Macros group.** Macros opens the Macros dialog. Record Macro opens the Record
Macro dialog (name, Ctrl+Shift shortcut letter, description, Use Relative References); OK
starts recording and stays off while the name or the letter cannot be used, with the reason
under the fields. While recording, the button reads Stop Recording, the status bar shows a red
dot, "Recording · N steps" and Stop, and Use Relative References is locked. Run Macro runs the
macro run last (or the only one); its menu lists the recent macros, then every macro. New
Macro opens the step editor on a new macro.
- **Macros dialog** (Automate › Macros, View › Macros, Alt+F8). It lists the workbook's macros
(with their shortcuts), then its Automate scripts, and says when the file carries a VBA project.
Scripts that came with an opened file stay disabled until Trust Scripts (`automate.trustScripts`)
trusts them for the session. Run runs the selected macro on the selection or the selected
script; Step Into, Edit and Create open the step editor; Delete asks first; Options sets a
macro's shortcut letter and description. The dialog keeps the result of `view.macros`, as before
macros existed.
- **Step editor.** A resizable window that works on a draft and saves it with `macro.save`; in a
narrow app window it is no larger than the window and its toolbar wraps onto a second row. The
step list shows each step's number, a breakpoint dot in the gutter (click to set or clear), a
category icon, a summary, an error marker and an enabled checkbox; Repeat bodies and If branches
are indented under their step, and rows drag to reorder within their list. Add Step opens a
command picker (control steps first; commands a macro may never run are left out); Duplicate and
Delete act on the selected step. The inspector's Details tab edits the selected step, with
reference boxes that take a typed reference or a selection on the grid and switch between a
token relative to the example input (Rel) and an absolute reference (Abs); the Inputs tab sets
each input's shape, header and column types, and Use current selection as example infers them;
the Output tab sets the anchor and what to do when results would land on data. The editor
belongs to the workbook it opened in: while another workbook is active it says so and Save,
Check, Run and Debug wait until that workbook is active again, and closing the workbook closes
the editor. A draft with unsaved changes counts as unsaved work when its workbook closes (File >
Close, Cmd+W, a window's close button), or the window that shows the editor closes while the
workbook stays open in another: the editor first asks Save changes to the macro, even if the
workbook itself is saved; Save or Don't Save goes on with the close, in the window it was asked
in (whichever window was activated meanwhile), and a workbook that closes then asks about its
own unsaved changes, and Cancel keeps both open. While the question stands, a further request
for the same close (Cmd+W again, the window's close button) waits for the answer without a
second question, and the close then runs once; a request for a different close (the whole
workbook while only the editor's window was closing, or the reverse) is refused with the reason
until the question is answered. A new macro that has not been edited does not ask. It keeps its
window until it closes itself: another dialog asked for meanwhile is refused with a message, and
closing the app (its window's close button, Quit, Cmd+Q) first asks about the editor's debug
run and unsaved steps, in the editor's window, then about each unsaved workbook in its window;
Cancel at any of these questions stops the quit with every window open (a draft already
discarded with Don't Save stays discarded).
- **Debug bar.** Check dry-runs the macro and colours the grid: inputs blue, the cells it writes
green, the cells among them that hold data red. Run runs it as one undo step. Step, Continue and
Run to Here start the debugger when needed (`macro.debug` with the editor's breakpoints and
`breakpointsOnly: true`, so a dot cleared while paused takes effect at once); the current step is
selected, its parameters are shown as they will run, and its target is outlined on the grid.
Stop asks whether to keep the changes so far or undo them. While a macro is debugged the status
bar says "Debugging" with the macro's name, and Show reopens the editor.
- **Questions.** A macro that needs approval offers Run; a macro whose output would land on data
offers Overwrite, Shift Down and Shift Right. Each button runs the command again with
`approve: true` or the chosen `onConflict`, in the workbook that asked: an answer given while
another workbook is active does nothing and says why.
- **Shortcuts.** Ctrl+Shift+letter (⌘⇧letter on a Mac) on the grid runs the macro with that
letter. The letters GridCraft uses itself keep their own meaning.
Commands with empty parameters never open these dialogs: `macro.record {}` starts recording
under the next free name, and the dialogs are opened only from the ribbon, the menus and keys.
## Automate scripts and VBA
Automate scripts (`automate.recordActions`, `newScript`, `allScripts`, `runScript`,
`deleteScript`) are an older, separate feature. They keep their commands, parameters, storage
(`_sc_scripts`) and results, and View › Macros (`view.macros`) still lists them. Macro commands
neither read nor change their storage; a recording keeps the steps a script run ran while it
recorded. A workbook can hold a script and a macro with the same name.
A VBA project in an `.xlsm` or `.xltm` file is preserved on save and never run. GridCraft macros
are stored apart from it.