diff --git a/crates/engine/src/macros/run.rs b/crates/engine/src/macros/run.rs index d9c714352..bff4e0b90 100644 --- a/crates/engine/src/macros/run.rs +++ b/crates/engine/src/macros/run.rs @@ -520,7 +520,8 @@ impl Guard { if Arc::ptr_eq(ps, sa) { continue; } - let in_input = |c: CellRef| inputs.iter().any(|(_, p, _)| p.sheet == si && p.range.contains(c)); + // The inputs have followed their cells, so they are on the sheet's index now. + let in_input = |c: CellRef| inputs.iter().any(|(_, p, _)| p.sheet == ai && p.range.contains(c)); let mut hit: Vec = ps .cells .diff(&sa.cells) diff --git a/crates/engine/src/tests/macros.rs b/crates/engine/src/tests/macros.rs index eaa4f527b..57307ee8c 100644 --- a/crates/engine/src/tests/macros.rs +++ b/crates/engine/src/tests/macros.rs @@ -205,10 +205,21 @@ fn inputs_and_the_output_follow_their_cells_when_a_step_moves_them() { {"command": "home.insertSheet", "params": {"name": "Summary", "before": 0}}, {"command": "cell.set", "params": {"cell": "Input", "input": "x"}} ]); - put(&mut s, json!({"name": "Front", "inputs": [{"name": "Input", "kind": "cell"}], "output": {"onConflict": "overwrite"}, "steps": steps})); + put( + &mut s, + json!({"name": "Front", "inputs": [{"name": "Input", "kind": "cell"}], "output": {"onConflict": "overwrite"}, "steps": steps.clone()}), + ); s.execute("macro.run", json!({"name": "Front", "inputs": "Sheet1!B2"})).unwrap(); assert_eq!((on(&s, "Sheet1", "B2"), on(&s, "Summary", "B2")), ("x".into(), "".into())); + // Data in the input: the step writes into its own input, which isn't data written over, on + // the input's sheet wherever it moved. + let mut s = super::s(); + set(&mut s, "B2", "held"); + put(&mut s, json!({"name": "Front", "inputs": [{"name": "Input", "kind": "cell"}], "output": {"onConflict": "fail"}, "steps": steps})); + s.execute("macro.run", json!({"name": "Front", "inputs": "Sheet1!B2"})).unwrap(); + assert_eq!(on(&s, "Sheet1", "B2"), "x"); + // Rows inserted above: the input and the output move down with their cells. let mut s = super::s(); set(&mut s, "B5", "in"); diff --git a/docs/macros.md b/docs/macros.md index c3a9c2198..fe169fb3b 100644 --- a/docs/macros.md +++ b/docs/macros.md @@ -9,8 +9,11 @@ error (a file it already wrote stays), checks where its results will land before and does not touch files without permission. Agents run macros with `macro.run` like any other command. -This page describes the macro format, its tokens, and running and checking macros. The engine has -no macro debugger, recorder or management commands in this version, and no macro interface. +This page describes the macro format, its tokens, and running and checking macros. `macro.run` +checks the macro, its inputs, its parameters and the policy before it runs, works out where it +writes, and checks each step as it runs; `macro.check` reports what a run would do without +running it. The engine has no macro debugger, recorder or management commands in this version, +and no macro interface. ## A macro @@ -123,8 +126,9 @@ refused rather than read as the header. 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: - both compare cells by place. + 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,