refactor: make active_view and axis_of infallible

Both functions previously returned Option despite their invariants
guaranteeing a value: active_view always names an existing view
(maintained by new/switch_view/delete_view), and axis_of only returns
None for categories never registered with the view (a programming error).

Callers no longer need to handle the impossible None case, eliminating
~15 match/if-let Option guards across app.rs, dispatch.rs, grid.rs,
tile_bar.rs, and category_panel.rs.

Also adds Model::evaluate_f64 (returns 0.0 for empty cells) and collapses
the double match-on-axis pattern in tile_bar/category_panel into a single
axis_display(Axis) helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ed L
2026-03-24 09:00:25 -07:00
parent a2e519efcc
commit 6038cb2d81
9 changed files with 168 additions and 208 deletions

View File

@ -9,6 +9,14 @@ use crate::model::Model;
use crate::view::Axis;
use crate::ui::app::AppMode;
fn axis_display(axis: Axis) -> (&'static str, Color) {
match axis {
Axis::Row => ("", Color::Green),
Axis::Column => ("", Color::Blue),
Axis::Page => ("", Color::Magenta),
}
}
pub struct TileBar<'a> {
pub model: &'a Model,
pub mode: &'a AppMode,
@ -22,10 +30,7 @@ impl<'a> TileBar<'a> {
impl<'a> Widget for TileBar<'a> {
fn render(self, area: Rect, buf: &mut Buffer) {
let view = match self.model.active_view() {
Some(v) => v,
None => return,
};
let view = self.model.active_view();
let selected_cat_idx = if let AppMode::TileSelect { cat_idx } = self.mode {
Some(*cat_idx)
@ -39,26 +44,14 @@ impl<'a> Widget for TileBar<'a> {
let cat_names: Vec<&str> = self.model.category_names();
for (i, cat_name) in cat_names.iter().enumerate() {
let axis = view.axis_of(cat_name);
let axis_symbol = match axis {
Some(Axis::Row) => "",
Some(Axis::Column) => "",
Some(Axis::Page) => "",
None => "",
};
let (axis_symbol, axis_color) = axis_display(view.axis_of(cat_name));
let label = format!(" [{cat_name} {axis_symbol}] ");
let is_selected = selected_cat_idx == Some(i);
let style = if is_selected {
Style::default().fg(Color::Black).bg(Color::Cyan).add_modifier(Modifier::BOLD)
} else {
match axis {
Some(Axis::Row) => Style::default().fg(Color::Green),
Some(Axis::Column) => Style::default().fg(Color::Blue),
Some(Axis::Page) => Style::default().fg(Color::Magenta),
None => Style::default().fg(Color::DarkGray),
}
Style::default().fg(axis_color)
};
if x + label.len() as u16 > area.x + area.width { break; }