diff --git a/crates/engine/src/cmd/macros.rs b/crates/engine/src/cmd/macros.rs index cd1f36c67..1af881587 100644 --- a/crates/engine/src/cmd/macros.rs +++ b/crates/engine/src/cmd/macros.rs @@ -223,6 +223,8 @@ fn save_recording(s: &mut Session, p: &Json, rec: &crate::record::Recorder, star None => crate::macros::next_name(&wb), }; let mut converted = crate::macros::recorder::convert(&name, &start, &rec.steps, &wb); + // Steps past the macro limit are left out and counted with the ones the recorder dropped. + let cut = converted.mac.steps.len().saturating_sub(gridcraft_model::MAX_MACRO_STEPS); converted.mac.steps.truncate(gridcraft_model::MAX_MACRO_STEPS); if let Some(desc) = str_param(p, "description") { converted.mac.description = desc.chars().take(gridcraft_model::MAX_MACRO_TEXT).collect(); @@ -235,5 +237,7 @@ fn save_recording(s: &mut Session, p: &Json, rec: &crate::record::Recorder, star let saved = s.execute("macro.save", json!({"macro": crate::macros::macro_json(&converted.mac), "replace": false})); s.set_active(active); saved?; - Ok(json!({"recording": false, "saved": name, "steps": steps, "dropped": rec.dropped, "skipped": converted.skipped, "inputs": inputs})) + Ok( + json!({"recording": false, "saved": name, "steps": steps, "dropped": rec.dropped.saturating_add(cut), "skipped": converted.skipped, "inputs": inputs}), + ) } diff --git a/crates/engine/src/tests/macros.rs b/crates/engine/src/tests/macros.rs index 0339ad5ee..3f0901c94 100644 --- a/crates/engine/src/tests/macros.rs +++ b/crates/engine/src/tests/macros.rs @@ -1141,3 +1141,25 @@ fn a_name_given_when_recording_stops_never_replaces_a_macro() { assert_eq!(recorded(&mut s, "Tidy"), ["cell.set {\"cell\":\"Z9\",\"input\":\"mine\"}"]); assert_eq!(recorded(&mut s, "tidy (2)"), ["cell.set {\"cell\":\"A1\",\"input\":\"recorded\"}"]); } + +#[test] +fn steps_past_the_macro_limit_are_counted_as_dropped() { + let mut s = s(); + s.execute("macro.record", json!({"relative": false})).unwrap(); + let (doc, selection) = (s.doc().unwrap().uid, s.doc().unwrap().selection.clone()); + let rec = s.recorder.as_mut().unwrap(); + for i in 0..gridcraft_model::MAX_MACRO_STEPS + 5 { + rec.push(crate::record::RecordedStep { + doc, + sheet: 0, + sheet_name: "Sheet1".into(), + selection: selection.clone(), + id: "cell.set".into(), + params: json!({"cell": "A1", "input": i.to_string()}), + }); + } + rec.dropped = 3; + let r = s.execute("macro.record", json!({"stop": true, "name": "Long"})).unwrap(); + assert_eq!(r["steps"], gridcraft_model::MAX_MACRO_STEPS); + assert_eq!(r["dropped"], 8, "{r}"); +} diff --git a/docs/macros.md b/docs/macros.md index 9f1461fc2..6cc67d4e8 100644 --- a/docs/macros.md +++ b/docs/macros.md @@ -123,10 +123,11 @@ of the step that just ran, and the cells changed so far. stopping never replaces a macro). 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), -recording goes on, so stopping again keeps what was recorded. 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. Toggles such as Bold are recorded with the state they set +recording goes on, so stopping again keeps what was recorded. A recording keeps up to 100,000 +commands and a macro up to 10,000 steps; steps past either limit 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. Toggles such as Bold are recorded with the state they set (`"on": true`), so playing them back sets them rather than flipping them. Commands a macro may not run are left out and listed in the result, 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