diff --git a/crates/engine/src/cmd/edit.rs b/crates/engine/src/cmd/edit.rs index fb00563f1..23cc3e544 100644 --- a/crates/engine/src/cmd/edit.rs +++ b/crates/engine/src/cmd/edit.rs @@ -196,8 +196,11 @@ fn cell_set(s: &mut Session, p: &Json) -> Result { Some(c) => c, None => s.doc()?.selection.active, }; - let input = - str_param(p, "input").or_else(|| str_param(p, "value")).map(str::to_string).or_else(|| p.get("value").map(json_to_input)).unwrap_or_default(); + let input = str_param(p, "input") + .or_else(|| str_param(p, "value")) + .map(str::to_string) + .or_else(|| p.get("value").map(json_to_input)) + .ok_or_else(|| bad("cell.set", "missing `input` (or `value`)"))?; let array = bool_param(p, "array").unwrap_or(false); let d = s.doc()?; if let Some(sh) = d.wb.sheet(sheet) diff --git a/crates/mcp/src/tests.rs b/crates/mcp/src/tests.rs index cf590bedb..1d4abb40c 100644 --- a/crates/mcp/src/tests.rs +++ b/crates/mcp/src/tests.rs @@ -339,6 +339,18 @@ fn serve_loop_over_buffers() { assert!(lines[2]["result"]["content"][0]["text"].as_str().unwrap().contains("42")); } +#[test] +fn cell_set_without_input_is_error() { + let mut s = server(); + ok(&mut s, "set_cell", json!({"cell": "B2", "input": "keep"})); + fails(&mut s, "execute_command", json!({"command": "cell.set", "params": {"cell": "B2"}})); + fails(&mut s, "execute_command", json!({"command": "cell.set", "params": {}})); + assert_eq!(ok(&mut s, "get_cell", json!({"cell": "B2"}))["text"], "keep"); + // An explicit empty string still clears. + ok(&mut s, "execute_command", json!({"command": "cell.set", "params": {"cell": "B2", "input": ""}})); + assert_eq!(ok(&mut s, "get_cell", json!({"cell": "B2"}))["text"], ""); +} + #[test] fn remote_backend_over_tcp() { // A fake app: answers engine.execute by running a headless session; closes after the first