refactor: use data_col_to_visual via group_for helpers, add column group toggle

Add row_group_for/col_group_for to GridLayout, replacing inline
backward-search logic. Refactor grid renderer to use col_group_for
instead of pre-filtering col_items. Add gz keybinding for column
group collapse toggle, symmetric with z for rows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Edward Langley
2026-04-02 10:21:41 -07:00
parent 5136aadd86
commit edd6431444
4 changed files with 174 additions and 41 deletions

View File

@ -395,6 +395,10 @@ impl App {
view.selected = (0, view.selected.1);
view.row_offset = 0;
}
// gz = toggle column group under cursor
('g', KeyCode::Char('z')) => {
self.toggle_col_group_under_cursor();
}
// yy = yank current cell
('y', KeyCode::Char('y')) => {
if let Some(key) = self.selected_cell_key() {
@ -1222,28 +1226,35 @@ impl App {
fn toggle_group_under_cursor(&mut self) {
let layout = GridLayout::new(&self.model, self.model.active_view());
let sel_row = self.model.active_view().selected.0;
let Some(vi) = layout.data_row_to_visual(sel_row) else {
let Some((cat, group)) = layout.row_group_for(sel_row) else {
return;
};
let group = layout.row_items[..vi].iter().rev().find_map(|e| {
if let AxisEntry::GroupHeader {
cat_name,
group_name,
} = e
{
Some((cat_name.clone(), group_name.clone()))
} else {
None
}
});
if let Some((cat, group)) = group {
let cmd = Command::ToggleGroup {
category: cat,
group,
};
command::dispatch(&mut self.model, &cmd);
self.dirty = true;
let cmd = Command::ToggleGroup {
category: cat,
group,
};
command::dispatch(&mut self.model, &cmd);
self.dirty = true;
}
fn toggle_col_group_under_cursor(&mut self) {
let layout = GridLayout::new(&self.model, self.model.active_view());
let sel_col = self.model.active_view().selected.1;
let Some((cat, group)) = layout.col_group_for(sel_col) else {
return;
};
let cmd = Command::ToggleGroup {
category: cat,
group,
};
command::dispatch(&mut self.model, &cmd);
// Clamp selection if col_count shrank
let new_count = GridLayout::new(&self.model, self.model.active_view()).col_count();
let view = self.model.active_view_mut();
if view.selected.1 >= new_count && new_count > 0 {
view.selected.1 = new_count - 1;
}
self.dirty = true;
}
fn hide_selected_row_item(&mut self) {