feat(command): add smart edit-or-drill for aggregated cells
Introduce EditOrDrill command that intelligently handles editing based on cell type. When cursor is on an aggregated pivot cell (categories on Axis::None, no records mode), it drills into the cell. Otherwise, it enters edit mode with the current displayed value. The 'i' and 'a' keys now trigger edit-or-drill instead of enter-edit-mode. Aggregated cells are styled in italic to signal that drilling is required for editing. Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
This commit is contained in:
@ -633,6 +633,40 @@ impl Cmd for EnterEditMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Smart dispatch for i/a: if the cursor is on an aggregated pivot cell
|
||||||
|
/// (categories on `Axis::None`, no records mode), drill into it instead of
|
||||||
|
/// editing. Otherwise enter edit mode with the current displayed value.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EditOrDrill;
|
||||||
|
impl Cmd for EditOrDrill {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"edit-or-drill"
|
||||||
|
}
|
||||||
|
fn execute(&self, ctx: &CmdContext) -> Vec<Box<dyn Effect>> {
|
||||||
|
let is_aggregated = ctx.records_col.is_none() && !ctx.none_cats.is_empty();
|
||||||
|
if is_aggregated {
|
||||||
|
let Some(key) = ctx.cell_key.clone() else {
|
||||||
|
return vec![effect::set_status(
|
||||||
|
"cannot drill — no cell at cursor",
|
||||||
|
)];
|
||||||
|
};
|
||||||
|
return DrillIntoCell { key }.execute(ctx);
|
||||||
|
}
|
||||||
|
// Edit path: prefer records display value (includes pending edits),
|
||||||
|
// else the underlying cell's stored value.
|
||||||
|
let initial_value = if let Some(v) = &ctx.records_value {
|
||||||
|
v.clone()
|
||||||
|
} else {
|
||||||
|
ctx.cell_key
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|k| ctx.model.get_cell(k).cloned())
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.unwrap_or_default()
|
||||||
|
};
|
||||||
|
EnterEditMode { initial_value }.execute(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Typewriter-style advance: move down, wrap to top of next column at bottom.
|
/// Typewriter-style advance: move down, wrap to top of next column at bottom.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EnterAdvance {
|
pub struct EnterAdvance {
|
||||||
@ -2341,6 +2375,7 @@ pub fn default_registry() -> CmdRegistry {
|
|||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
r.register_nullary(|| Box::new(EditOrDrill));
|
||||||
r.register_nullary(|| Box::new(EnterExportPrompt));
|
r.register_nullary(|| Box::new(EnterExportPrompt));
|
||||||
r.register_nullary(|| Box::new(EnterFormulaEdit));
|
r.register_nullary(|| Box::new(EnterFormulaEdit));
|
||||||
r.register_nullary(|| Box::new(EnterTileSelect));
|
r.register_nullary(|| Box::new(EnterTileSelect));
|
||||||
|
|||||||
@ -331,9 +331,9 @@ impl KeymapSet {
|
|||||||
);
|
);
|
||||||
normal.bind(KeyCode::Tab, none, "cycle-panel-focus");
|
normal.bind(KeyCode::Tab, none, "cycle-panel-focus");
|
||||||
|
|
||||||
// Editing entry
|
// Editing entry — i/a drill into aggregated cells, else edit
|
||||||
normal.bind(KeyCode::Char('i'), none, "enter-edit-mode");
|
normal.bind(KeyCode::Char('i'), none, "edit-or-drill");
|
||||||
normal.bind(KeyCode::Char('a'), none, "enter-edit-mode");
|
normal.bind(KeyCode::Char('a'), none, "edit-or-drill");
|
||||||
normal.bind(KeyCode::Enter, none, "enter-advance");
|
normal.bind(KeyCode::Enter, none, "enter-advance");
|
||||||
normal.bind(KeyCode::Char('e'), ctrl, "enter-export-prompt");
|
normal.bind(KeyCode::Char('e'), ctrl, "enter-export-prompt");
|
||||||
|
|
||||||
|
|||||||
@ -402,7 +402,13 @@ impl<'a> GridWidget<'a> {
|
|||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
.contains(&self.search_query.to_lowercase());
|
.contains(&self.search_query.to_lowercase());
|
||||||
|
|
||||||
let cell_style = if is_selected {
|
// Aggregated cells (pivot view with hidden dims) are
|
||||||
|
// not directly editable — shown in italic to signal
|
||||||
|
// "drill to edit". Records mode cells are always
|
||||||
|
// directly editable, as are plain pivot cells.
|
||||||
|
let is_aggregated = !layout.is_records_mode()
|
||||||
|
&& !layout.none_cats.is_empty();
|
||||||
|
let mut cell_style = if is_selected {
|
||||||
Style::default()
|
Style::default()
|
||||||
.fg(Color::Black)
|
.fg(Color::Black)
|
||||||
.bg(Color::Cyan)
|
.bg(Color::Cyan)
|
||||||
@ -421,6 +427,9 @@ impl<'a> GridWidget<'a> {
|
|||||||
} else {
|
} else {
|
||||||
Style::default()
|
Style::default()
|
||||||
};
|
};
|
||||||
|
if is_aggregated {
|
||||||
|
cell_style = cell_style.add_modifier(Modifier::ITALIC);
|
||||||
|
}
|
||||||
|
|
||||||
buf.set_string(
|
buf.set_string(
|
||||||
x,
|
x,
|
||||||
|
|||||||
Reference in New Issue
Block a user