refactor(command): pre-resolve cell key and grid dimensions in CmdContext
Refactor command system to pre-resolve cell key and grid dimensions in CmdContext, eliminating repeated GridLayout construction. Key changes: - Add cell_key, row_count, col_count to CmdContext - Replace generic CmdRegistry::register with register/register_pure/register_nullary - Cell commands (clear-cell, yank, paste) now take explicit CellKey - Update keymap dispatch to use new interactive() method - Special-case "search" buffer in SetBuffer effect - Update tests to populate new context fields This reduces code duplication and makes command execution more efficient by computing layout once at context creation time. Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -165,7 +165,7 @@ impl Keymap {
|
|||||||
let binding = self.lookup(key, mods)?;
|
let binding = self.lookup(key, mods)?;
|
||||||
match binding {
|
match binding {
|
||||||
Binding::Cmd { name, args } => {
|
Binding::Cmd { name, args } => {
|
||||||
let cmd = registry.parse(name, args).ok()?;
|
let cmd = registry.interactive(name, args, ctx).ok()?;
|
||||||
Some(cmd.execute(ctx))
|
Some(cmd.execute(ctx))
|
||||||
}
|
}
|
||||||
Binding::Prefix(sub) => Some(vec![Box::new(SetTransientKeymap(sub.clone()))]),
|
Binding::Prefix(sub) => Some(vec![Box::new(SetTransientKeymap(sub.clone()))]),
|
||||||
@ -267,7 +267,7 @@ impl KeymapSet {
|
|||||||
normal.bind_args(KeyCode::Char('u'), ctrl, "scroll-rows", vec!["-5".into()]);
|
normal.bind_args(KeyCode::Char('u'), ctrl, "scroll-rows", vec!["-5".into()]);
|
||||||
|
|
||||||
// Cell operations
|
// Cell operations
|
||||||
normal.bind(KeyCode::Char('x'), none, "clear-selected-cell");
|
normal.bind(KeyCode::Char('x'), none, "clear-cell");
|
||||||
normal.bind(KeyCode::Char('p'), none, "paste");
|
normal.bind(KeyCode::Char('p'), none, "paste");
|
||||||
|
|
||||||
// View
|
// View
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use crate::import::wizard::ImportWizard;
|
|||||||
use crate::model::cell::CellValue;
|
use crate::model::cell::CellValue;
|
||||||
use crate::model::Model;
|
use crate::model::Model;
|
||||||
use crate::persistence;
|
use crate::persistence;
|
||||||
|
use crate::view::GridLayout;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum AppMode {
|
pub enum AppMode {
|
||||||
@ -101,6 +102,8 @@ impl App {
|
|||||||
|
|
||||||
pub fn cmd_context(&self, key: KeyCode, mods: KeyModifiers) -> CmdContext<'_> {
|
pub fn cmd_context(&self, key: KeyCode, mods: KeyModifiers) -> CmdContext<'_> {
|
||||||
let view = self.model.active_view();
|
let view = self.model.active_view();
|
||||||
|
let layout = GridLayout::new(&self.model, view);
|
||||||
|
let (sel_row, sel_col) = view.selected;
|
||||||
CmdContext {
|
CmdContext {
|
||||||
model: &self.model,
|
model: &self.model,
|
||||||
mode: &self.mode,
|
mode: &self.mode,
|
||||||
@ -120,6 +123,9 @@ impl App {
|
|||||||
cat_panel_cursor: self.cat_panel_cursor,
|
cat_panel_cursor: self.cat_panel_cursor,
|
||||||
view_panel_cursor: self.view_panel_cursor,
|
view_panel_cursor: self.view_panel_cursor,
|
||||||
tile_cat_idx: self.tile_cat_idx,
|
tile_cat_idx: self.tile_cat_idx,
|
||||||
|
cell_key: layout.cell_key(sel_row, sel_col),
|
||||||
|
row_count: layout.row_count(),
|
||||||
|
col_count: layout.col_count(),
|
||||||
key_code: key,
|
key_code: key,
|
||||||
key_modifiers: mods,
|
key_modifiers: mods,
|
||||||
}
|
}
|
||||||
@ -220,11 +226,26 @@ mod tests {
|
|||||||
app.apply_effects(effects);
|
app.apply_effects(effects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enter_advance_cmd(app: &App) -> crate::command::cmd::EnterAdvance {
|
||||||
|
use crate::command::cmd::CursorState;
|
||||||
|
let view = app.model.active_view();
|
||||||
|
let cursor = CursorState {
|
||||||
|
row: view.selected.0,
|
||||||
|
col: view.selected.1,
|
||||||
|
row_count: 3,
|
||||||
|
col_count: 2,
|
||||||
|
row_offset: 0,
|
||||||
|
col_offset: 0,
|
||||||
|
};
|
||||||
|
crate::command::cmd::EnterAdvance { cursor }
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn enter_advance_moves_down_within_column() {
|
fn enter_advance_moves_down_within_column() {
|
||||||
let mut app = two_col_model();
|
let mut app = two_col_model();
|
||||||
app.model.active_view_mut().selected = (0, 0);
|
app.model.active_view_mut().selected = (0, 0);
|
||||||
run_cmd(&mut app, &crate::command::cmd::EnterAdvance);
|
let cmd = enter_advance_cmd(&app);
|
||||||
|
run_cmd(&mut app, &cmd);
|
||||||
assert_eq!(app.model.active_view().selected, (1, 0));
|
assert_eq!(app.model.active_view().selected, (1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +254,8 @@ mod tests {
|
|||||||
let mut app = two_col_model();
|
let mut app = two_col_model();
|
||||||
// row_max = 2 (A,B,C), col 0 → should wrap to (0, 1)
|
// row_max = 2 (A,B,C), col 0 → should wrap to (0, 1)
|
||||||
app.model.active_view_mut().selected = (2, 0);
|
app.model.active_view_mut().selected = (2, 0);
|
||||||
run_cmd(&mut app, &crate::command::cmd::EnterAdvance);
|
let cmd = enter_advance_cmd(&app);
|
||||||
|
run_cmd(&mut app, &cmd);
|
||||||
assert_eq!(app.model.active_view().selected, (0, 1));
|
assert_eq!(app.model.active_view().selected, (0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +263,8 @@ mod tests {
|
|||||||
fn enter_advance_stays_at_bottom_right() {
|
fn enter_advance_stays_at_bottom_right() {
|
||||||
let mut app = two_col_model();
|
let mut app = two_col_model();
|
||||||
app.model.active_view_mut().selected = (2, 1);
|
app.model.active_view_mut().selected = (2, 1);
|
||||||
run_cmd(&mut app, &crate::command::cmd::EnterAdvance);
|
let cmd = enter_advance_cmd(&app);
|
||||||
|
run_cmd(&mut app, &cmd);
|
||||||
assert_eq!(app.model.active_view().selected, (2, 1));
|
assert_eq!(app.model.active_view().selected, (2, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -289,9 +289,14 @@ pub struct SetBuffer {
|
|||||||
}
|
}
|
||||||
impl Effect for SetBuffer {
|
impl Effect for SetBuffer {
|
||||||
fn apply(&self, app: &mut App) {
|
fn apply(&self, app: &mut App) {
|
||||||
|
// "search" is special — it writes to search_query for backward compat
|
||||||
|
if self.name == "search" {
|
||||||
|
app.search_query = self.value.clone();
|
||||||
|
} else {
|
||||||
app.buffers.insert(self.name.clone(), self.value.clone());
|
app.buffers.insert(self.name.clone(), self.value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SetTileCatIdx(pub usize);
|
pub struct SetTileCatIdx(pub usize);
|
||||||
|
|||||||
Reference in New Issue
Block a user