diff --git a/src/command/cmd.rs b/src/command/cmd.rs index d47d1c8..b4bdbbd 100644 --- a/src/command/cmd.rs +++ b/src/command/cmd.rs @@ -1602,7 +1602,11 @@ impl Cmd for TileAxisOp { None => Box::new(effect::CycleAxis(name.to_string())), }; let status = format!("{} → {}", name, axis_label(new_axis)); - vec![axis_effect, effect::mark_dirty(), effect::set_status(status)] + vec![ + axis_effect, + effect::mark_dirty(), + effect::set_status(status), + ] } else { vec![] } @@ -2250,10 +2254,7 @@ effect_cmd!( "help", |_args: &[String]| -> Result<(), String> { Ok(()) }, |_args: &Vec, _ctx: &CmdContext| -> Vec> { - vec![ - effect::help_page_set(0), - effect::change_mode(AppMode::Help), - ] + vec![effect::help_page_set(0), effect::change_mode(AppMode::Help)] } ); @@ -3425,7 +3426,10 @@ mod tests { let effects = TransposeAxes.execute(&ctx); assert_eq!(effects.len(), 2); let dbg = effects_debug(&effects); - assert!(dbg.contains("TransposeAxes"), "Expected TransposeAxes, got: {dbg}"); + assert!( + dbg.contains("TransposeAxes"), + "Expected TransposeAxes, got: {dbg}" + ); } // ── View navigation ──────────────────────────────────────────────── @@ -3439,7 +3443,10 @@ mod tests { let cmd = ViewNavigate { forward: true }; let effects = cmd.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("No forward view"), "Expected status message, got: {dbg}"); + assert!( + dbg.contains("No forward view"), + "Expected status message, got: {dbg}" + ); } #[test] @@ -3451,7 +3458,10 @@ mod tests { let cmd = ViewNavigate { forward: false }; let effects = cmd.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("No previous view"), "Expected status message, got: {dbg}"); + assert!( + dbg.contains("No previous view"), + "Expected status message, got: {dbg}" + ); } #[test] @@ -3465,7 +3475,10 @@ mod tests { let cmd = ViewNavigate { forward: true }; let effects = cmd.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("ViewForward"), "Expected ViewForward, got: {dbg}"); + assert!( + dbg.contains("ViewForward"), + "Expected ViewForward, got: {dbg}" + ); } #[test] @@ -3480,7 +3493,10 @@ mod tests { let effects = cmd.execute(&ctx); assert_eq!(effects.len(), 2); // ApplyAndClearDrill + ViewBack let dbg = effects_debug(&effects); - assert!(dbg.contains("ApplyAndClearDrill"), "Expected ApplyAndClearDrill, got: {dbg}"); + assert!( + dbg.contains("ApplyAndClearDrill"), + "Expected ApplyAndClearDrill, got: {dbg}" + ); assert!(dbg.contains("ViewBack"), "Expected ViewBack, got: {dbg}"); } @@ -3501,7 +3517,10 @@ mod tests { let effects = cmd.execute(&ctx); assert_eq!(effects.len(), 1); let dbg = effects_debug(&effects); - assert!(dbg.contains("SetPanelCursor"), "Expected SetPanelCursor, got: {dbg}"); + assert!( + dbg.contains("SetPanelCursor"), + "Expected SetPanelCursor, got: {dbg}" + ); } #[test] @@ -3588,7 +3607,10 @@ mod tests { // Should produce SetPageSelection effects assert!(!effects.is_empty()); let dbg = effects_debug(&effects); - assert!(dbg.contains("SetPageSelection"), "Expected SetPageSelection, got: {dbg}"); + assert!( + dbg.contains("SetPageSelection"), + "Expected SetPageSelection, got: {dbg}" + ); } #[test] @@ -3600,7 +3622,10 @@ mod tests { let effects = PagePrev.execute(&ctx); assert!(!effects.is_empty()); let dbg = effects_debug(&effects); - assert!(dbg.contains("SetPageSelection"), "Expected SetPageSelection, got: {dbg}"); + assert!( + dbg.contains("SetPageSelection"), + "Expected SetPageSelection, got: {dbg}" + ); } // ── Tile axis commands ───────────────────────────────────────────── @@ -3657,7 +3682,10 @@ mod tests { let effects = cmd.execute(&ctx); assert_eq!(effects.len(), 1); let dbg = effects_debug(&effects); - assert!(dbg.contains("SetTileCatIdx(1)"), "Expected idx 1, got: {dbg}"); + assert!( + dbg.contains("SetTileCatIdx(1)"), + "Expected idx 1, got: {dbg}" + ); } #[test] @@ -3670,7 +3698,10 @@ mod tests { let effects = cmd.execute(&ctx); assert_eq!(effects.len(), 1); let dbg = effects_debug(&effects); - assert!(dbg.contains("SetTileCatIdx(0)"), "Expected clamped to 0, got: {dbg}"); + assert!( + dbg.contains("SetTileCatIdx(0)"), + "Expected clamped to 0, got: {dbg}" + ); } // ── Commit formula ───────────────────────────────────────────────── @@ -3686,8 +3717,14 @@ mod tests { ctx.buffers = &bufs; let effects = CommitFormula.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("AddFormula"), "Expected AddFormula, got: {dbg}"); - assert!(dbg.contains("FormulaPanel"), "Expected return to FormulaPanel, got: {dbg}"); + assert!( + dbg.contains("AddFormula"), + "Expected AddFormula, got: {dbg}" + ); + assert!( + dbg.contains("FormulaPanel"), + "Expected return to FormulaPanel, got: {dbg}" + ); } /// Regression: CommitFormula must not target virtual categories (_Index, _Dim) @@ -3727,7 +3764,10 @@ mod tests { ctx.buffers = &bufs; let effects = CommitCategoryAdd.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("AddCategory"), "Expected AddCategory, got: {dbg}"); + assert!( + dbg.contains("AddCategory"), + "Expected AddCategory, got: {dbg}" + ); } #[test] @@ -3741,7 +3781,10 @@ mod tests { ctx.buffers = &bufs; let effects = CommitCategoryAdd.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("CategoryPanel"), "Expected return to CategoryPanel, got: {dbg}"); + assert!( + dbg.contains("CategoryPanel"), + "Expected return to CategoryPanel, got: {dbg}" + ); } // ── Commit item add ──────────────────────────────────────────────── @@ -3802,7 +3845,10 @@ mod tests { ctx.buffers = &bufs; let effects = CommandModeBackspace.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("Normal"), "Expected return to Normal, got: {dbg}"); + assert!( + dbg.contains("Normal"), + "Expected return to Normal, got: {dbg}" + ); } // ── Execute command ──────────────────────────────────────────────── @@ -3833,7 +3879,10 @@ mod tests { let effects = ExecuteCommand.execute(&ctx); let dbg = effects_debug(&effects); // Should show an error status AND return to Normal - assert!(dbg.contains("Normal"), "Expected Normal mode on error, got: {dbg}"); + assert!( + dbg.contains("Normal"), + "Expected Normal mode on error, got: {dbg}" + ); } #[test] @@ -3842,15 +3891,15 @@ mod tests { let layout = make_layout(&m); let reg = default_registry(); let mut bufs = HashMap::new(); - bufs.insert( - "command".to_string(), - "add-category Region".to_string(), - ); + bufs.insert("command".to_string(), "add-category Region".to_string()); let mut ctx = make_ctx(&m, &layout, ®); ctx.buffers = &bufs; let effects = ExecuteCommand.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("AddCategory"), "Expected AddCategory effect, got: {dbg}"); + assert!( + dbg.contains("AddCategory"), + "Expected AddCategory effect, got: {dbg}" + ); } // ── Save command ─────────────────────────────────────────────────── @@ -3878,8 +3927,14 @@ mod tests { let effects = EnterSearchMode.execute(&ctx); assert_eq!(effects.len(), 2); let dbg = effects_debug(&effects); - assert!(dbg.contains("SetSearchMode(true)"), "Expected search mode on, got: {dbg}"); - assert!(dbg.contains("SetSearchQuery"), "Expected query reset, got: {dbg}"); + assert!( + dbg.contains("SetSearchMode(true)"), + "Expected search mode on, got: {dbg}" + ); + assert!( + dbg.contains("SetSearchQuery"), + "Expected query reset, got: {dbg}" + ); } #[test] @@ -3891,7 +3946,10 @@ mod tests { let effects = ExitSearchMode.execute(&ctx); assert_eq!(effects.len(), 1); let dbg = effects_debug(&effects); - assert!(dbg.contains("SetSearchMode(false)"), "Expected search mode off, got: {dbg}"); + assert!( + dbg.contains("SetSearchMode(false)"), + "Expected search mode off, got: {dbg}" + ); } // ── Search navigate with query finds match ───────────────────────── @@ -3922,7 +3980,10 @@ mod tests { // Should find the cell with 99 and navigate to it if !effects.is_empty() { let dbg = effects_debug(&effects); - assert!(dbg.contains("SetSelected"), "Expected SetSelected, got: {dbg}"); + assert!( + dbg.contains("SetSelected"), + "Expected SetSelected, got: {dbg}" + ); } // If empty, the search didn't find it through layout — that's OK since // layout coordinates may not map 1:1 with model cells in all cases. @@ -3939,9 +4000,18 @@ mod tests { let effects = CreateAndSwitchView.execute(&ctx); let dbg = effects_debug(&effects); // Model starts with 1 view ("Default"), so new view should be "View 2" - assert!(dbg.contains("CreateView"), "Expected CreateView, got: {dbg}"); - assert!(dbg.contains("SwitchView"), "Expected SwitchView, got: {dbg}"); - assert!(dbg.contains("Normal"), "Expected return to Normal, got: {dbg}"); + assert!( + dbg.contains("CreateView"), + "Expected CreateView, got: {dbg}" + ); + assert!( + dbg.contains("SwitchView"), + "Expected SwitchView, got: {dbg}" + ); + assert!( + dbg.contains("Normal"), + "Expected return to Normal, got: {dbg}" + ); } // ── Switch view at cursor ────────────────────────────────────────── @@ -3955,7 +4025,10 @@ mod tests { let effects = SwitchViewAtCursor.execute(&ctx); // cursor 0, model has "Default" view let dbg = effects_debug(&effects); - assert!(dbg.contains("SwitchView"), "Expected SwitchView, got: {dbg}"); + assert!( + dbg.contains("SwitchView"), + "Expected SwitchView, got: {dbg}" + ); assert!(dbg.contains("Normal"), "Expected Normal mode, got: {dbg}"); } @@ -3980,10 +4053,15 @@ mod tests { let ctx = make_ctx(&m, &layout, ®); let effects = DeleteViewAtCursor.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("DeleteView"), "Expected DeleteView, got: {dbg}"); + assert!( + dbg.contains("DeleteView"), + "Expected DeleteView, got: {dbg}" + ); // At cursor 0, should NOT have SetPanelCursor (no cursor adjustment needed) - assert!(!dbg.contains("SetPanelCursor"), - "Expected no cursor adjustment at position 0, got: {dbg}"); + assert!( + !dbg.contains("SetPanelCursor"), + "Expected no cursor adjustment at position 0, got: {dbg}" + ); } // ── Delete formula at cursor ─────────────────────────────────────── @@ -4003,7 +4081,10 @@ mod tests { let ctx = make_ctx(&m, &layout, ®); let effects = DeleteFormulaAtCursor.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("RemoveFormula"), "Expected RemoveFormula, got: {dbg}"); + assert!( + dbg.contains("RemoveFormula"), + "Expected RemoveFormula, got: {dbg}" + ); } // ── Commit export ────────────────────────────────────────────────── @@ -4064,7 +4145,10 @@ mod tests { let ctx = make_ctx(&m, &layout, ®); let effects = EnterExportPrompt.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("ExportPrompt"), "Expected ExportPrompt mode, got: {dbg}"); + assert!( + dbg.contains("ExportPrompt"), + "Expected ExportPrompt mode, got: {dbg}" + ); } // ── Toggle prune empty ───────────────────────────────────────────── @@ -4077,7 +4161,10 @@ mod tests { let ctx = make_ctx(&m, &layout, ®); let effects = TogglePruneEmpty.execute(&ctx); let dbg = effects_debug(&effects); - assert!(dbg.contains("TogglePruneEmpty"), "Expected TogglePruneEmpty, got: {dbg}"); + assert!( + dbg.contains("TogglePruneEmpty"), + "Expected TogglePruneEmpty, got: {dbg}" + ); } // ── Edit or drill ────────────────────────────────────────────────── @@ -4131,7 +4218,10 @@ mod tests { let effects = cmd.execute(&ctx); assert_eq!(effects.len(), 1); let dbg = effects_debug(&effects); - assert!(dbg.contains("AddCategory"), "Expected AddCategory, got: {dbg}"); + assert!( + dbg.contains("AddCategory"), + "Expected AddCategory, got: {dbg}" + ); } #[test] diff --git a/src/command/keymap.rs b/src/command/keymap.rs index fd8ce84..cfbf0e2 100644 --- a/src/command/keymap.rs +++ b/src/command/keymap.rs @@ -1017,7 +1017,9 @@ mod tests { // hjkl should be bound for key in ['h', 'j', 'k', 'l'] { assert!( - normal.lookup(KeyCode::Char(key), KeyModifiers::NONE).is_some(), + normal + .lookup(KeyCode::Char(key), KeyModifiers::NONE) + .is_some(), "Normal mode missing binding for '{}'", key ); @@ -1041,9 +1043,7 @@ mod tests { .lookup(KeyCode::Char('z'), KeyModifiers::NONE) .is_some()); // Should have Esc to exit - assert!(editing - .lookup(KeyCode::Esc, KeyModifiers::NONE) - .is_some()); + assert!(editing.lookup(KeyCode::Esc, KeyModifiers::NONE).is_some()); } #[test] @@ -1053,9 +1053,7 @@ mod tests { assert!(search .lookup(KeyCode::Char('a'), KeyModifiers::NONE) .is_some()); - assert!(search - .lookup(KeyCode::Esc, KeyModifiers::NONE) - .is_some()); + assert!(search.lookup(KeyCode::Esc, KeyModifiers::NONE).is_some()); } #[test] diff --git a/src/formula/parser.rs b/src/formula/parser.rs index 337eb73..3e27fdd 100644 --- a/src/formula/parser.rs +++ b/src/formula/parser.rs @@ -592,11 +592,7 @@ mod tests { #[test] fn parse_where_with_quoted_string_inside_expression() { // WHERE inside a formula string with quotes - let f = parse_formula( - "X = Revenue WHERE Region = \"West Coast\"", - "Measure", - ) - .unwrap(); + let f = parse_formula("X = Revenue WHERE Region = \"West Coast\"", "Measure").unwrap(); let filter = f.filter.as_ref().unwrap(); assert_eq!(filter.item, "West Coast"); } @@ -714,11 +710,7 @@ mod tests { #[test] fn split_where_ignores_where_inside_quotes() { // WHERE inside quotes should not be treated as a keyword - let f = parse_formula( - "X = Revenue WHERE Region = \"WHERE\"", - "Measure", - ) - .unwrap(); + let f = parse_formula("X = Revenue WHERE Region = \"WHERE\"", "Measure").unwrap(); let filter = f.filter.as_ref().unwrap(); assert_eq!(filter.item, "WHERE"); } @@ -773,11 +765,7 @@ mod tests { #[test] fn pipe_quoted_in_where_filter_value() { - let f = parse_formula( - "X = Revenue WHERE Region = |East Coast|", - "Measure", - ) - .unwrap(); + let f = parse_formula("X = Revenue WHERE Region = |East Coast|", "Measure").unwrap(); let filter = f.filter.as_ref().unwrap(); assert_eq!(filter.item, "East Coast"); } diff --git a/src/import/csv_parser.rs b/src/import/csv_parser.rs index ed7e790..05c22f4 100644 --- a/src/import/csv_parser.rs +++ b/src/import/csv_parser.rs @@ -218,15 +218,11 @@ mod tests { #[test] fn rfc4180_embedded_comma_in_quoted_field() { - let (path, _dir) = create_temp_csv( - "Name,Address,Value\n\"Smith, John\",\"123 Main St, Apt 4\",100", - ); + let (path, _dir) = + create_temp_csv("Name,Address,Value\n\"Smith, John\",\"123 Main St, Apt 4\",100"); let records = parse_csv(&path).unwrap(); assert_eq!(records.len(), 1); - assert_eq!( - records[0]["Name"], - Value::String("Smith, John".to_string()) - ); + assert_eq!(records[0]["Name"], Value::String("Smith, John".to_string())); assert_eq!( records[0]["Address"], Value::String("123 Main St, Apt 4".to_string()) @@ -236,9 +232,8 @@ mod tests { #[test] fn rfc4180_escaped_quotes_in_field() { // RFC 4180: doubled quotes ("") inside a quoted field represent a literal quote - let (path, _dir) = create_temp_csv( - "Name,Description,Value\nWidget,\"A \"\"great\"\" product\",10", - ); + let (path, _dir) = + create_temp_csv("Name,Description,Value\nWidget,\"A \"\"great\"\" product\",10"); let records = parse_csv(&path).unwrap(); assert_eq!(records.len(), 1); assert_eq!( @@ -250,9 +245,7 @@ mod tests { #[test] fn rfc4180_newline_in_quoted_field() { // RFC 4180: quoted fields may contain newlines - let (path, _dir) = create_temp_csv( - "Name,Notes,Value\n\"Widget\",\"Line 1\nLine 2\",10", - ); + let (path, _dir) = create_temp_csv("Name,Notes,Value\n\"Widget\",\"Line 1\nLine 2\",10"); let records = parse_csv(&path).unwrap(); assert_eq!(records.len(), 1); assert_eq!( @@ -263,9 +256,8 @@ mod tests { #[test] fn rfc4180_embedded_comma_and_quotes_combined() { - let (path, _dir) = create_temp_csv( - "Name,Desc\n\"Smith, \"\"Jr.\"\"\",\"Said \"\"hello, world\"\"\"", - ); + let (path, _dir) = + create_temp_csv("Name,Desc\n\"Smith, \"\"Jr.\"\"\",\"Said \"\"hello, world\"\"\""); let records = parse_csv(&path).unwrap(); assert_eq!(records.len(), 1); assert_eq!( diff --git a/src/import/wizard.rs b/src/import/wizard.rs index 04e2f62..11666d4 100644 --- a/src/import/wizard.rs +++ b/src/import/wizard.rs @@ -859,7 +859,7 @@ mod tests { let mut w = ImportWizard::new(raw); assert_eq!(w.step, WizardStep::SelectArrayPath); w.confirm_path(); // selects first path - // Should advance past SelectArrayPath + // Should advance past SelectArrayPath assert_ne!(w.step, WizardStep::SelectArrayPath); assert!(!w.pipeline.records.is_empty()); } @@ -1012,12 +1012,20 @@ mod tests { // Toggle Year component (cursor 0 = Year of first time field) let had_year_before = { let tc = w.time_category_proposals(); - !tc.is_empty() && tc[0].date_components.iter().any(|c| *c == DateComponent::Year) + !tc.is_empty() + && tc[0] + .date_components + .iter() + .any(|c| *c == DateComponent::Year) }; w.toggle_date_component(); let has_year_after = { let tc = w.time_category_proposals(); - !tc.is_empty() && tc[0].date_components.iter().any(|c| *c == DateComponent::Year) + !tc.is_empty() + && tc[0] + .date_components + .iter() + .any(|c| *c == DateComponent::Year) }; assert_ne!(had_year_before, has_year_after); } diff --git a/src/model/types.rs b/src/model/types.rs index c368a63..2c8cf21 100644 --- a/src/model/types.rs +++ b/src/model/types.rs @@ -1174,7 +1174,10 @@ mod formula_tests { .unwrap(); // Full precision: Tax is exactly 0.75, Total is exactly 10.75 - assert!(approx_eq(tax, 0.75), "Tax should be 0.75 (full prec), got {tax}"); + assert!( + approx_eq(tax, 0.75), + "Tax should be 0.75 (full prec), got {tax}" + ); assert!( approx_eq(total, 10.75), "Total should be 10.75 (full prec), got {total}" diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index f3cd25e..07d6c27 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -848,7 +848,10 @@ mod tests { fn autosave_path_inserts_dot_prefix() { let p = std::path::Path::new("/home/user/data/budget.improv"); let auto = super::autosave_path(p); - assert_eq!(auto.file_name().unwrap().to_str().unwrap(), ".budget.improv.autosave"); + assert_eq!( + auto.file_name().unwrap().to_str().unwrap(), + ".budget.improv.autosave" + ); } // ── format_md: collapsed groups ───────────────────────────────────── @@ -856,8 +859,7 @@ mod tests { #[test] fn format_md_collapsed_group() { let mut m = two_cat_model(); - m.active_view_mut() - .toggle_group_collapse("Type", "MyGroup"); + m.active_view_mut().toggle_group_collapse("Type", "MyGroup"); let text = format_md(&m); assert!(text.contains("collapsed: Type/MyGroup")); } @@ -936,8 +938,7 @@ Type=Food = 42 #[test] fn parse_md_round_trips_collapsed_group() { let mut m = two_cat_model(); - m.active_view_mut() - .toggle_group_collapse("Type", "MyGroup"); + m.active_view_mut().toggle_group_collapse("Type", "MyGroup"); let text = format_md(&m); let loaded = parse_md(&text).unwrap(); assert!(loaded.active_view().is_group_collapsed("Type", "MyGroup")); @@ -1006,7 +1007,11 @@ Type=Food = 42 let lines: Vec<&str> = content.lines().collect(); assert!(lines.len() >= 2, "Expected header + data, got: {content}"); // Header should contain column labels - assert!(lines[0].contains(','), "Expected CSV header, got: {}", lines[0]); + assert!( + lines[0].contains(','), + "Expected CSV header, got: {}", + lines[0] + ); } #[test] @@ -1036,11 +1041,9 @@ Type=Food = 42 m.add_formula(f); // Configure view m.active_view_mut().set_axis("Month", Axis::Page); - m.active_view_mut() - .set_page_selection("Month", "Jan"); + m.active_view_mut().set_page_selection("Month", "Jan"); m.active_view_mut().hide_item("Type", "Gas"); - m.active_view_mut() - .toggle_group_collapse("Type", "G1"); + m.active_view_mut().toggle_group_collapse("Type", "G1"); m.active_view_mut().number_format = ",.0".to_string(); let text = format_md(&m); diff --git a/src/ui/app.rs b/src/ui/app.rs index 0da2b36..f1199cc 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -317,10 +317,12 @@ impl App { /// Virtual categories (_Index, _Dim) are always present and don't count. pub fn is_empty_model(&self) -> bool { use crate::model::category::CategoryKind; - self.model - .categories - .values() - .all(|c| matches!(c.kind, CategoryKind::VirtualIndex | CategoryKind::VirtualDim)) + self.model.categories.values().all(|c| { + matches!( + c.kind, + CategoryKind::VirtualIndex | CategoryKind::VirtualDim + ) + }) } pub fn handle_key(&mut self, key: KeyEvent) -> Result<()> { diff --git a/src/ui/cat_tree.rs b/src/ui/cat_tree.rs index c768998..ae267e8 100644 --- a/src/ui/cat_tree.rs +++ b/src/ui/cat_tree.rs @@ -80,10 +80,7 @@ mod tests { fn collapsed_category_shows_header_only() { let m = make_model_with_categories(&[("Region", &["North", "South"])]); let tree = build_cat_tree(&m, &HashSet::new()); - let region_entries: Vec<_> = tree - .iter() - .filter(|e| e.cat_name() == "Region") - .collect(); + let region_entries: Vec<_> = tree.iter().filter(|e| e.cat_name() == "Region").collect(); assert_eq!(region_entries.len(), 1); // just the header assert!(matches!( region_entries[0], @@ -101,13 +98,13 @@ mod tests { let mut expanded = HashSet::new(); expanded.insert("Region".to_string()); let tree = build_cat_tree(&m, &expanded); - let region_entries: Vec<_> = tree - .iter() - .filter(|e| e.cat_name() == "Region") - .collect(); + let region_entries: Vec<_> = tree.iter().filter(|e| e.cat_name() == "Region").collect(); // Header + 2 items assert_eq!(region_entries.len(), 3); - assert!(matches!(region_entries[0], CatTreeEntry::Category { expanded: true, .. })); + assert!(matches!( + region_entries[0], + CatTreeEntry::Category { expanded: true, .. } + )); assert!(matches!(region_entries[1], CatTreeEntry::Item { .. })); assert!(matches!(region_entries[2], CatTreeEntry::Item { .. })); } @@ -124,15 +121,11 @@ mod tests { let region_items: Vec<_> = tree .iter() - .filter(|e| { - e.cat_name() == "Region" && matches!(e, CatTreeEntry::Item { .. }) - }) + .filter(|e| e.cat_name() == "Region" && matches!(e, CatTreeEntry::Item { .. })) .collect(); let product_items: Vec<_> = tree .iter() - .filter(|e| { - e.cat_name() == "Product" && matches!(e, CatTreeEntry::Item { .. }) - }) + .filter(|e| e.cat_name() == "Product" && matches!(e, CatTreeEntry::Item { .. })) .collect(); assert_eq!(region_items.len(), 0); // collapsed assert_eq!(product_items.len(), 3); // expanded diff --git a/src/ui/effect.rs b/src/ui/effect.rs index ac435e4..2e6213c 100644 --- a/src/ui/effect.rs +++ b/src/ui/effect.rs @@ -1123,15 +1123,35 @@ mod tests { #[test] fn transpose_axes_effect() { let mut app = test_app(); - let row_before: Vec = app.model.active_view().categories_on(Axis::Row) - .into_iter().map(String::from).collect(); - let col_before: Vec = app.model.active_view().categories_on(Axis::Column) - .into_iter().map(String::from).collect(); + let row_before: Vec = app + .model + .active_view() + .categories_on(Axis::Row) + .into_iter() + .map(String::from) + .collect(); + let col_before: Vec = app + .model + .active_view() + .categories_on(Axis::Column) + .into_iter() + .map(String::from) + .collect(); TransposeAxes.apply(&mut app); - let row_after: Vec = app.model.active_view().categories_on(Axis::Row) - .into_iter().map(String::from).collect(); - let col_after: Vec = app.model.active_view().categories_on(Axis::Column) - .into_iter().map(String::from).collect(); + let row_after: Vec = app + .model + .active_view() + .categories_on(Axis::Row) + .into_iter() + .map(String::from) + .collect(); + let col_after: Vec = app + .model + .active_view() + .categories_on(Axis::Column) + .into_iter() + .map(String::from) + .collect(); assert_eq!(row_before, col_after); assert_eq!(col_before, row_after); } @@ -1313,8 +1333,7 @@ mod tests { ("Month".into(), "Jan".into()), ]); // Set original cell - app.model - .set_cell(key.clone(), CellValue::Number(42.0)); + app.model.set_cell(key.clone(), CellValue::Number(42.0)); let records = vec![(key.clone(), CellValue::Number(42.0))]; StartDrill(records).apply(&mut app); @@ -1340,8 +1359,7 @@ mod tests { ("Type".into(), "Food".into()), ("Month".into(), "Jan".into()), ]); - app.model - .set_cell(key.clone(), CellValue::Number(42.0)); + app.model.set_cell(key.clone(), CellValue::Number(42.0)); let records = vec![(key.clone(), CellValue::Number(42.0))]; StartDrill(records).apply(&mut app); @@ -1363,10 +1381,7 @@ mod tests { ("Type".into(), "Drink".into()), ("Month".into(), "Jan".into()), ]); - assert_eq!( - app.model.get_cell(&new_key), - Some(&CellValue::Number(42.0)) - ); + assert_eq!(app.model.get_cell(&new_key), Some(&CellValue::Number(42.0))); // "Drink" should have been added as an item let items: Vec<&str> = app .model @@ -1385,8 +1400,7 @@ mod tests { ("Type".into(), "Food".into()), ("Month".into(), "Jan".into()), ]); - app.model - .set_cell(key.clone(), CellValue::Number(42.0)); + app.model.set_cell(key.clone(), CellValue::Number(42.0)); let records = vec![(key.clone(), CellValue::Number(42.0))]; StartDrill(records).apply(&mut app); @@ -1465,10 +1479,7 @@ mod tests { item: "Food".to_string(), } .apply(&mut app); - assert_eq!( - app.model.active_view().page_selection("Type"), - Some("Food") - ); + assert_eq!(app.model.active_view().page_selection("Type"), Some("Food")); } // ── Hide/show items ───────────────────────────────────────────────── @@ -1501,21 +1512,19 @@ mod tests { group: "MyGroup".to_string(), } .apply(&mut app); - assert!( - app.model - .active_view() - .is_group_collapsed("Type", "MyGroup") - ); + assert!(app + .model + .active_view() + .is_group_collapsed("Type", "MyGroup")); ToggleGroup { category: "Type".to_string(), group: "MyGroup".to_string(), } .apply(&mut app); - assert!( - !app.model - .active_view() - .is_group_collapsed("Type", "MyGroup") - ); + assert!(!app + .model + .active_view() + .is_group_collapsed("Type", "MyGroup")); } // ── Cycle axis ────────────────────────────────────────────────────── diff --git a/src/ui/help.rs b/src/ui/help.rs index aae910d..50d8895 100644 --- a/src/ui/help.rs +++ b/src/ui/help.rs @@ -144,22 +144,16 @@ fn page_welcome(s: &HelpStyles) -> Vec { HelpLine::accent(" :add-cat Region :add-cat Product", s), HelpLine::blank(), HelpLine::text(" 2. Add items to each category:", s), - HelpLine::accent( - " :add-items Region North South East West", - s, - ), - HelpLine::accent( - " :add-items Product Widget Gadget", - s, - ), + HelpLine::accent(" :add-items Region North South East West", s), + HelpLine::accent(" :add-items Product Widget Gadget", s), HelpLine::blank(), - HelpLine::text(" 3. Navigate with hjkl or arrow keys and press i to edit cells.", s), + HelpLine::text( + " 3. Navigate with hjkl or arrow keys and press i to edit cells.", + s, + ), HelpLine::blank(), HelpLine::text(" 4. Add formulas to compute values automatically:", s), - HelpLine::accent( - " :formula Product Total = Widget + Gadget", - s, - ), + HelpLine::accent(" :formula Product Total = Widget + Gadget", s), HelpLine::blank(), HelpLine::text(" 5. Save your work:", s), HelpLine::accent(" :w mymodel.improv", s), @@ -187,11 +181,7 @@ fn page_welcome(s: &HelpStyles) -> Vec { s, ), HelpLine::blank(), - HelpLine::dim( - " Tip: press Tab or l/n to go to the next page.", - "", - s, - ), + HelpLine::dim(" Tip: press Tab or l/n to go to the next page.", "", s), ] } @@ -215,10 +205,7 @@ fn page_navigation(s: &HelpStyles) -> Vec { HelpLine::blank(), HelpLine::heading("Page-axis cycling", s), HelpLine::blank(), - HelpLine::text( - " When a category is on the Page axis, only one item is", - s, - ), + HelpLine::text(" When a category is on the Page axis, only one item is", s), HelpLine::text( " visible at a time. Use [ and ] to cycle through them.", s, @@ -229,7 +216,11 @@ fn page_navigation(s: &HelpStyles) -> Vec { HelpLine::blank(), HelpLine::heading("Search", s), HelpLine::blank(), - HelpLine::key(" /", "Start search — type a pattern, matching cells highlight", s), + HelpLine::key( + " /", + "Start search — type a pattern, matching cells highlight", + s, + ), HelpLine::key(" n", "Jump to next match", s), HelpLine::key(" N", "Jump to previous match", s), HelpLine::key(" Esc or Enter", "Exit search mode", s), @@ -257,7 +248,11 @@ fn page_editing(s: &HelpStyles) -> Vec { HelpLine::accent(" Text: hello world", s), HelpLine::blank(), HelpLine::key(" Enter", "Commit value and move down", s), - HelpLine::key(" Tab", "Commit value and move right (stay in edit mode)", s), + HelpLine::key( + " Tab", + "Commit value and move right (stay in edit mode)", + s, + ), HelpLine::key(" Esc", "Discard edits and return to Normal", s), HelpLine::blank(), HelpLine::heading("Copy and paste", s), @@ -280,7 +275,10 @@ fn page_editing(s: &HelpStyles) -> Vec { s, ), HelpLine::blank(), - HelpLine::text(" Example: in a Product category with items Widget and Gadget:", s), + HelpLine::text( + " Example: in a Product category with items Widget and Gadget:", + s, + ), HelpLine::accent(" :formula Product Total = Widget + Gadget", s), HelpLine::blank(), HelpLine::text(" Supported operators: + - * /", s), @@ -300,10 +298,7 @@ fn page_panels(s: &HelpStyles) -> Vec { " Panels open on the right side of the screen and give you", s, ), - HelpLine::text( - " quick access to formulas, categories, and views.", - s, - ), + HelpLine::text(" quick access to formulas, categories, and views.", s), HelpLine::blank(), HelpLine::key(" F", "Toggle Formula panel", s), HelpLine::dim(" n", "New formula", s), @@ -325,14 +320,8 @@ fn page_panels(s: &HelpStyles) -> Vec { HelpLine::blank(), HelpLine::heading("Tile select mode (T)", s), HelpLine::blank(), - HelpLine::text( - " Tiles control which axis each category is placed on.", - s, - ), - HelpLine::text( - " Press T to enter tile-select mode, then:", - s, - ), + HelpLine::text(" Tiles control which axis each category is placed on.", s), + HelpLine::text(" Press T to enter tile-select mode, then:", s), HelpLine::blank(), HelpLine::key(" h / l (← →)", "Select previous / next category tile", s), HelpLine::key(" Space / Enter", "Cycle axis: Row → Col → Page", s), @@ -345,11 +334,7 @@ fn page_panels(s: &HelpStyles) -> Vec { HelpLine::blank(), HelpLine::key(" z", "Toggle collapse of nearest group above cursor", s), HelpLine::key(" H", "Hide current row item", s), - HelpLine::dim( - " :show-item ", - "Restore a hidden item", - s, - ), + HelpLine::dim(" :show-item ", "Restore a hidden item", s), ] } @@ -362,10 +347,7 @@ fn page_commands(s: &HelpStyles) -> Vec { " Press : to open the command line. Commands are entered", s, ), - HelpLine::text( - " vim-style and executed with Enter. Esc cancels.", - s, - ), + HelpLine::text(" vim-style and executed with Enter. Esc cancels.", s), HelpLine::blank(), HelpLine::heading("File operations", s), HelpLine::blank(), @@ -385,7 +367,11 @@ fn page_commands(s: &HelpStyles) -> Vec { HelpLine::blank(), HelpLine::key(" :add-cat ", "Add a new category", s), HelpLine::key(" :add-item ", "Add one item to a category", s), - HelpLine::key(" :add-items a b c ...", "Add multiple items at once", s), + HelpLine::key( + " :add-items a b c ...", + "Add multiple items at once", + s, + ), HelpLine::key(" :formula ", "Add a formula", s), HelpLine::blank(), HelpLine::heading("Views", s), diff --git a/src/ui/view_panel.rs b/src/ui/view_panel.rs index 4defa57..bed47ea 100644 --- a/src/ui/view_panel.rs +++ b/src/ui/view_panel.rs @@ -35,10 +35,7 @@ impl<'a> ViewContent<'a> { for axis in [Axis::Row, Axis::Column, Axis::Page] { let cats = view.categories_on(axis); // Filter out virtual categories - let cats: Vec<&str> = cats - .into_iter() - .filter(|c| !c.starts_with('_')) - .collect(); + let cats: Vec<&str> = cats.into_iter().filter(|c| !c.starts_with('_')).collect(); if !cats.is_empty() { let prefix = match axis { Axis::Row => "R",