feat(cmd): allow direct commit of synthetic records in records mode
Allow synthetic record edits to be applied directly to the model when not in drill mode, whereas they remain staged in drill state when a drill snapshot is active. This enables editing of records in plain records view. Additionally, add validation to prevent creating records with empty coordinates in both direct commits and when applying staged drill edits. Includes regression tests for persistence in blank models, drill state staging, and empty coordinate prevention. Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-31B-it-UD-Q4_K_XL.gguf)
This commit is contained in:
@ -137,14 +137,70 @@ mod tests {
|
||||
// ── Commit commands (mode-specific buffer consumers) ────────────────────────
|
||||
|
||||
/// Commit a cell value: for synthetic records keys, stage in drill pending edits
|
||||
/// or apply directly; for real keys, write to the model.
|
||||
fn commit_cell_value(key: &CellKey, value: &str, effects: &mut Vec<Box<dyn Effect>>) {
|
||||
/// in drill mode, or apply directly in plain records mode; for real keys, write
|
||||
/// to the model.
|
||||
fn commit_cell_value(
|
||||
ctx: &CmdContext,
|
||||
key: &CellKey,
|
||||
value: &str,
|
||||
effects: &mut Vec<Box<dyn Effect>>,
|
||||
) {
|
||||
if let Some((record_idx, col_name)) = crate::view::synthetic_record_info(key) {
|
||||
effects.push(Box::new(effect::SetDrillPendingEdit {
|
||||
record_idx,
|
||||
col_name,
|
||||
new_value: value.to_string(),
|
||||
if ctx.has_drill_state {
|
||||
effects.push(Box::new(effect::SetDrillPendingEdit {
|
||||
record_idx,
|
||||
col_name,
|
||||
new_value: value.to_string(),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
let Some((orig_key, _)) = ctx
|
||||
.layout
|
||||
.records
|
||||
.as_ref()
|
||||
.and_then(|records| records.get(record_idx))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if col_name == "Value" {
|
||||
if value.is_empty() {
|
||||
effects.push(Box::new(effect::ClearCell(orig_key.clone())));
|
||||
} else if let Ok(n) = value.parse::<f64>() {
|
||||
effects.push(Box::new(effect::SetCell(
|
||||
orig_key.clone(),
|
||||
CellValue::Number(n),
|
||||
)));
|
||||
} else {
|
||||
effects.push(Box::new(effect::SetCell(
|
||||
orig_key.clone(),
|
||||
CellValue::Text(value.to_string()),
|
||||
)));
|
||||
}
|
||||
effects.push(effect::mark_dirty());
|
||||
return;
|
||||
}
|
||||
|
||||
if value.is_empty() {
|
||||
effects.push(effect::set_status("Record coordinates cannot be empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(existing_value) = ctx.model.get_cell(orig_key).cloned() else {
|
||||
return;
|
||||
};
|
||||
effects.push(Box::new(effect::ClearCell(orig_key.clone())));
|
||||
effects.push(Box::new(effect::AddItem {
|
||||
category: col_name.clone(),
|
||||
item: value.to_string(),
|
||||
}));
|
||||
effects.push(Box::new(effect::SetCell(
|
||||
orig_key.clone().with(col_name, value),
|
||||
existing_value,
|
||||
)));
|
||||
effects.push(effect::mark_dirty());
|
||||
return;
|
||||
} else if value.is_empty() {
|
||||
effects.push(Box::new(effect::ClearCell(key.clone())));
|
||||
effects.push(effect::mark_dirty());
|
||||
@ -187,7 +243,7 @@ impl Cmd for CommitAndAdvance {
|
||||
}
|
||||
fn execute(&self, ctx: &CmdContext) -> Vec<Box<dyn Effect>> {
|
||||
let mut effects: Vec<Box<dyn Effect>> = Vec::new();
|
||||
commit_cell_value(&self.key, &self.value, &mut effects);
|
||||
commit_cell_value(ctx, &self.key, &self.value, &mut effects);
|
||||
match self.advance {
|
||||
AdvanceDir::Down => {
|
||||
let adv = EnterAdvance {
|
||||
|
||||
Reference in New Issue
Block a user