From 7fea5f67ed6fb5da37054ee2bf4add7347fddec3 Mon Sep 17 00:00:00 2001 From: Edward Langley Date: Thu, 9 Apr 2026 14:24:39 -0700 Subject: [PATCH] refactor(command): improve formula commitment and buffer management Refactor command execution and buffer management. - `CommitFormula` now defaults to targeting `_Measure` . - `CommitFormula` no longer automatically clears the buffer; buffer clearing is now handled by keymap sequences. - Added `ClearBufferCmd` to the command registry. - Updated `AddFormulaCmd` to support optional target category. - Added `SetBuffer` effect to allow clearing buffers. Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL) --- src/command/cmd/commit.rs | 43 ++++++++++++++-------------------- src/command/cmd/effect_cmds.rs | 30 +++++++++++++++++++++--- src/command/cmd/registry.rs | 1 + src/ui/effect.rs | 17 ++++++++++++++ 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/command/cmd/commit.rs b/src/command/cmd/commit.rs index 5783761..6bcd09a 100644 --- a/src/command/cmd/commit.rs +++ b/src/command/cmd/commit.rs @@ -34,8 +34,10 @@ mod tests { ); } + /// Formulas always target _Measure by default, even when no regular + /// categories exist. _Measure is a virtual category that always exists. #[test] - fn commit_formula_without_regular_categories_shows_status() { + fn commit_formula_without_regular_categories_targets_measure() { let m = Model::new("Empty"); let layout = make_layout(&m); let reg = make_registry(); @@ -46,12 +48,12 @@ mod tests { let effects = CommitFormula.execute(&ctx); let dbg = effects_debug(&effects); assert!( - !dbg.contains("AddFormula"), - "Should not add formula when only virtual categories exist, got: {dbg}" + dbg.contains("AddFormula"), + "Should add formula targeting _Measure, got: {dbg}" ); assert!( - dbg.contains("Add at least one category first"), - "Expected status message, got: {dbg}" + dbg.contains("_Measure"), + "target_category should be _Measure, got: {dbg}" ); } @@ -220,30 +222,23 @@ impl Cmd for CommitFormula { } fn execute(&self, ctx: &CmdContext) -> Vec> { let buf = ctx.buffers.get("formula").cloned().unwrap_or_default(); - let first_cat = ctx - .model - .regular_category_names() - .into_iter() - .next() - .map(String::from); let mut effects: Vec> = Vec::new(); - if let Some(cat) = first_cat { - effects.push(Box::new(effect::AddFormula { - raw: buf, - target_category: cat, - })); - effects.push(effect::mark_dirty()); - effects.push(effect::set_status("Formula added")); - } else { - effects.push(effect::set_status("Add at least one category first.")); - } + // Default formula target to _Measure (the virtual measure category). + // _Measure dynamically includes all formula targets. + effects.push(Box::new(effect::AddFormula { + raw: buf, + target_category: "_Measure".to_string(), + })); + effects.push(effect::mark_dirty()); + effects.push(effect::set_status("Formula added")); effects.push(effect::change_mode(AppMode::FormulaPanel)); effects } } /// Shared helper: read a buffer, trim it, and if non-empty, produce add + dirty -/// + status + clear-buffer effects. If empty, return to CategoryPanel. +/// + status effects. If empty, return to CategoryPanel. +/// Buffer clearing is handled by the keymap (Enter → [commit, clear-buffer]). fn commit_add_from_buffer( ctx: &CmdContext, buffer_name: &str, @@ -262,10 +257,6 @@ fn commit_add_from_buffer( add, effect::mark_dirty(), effect::set_status(status_msg(&trimmed)), - Box::new(effect::SetBuffer { - name: buffer_name.to_string(), - value: String::new(), - }), ] } diff --git a/src/command/cmd/effect_cmds.rs b/src/command/cmd/effect_cmds.rs index e020a43..5132328 100644 --- a/src/command/cmd/effect_cmds.rs +++ b/src/command/cmd/effect_cmds.rs @@ -200,11 +200,35 @@ effect_cmd!( effect_cmd!( AddFormulaCmd, "add-formula", - |args: &[String]| require_args("add-formula", args, 2), + |args: &[String]| { + if args.is_empty() || args.len() > 2 { + return Err(format!("add-formula requires 1-2 argument(s), got {}", args.len())); + } + Ok(()) + }, |args: &Vec, _ctx: &CmdContext| -> Vec> { + // 1 arg: formula text (target_category defaults to _Measure) + // 2 args: target_category, formula text + let (cat, raw) = if args.len() == 2 { + (args[0].clone(), args[1].clone()) + } else { + ("_Measure".to_string(), args[0].clone()) + }; vec![Box::new(effect::AddFormula { - target_category: args[0].clone(), - raw: args[1].clone(), + target_category: cat, + raw, + })] + } +); + +effect_cmd!( + ClearBufferCmd, + "clear-buffer", + |args: &[String]| require_args("clear-buffer", args, 1), + |args: &Vec, _ctx: &CmdContext| -> Vec> { + vec![Box::new(effect::SetBuffer { + name: args[0].clone(), + value: String::new(), })] } ); diff --git a/src/command/cmd/registry.rs b/src/command/cmd/registry.rs index ec38769..7e61141 100644 --- a/src/command/cmd/registry.rs +++ b/src/command/cmd/registry.rs @@ -25,6 +25,7 @@ pub fn default_registry() -> CmdRegistry { r.register_pure(&AddItemsCmd(vec![]), AddItemsCmd::parse); r.register_pure(&AddItemInGroupCmd(vec![]), AddItemInGroupCmd::parse); r.register_pure(&SetCellCmd(vec![]), SetCellCmd::parse); + r.register_pure(&ClearBufferCmd(vec![]), ClearBufferCmd::parse); r.register( &ClearCellCommand { key: CellKey::new(vec![]), diff --git a/src/ui/effect.rs b/src/ui/effect.rs index 60f26f4..a06c175 100644 --- a/src/ui/effect.rs +++ b/src/ui/effect.rs @@ -1252,6 +1252,23 @@ mod tests { assert_eq!(app.mode, AppMode::Help); } + /// SetBuffer with empty value clears the buffer (used by clear-buffer command + /// in keymap sequences after commit). + #[test] + fn set_buffer_empty_clears() { + let mut app = test_app(); + app.buffers.insert("formula".to_string(), "old text".to_string()); + SetBuffer { + name: "formula".to_string(), + value: String::new(), + } + .apply(&mut app); + assert_eq!( + app.buffers.get("formula").map(|s| s.as_str()), + Some(""), + ); + } + #[test] fn set_status_effect() { let mut app = test_app();