Commit Graph
17 Commits
Author SHA1 Message Date
prxnvt ca2be34e8a Engine: a rolled-back group takes what its script runs ran out of the recording too
Taking back the steps a rolled-back group recorded left what a taken-back script or macro run
ran (`Recorder::ran`) under its old index, where a later run could pick it up, and left it out of
the size count. `cut_back` now drops it with its step, moves a kept run's entry to the step's new
index and counts both again.

- Test: `a_rolled_back_script_run_takes_what_it_ran_out_of_the_recording`.
2026-10-25 06:29:23 -04:00
prxnvt 0a9305f784 Merge #2145 (9a22c4b2) into #2152 2026-10-25 06:28:06 -04:00
prxnvt 9a22c4b2f2 Merge the footprint pull request (24f0c3df, with #2144 and #2151) into #2145 2026-10-25 06:28:06 -04:00
prxnvt 0a929eaf68 Engine: a rolled-back group takes back only the steps recorded in its workbook
A rollback took back every step recorded since its group began, so an edit recorded in another
workbook while the group was open was lost from the recording although the edit stayed. It now
takes back only the steps recorded in the group's own workbook.

- Test: the other workbook's edit in `stop_action_runs_only_on_its_own_and_is_not_recorded`.
2026-10-25 06:27:53 -04:00
prxnvt ec58ec5f4b Merge #2145 (f0b667aa) into #2152 2026-10-25 06:02:18 -04:00
prxnvt f0b667aa02 Merge the footprint pull request (361fff98, with #2144 and #2151) into #2145 2026-10-25 06:02:18 -04:00
prxnvt bfcf50aad3 Engine: rolling back an undo group takes back the steps it recorded
Stop Action (or any rollback) put a group's edits back but left the steps recorded while the
group was open in the recording, so playing the recording back made edits the workbook no longer
had. A group remembers where the recording was when it began, and its rollback cuts the
recording back to there.

- Test: `stop_action_runs_only_on_its_own_and_is_not_recorded`, which kept the rolled-back edit
  before.
2026-10-25 06:00:13 -04:00
prxnvt fdd26876fb Merge #2145 (227078f5, with the footprint pull request and #2144) into #2152
# Conflicts:
#	docs/macros.md
2026-10-25 03:21:39 -04:00
prxnvt 460a72d3bb Engine: a recording keeps what ran and plays back as it was recorded
- A script step that only opened a dialog (a menu-style call that left the workbook unchanged)
  is left out of the script run's steps, by the recorder hook's rule; a script run whose steps
  the recording couldn't keep is left out and listed in `skipped`, not read from the workbook
  as the script stands when recording stops (a_script_step_that_only_opened_a_dialog_is_left_out_of_the_recording).
- A script's toggles keep the state they set (`"on": true`), as a top-level Bold does
  (a_script_run_records_the_state_its_toggles_set).
- A recorded macro.run keeps the steps it ran, as a script run does, so saving or deleting the
  macro before the recording stops changes nothing (a_recorded_macro_run_keeps_the_steps_that_ran).
- The example input's shape and column types are inferred when recording starts, not from the
  data the recording changed (the_recorded_input_is_inferred_as_it_was_when_recording_started).
- Recorded text that playback would read as a token stays text: a reference parameter that reads
  as one becomes {"$text": …}, and `{{` becomes `{{{{`
  (recorded_text_that_reads_as_a_token_plays_back_as_text). The resolver (below #2152) gains
  `{"$text": …}`, text passed as it is (text_marked_as_text_is_never_a_token).
- A recording over the macro size limit is cut at the limit and the steps left out are counted
  in `dropped` (a_recording_past_the_macro_size_is_cut_and_counted).
- A macro recorded in a workbook opened from a file is approved for the session, since the
  person recorded it (a_macro_recorded_in_a_workbook_from_a_file_runs_without_asking).
- macro.record refuses parameters it would ignore: name or description when starting, relative
  when stopping, stop: false while recording, others beside cancel: true, and wrong kinds
  (record_refuses_parameters_it_would_ignore).
- Undo while recording keeps the undone step, as in Excel; documented
  (undo_while_recording_keeps_the_undone_step_as_excel_does).
- Docs: macros.md Recording and Tokens; module comments no longer say scripts are read.
2026-10-25 03:19:35 -04:00
prxnvt 7dad14e77e Engine: the macro debugger locks its workbook to looking around, ends with Stop Action and checks its parameters
- `macro.debug` refuses to run as a step of a script or macro, and is never recorded (the
  recording buffer and Record Actions' journal both leave it out); a debugger whose undo group
  something else closed locks nothing, and its next action says the run had ended instead of
  reporting a keep or a rollback. Tests: `the_debugger_runs_on_its_own_and_is_never_recorded`,
  `a_debugger_whose_group_was_closed_elsewhere_locks_nothing`.
- Stop Action is no longer refused under the debugger: it rolls the run back, ends the debugger
  and names the macro. Test: `stop_action_stops_a_macro_being_debugged` (was
  `stop_action_waits_while_a_macro_is_being_debugged`).
- Between steps the debugged workbook runs only `macro.debug`, queries and an allow-list of
  commands that look around (selection, sheet changes, Go To, Find, Copy, zoom, Switch Window,
  Close, Stop Action); everything else is refused, saving and view modes included. The run's
  active sheet and selection are put back before its next step. Test:
  `between_steps_only_looking_around_runs_and_the_run_continues_where_it_was`.
- Only the top-level `macro.debug` call rolls the run back after a panic; a panic nested in a step
  is that step's error. Test: `a_panic_inside_a_step_is_that_steps_error_and_the_run_goes_on`.
- `keep` and `breakpointsOnly` must be true or false, breakpoints must be step paths of the macro
  (at most 10,000), and the action is checked before breakpoints change. Test:
  `debugger_parameters_are_checked_before_anything_changes`.
- Answers: `executed` counts the run's own steps (not the footprint's), `shifted` and `wroteFiles`
  are reported, a rollback's message names the files that stay, `changed` lists deleted and
  renamed sheets and at most 500 entries with `changedCells`, and a Repeat over whole rows or
  columns shows the part in use. Tests: `the_debuggers_answers_count_its_own_steps_and_say_what_stays`,
  `the_debugger_lists_deleted_and_renamed_sheets_and_caps_the_list`,
  `the_debugger_shows_a_repeat_over_whole_columns_as_the_run_goes_over_them`.
2026-10-25 03:17:42 -04:00
prxnvt b995c7c9a0 Engine: a recorded script run keeps the steps that ran
The recorder expanded an automate.runScript step from the workbook as it
stood when the recording stopped, so a script edited or deleted during the
recording changed the saved macro, or dropped the step. The run now leaves
the steps it ran with the recorder (Recorder::ran, by step index, within
the byte budget), and the conversion reads those, falling back to the
workbook only when they could not be kept.
2026-10-25 02:18:58 -04:00
prxnvt 6cd4cebfb7 Engine: Stop Action runs on its own and is not recorded
Run from inside another command, automate.stopAction rolled back that
command's own group, pulling the workbook from under the rest of its run; and
the recording buffer kept it, so a recording could replay the stop inside the
run it was part of. Nested, the command is refused and the group stays; the
recorder leaves it out (record::NOT_RECORDED).
2026-10-24 02:18:07 -04:00
prxnvt 2e72407fc6 Engine: the recorder skips a call that only opened a dialog
A menu-style call with no parameters, such as `file.open`,
`data.fromTextCsv` or `home.formatCells` with `{}`, only queues its
dialog and succeeds. The recorder kept it as a step with empty
parameters, and then kept the dialog's confirming call as well, so
playing the recording back ran the command twice, or failed on the
empty step when played back headless. Only `execute_headless` took
the step back, and only for the open and save-as dialogs.

`execute` now compares the queued UI requests before and after a
top-level command and does not record one that queued a dialog. The
special case in `execute_headless` goes (it keeps turning a missing
file into an error), and with it `Recorder::truncate`, which had no
other caller.
2026-10-24 00:51:37 -04:00
prxnvt bbf36000d4 Engine: the recorder counts a dropped step without serializing it
Once a step has been dropped, or the step count is full, push serialized
each later step only to count it; a file.open step holds a whole file. The
checks that need no size come first.
2026-10-23 23:08:36 -04:00
prxnvt 456cf73886 Engine: a headless call that fails for want of a file is not recorded
file.open with no file succeeds by queuing a dialog, which execute_headless
turns into an error for callers with no UI; the recording kept the step.
Recorder::truncate forgets it and keeps the byte count right. Regression test.
2026-10-23 20:08:40 -04:00
prxnvt a8e8bf851e Engine: the recording buffer is bounded in bytes and keeps the start of a recording
The buffer kept at most 100,000 steps but each step keeps its full parameters, and a file.open step holds the whole file as base64, so a recording of a few opens of a large workbook kept tens of MB alive. Like the journal, the buffer now also stops at 64 MB of steps serialized as JSON. A step that does not fit is counted as dropped, and once a step is dropped every later one is too, so what the buffer holds is always how the recording began, never a sequence with gaps.
2026-10-23 16:17:57 -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