Commit Graph

49 Commits

Author SHA1 Message Date
eb83df9984 feat: add prune empty feature for pivot views
Add prune_empty feature to hide empty rows/columns in pivot mode.

View gains prune_empty boolean (default false for backward compat).
GridLayout::prune_empty() removes data rows where all columns are
empty and data columns where all rows are empty.

Group headers are preserved if at least one data item survives.
In records mode, pruning is skipped (user drilled in to see all data).

EditOrDrill command updated to check for regular (non-virtual)
categories when determining if a cell is aggregated.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-11 00:06:48 -07:00
55cad99ae1 feat: add new commands for records mode and category management
Add new commands for enhanced data entry and category management.

AddRecordRow: Adds a new record row in records mode with empty value.
TogglePruneEmpty: Toggles pruning of empty rows/columns in pivot mode.
ToggleRecordsMode: Switches between records and pivot layout.
DeleteCategoryAtCursor: Removes a category and all its cells.
ToggleCatExpand: Expands/collapses a category in the tree.
FilterToItem: Filters to show only items matching cursor position.

Model gains remove_category() and remove_item() to delete categories
and items along with all referencing cells and formulas.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-11 00:06:48 -07:00
5fe553b57a feat: add category tree with expand/collapse in category panel
Add a tree-based category panel that supports expand/collapse of categories.

Introduces CatTreeEntry and build_cat_tree to render categories as
a collapsible tree. The category panel now displays categories with
expand indicators (▶/▼) and shows items under expanded categories.

CmdContext gains cat_tree_entry(), cat_at_cursor(), and cat_tree_len()
methods to work with the tree. App tracks expanded_cats in a HashSet.

Keymap updates: Enter in category panel now triggers filter-to-item.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-11 00:06:48 -07:00
ab92775357 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)
2026-04-05 12:35:40 -07:00
f56ca2c66a feat(ui): add dynamic column widths for records mode
Implement dynamic column widths for the grid widget when in records mode.

In records mode, each column width is computed based on the widest
content (pending edit, record value, or header label), with a minimum
of 6 characters and maximum of 32. Pivot mode continues to use fixed
10-character column widths.

The rendering code has been updated to use the computed column widths
and x-offsets for all grid elements: headers, data cells, and totals.
Note that the total row is now only displayed in pivot mode, as it
is not meaningful in records mode.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-05 11:53:37 -07:00
78df3a4949 feat: add records-mode drill-down with staged edits
Introduce records-mode drill-down functionality that allows users to
edit individual records without immediately modifying the underlying model.

Key changes:
- Added DrillState struct to hold frozen records snapshot and pending edits
- New effects: StartDrill, ApplyAndClearDrill, SetDrillPendingEdit
- Extended CmdContext with records_col and records_value for records mode
- CommitCellEdit now stages edits in pending_edits when in records mode
- DrillIntoCell captures a snapshot before switching to drill view
- GridLayout supports frozen records for stable view during edits
- GridWidget renders with drill_state for pending edit display

In records mode, edits are staged and only applied to the model when
the user navigates away or commits. This prevents data loss and allows
batch editing of records.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-05 11:45:36 -07:00
19645a34cf feat: add records mode (long-format view) for drill-down
Implement records mode (long-format view) when drilling into aggregated cells.

Key changes:
- DrillIntoCell now creates views with _Index on Row and _Dim on Column
- GridLayout detects records mode and builds a records list instead of
  cross-product row/col items
- Added records_display() to render individual cell values in records mode
- GridWidget and CSV export updated to handle records mode rendering
- category_names() now includes virtual categories (_Index, _Dim)
- Tests updated to reflect virtual categories counting toward limits

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-05 11:10:41 -07:00
67041dd4a5 feat: add view history navigation and drill-into-cell
Add view navigation history with back/forward stacks (bound to < and >).

Introduce CategoryKind enum to distinguish regular categories from
virtual ones (_Index, _Dim) that are synthesized at query time.

Add DrillIntoCell command that creates a drill view showing raw data
for an aggregated cell, expanding categories on Axis::None into Row
and Column axes while filtering by the cell's fixed coordinates.

Virtual categories default to Axis::None and are automatically added
to all views when the model is initialized.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-05 10:57:28 -07:00
872c4c6c5d refactor: add Default derives to CmdRegistry and Keymap
Add #[derive(Default)] to CmdRegistry and Keymap structs, enabling
easy construction of empty instances with CmdRegistry::default() and
Keymap::default().

This simplifies initialization code and follows Rust conventions for
types that hold empty collections as their default state.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-05 01:07:08 -07:00
d3a1a57c78 refactor: improve dot separator parsing in command parser
Change split_on_dot() to require dot to be a standalone word
surrounded by whitespace or at line boundaries, rather than any
dot character.

This prevents accidental splitting on dots within identifiers or
quoted strings, making the command syntax more predictable.

The new logic checks both preceding and following bytes to ensure
the dot is truly isolated before treating it as a separator.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-05 01:07:08 -07:00
0f1de6ba58 refactor(keymap): add Char key fallback and remove unused SHIFT binding
Improve keymap lookup for Char keys by adding fallback to NONE modifiers.
Terminals vary in whether they send SHIFT for uppercase/symbol characters,
so we now retry without modifiers when an exact match fails.

Also removed the unused shift variable and updated key bindings to use
NONE modifiers instead of SHIFT for consistency.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 18:37:43 -07:00
89fdb27d6c refactor(command): switch to prototype-based command registration
Refactor command registry to use prototype-based registration instead of
string-based names. This makes the API more consistent and type-safe.

Changes:
- Changed Cmd::name() to return &'static str instead of &str
- Updated CmdRegistry::register, register_pure, and register_nullary to accept
  prototype command instances instead of string names
- Added NamedCmd helper struct for cases where command is built by closure
- Updated all command implementations to return static string literals
- Modified EnterMode::execute to clear buffers when entering text-entry modes

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 18:37:43 -07:00
e2ff9cf98e refactor(command): remove key_modifiers from CmdContext
Remove the key_modifiers field from CmdContext struct and all its usages.

This simplifies the command context by removing unused modifier state.
The Cmd trait's execute method no longer receives key modifiers.

Changes:
- Removed KeyModifiers import from cmd.rs
- Removed key_modifiers field from CmdContext struct
- Removed file_path_set field from CmdContext (unused)
- Updated App::cmd_context to not populate key_modifiers
- Removed KeymapSet::registry() accessor
- Updated test code to match new struct layout
- Added documentation to Cmd::name() method

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 12:40:55 -07:00
c6c8ac2c69 chore: clippy + format 2026-04-04 12:34:50 -07:00
35946afc91 refactor(command): pre-resolve cell key and grid dimensions in CmdContext
Refactor command system to pre-resolve cell key and grid dimensions
in CmdContext, eliminating repeated GridLayout construction.

Key changes:
- Add cell_key, row_count, col_count to CmdContext
- Replace generic CmdRegistry::register with
  register/register_pure/register_nullary
- Cell commands (clear-cell, yank, paste) now take explicit CellKey
- Update keymap dispatch to use new interactive() method
- Special-case "search" buffer in SetBuffer effect
- Update tests to populate new context fields

This reduces code duplication and makes command execution more
efficient by computing layout once at context creation time.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 12:33:11 -07:00
649d80cb35 refactor(command): decouple keymap bindings from command implementations
Refactor the keymap system to use string-based command names instead of
concrete command struct instantiations. This introduces a Binding enum that
can represent either a command lookup (name + args) or a prefix sub-keymap.

Key changes:
- Keymap now stores Binding enum instead of Arc<dyn Cmd>
- dispatch() accepts CmdRegistry to resolve commands at runtime
- Added bind_args() for commands with arguments
- KeymapSet now owns the command registry
- Removed PrefixKey struct, inlined its logic
- Updated all default keymap bindings to use string names

This enables more flexible command configuration and easier testing.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 11:02:00 -07:00
a45390b7a9 refactor(command): rename commands and extract panel/axis parsers
Rename several commands for consistency:
- save -> save-as (SaveAsCmd)
- save-cmd -> save (SaveCmd)
- enter-search -> search (EnterSearchMode)
- enter-edit -> enter-edit-mode (EnterEditMode)
- exit-search -> exit-search-mode (ExitSearchMode)

Add new commands:
- search-or-category-add
- search-append-char
- search-pop-char
- toggle-panel-and-focus
- toggle-panel-visibility
- command-mode-backspace

Extract parse_panel() and parse_axis() helper functions to replace
repeated match statements. Update documentation comments to reflect
quasi-lisp syntax instead of Forth-style.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 10:57:37 -07:00
830869d91c test(command): update tests to use ExecuteCommand instead of QuitCmd
Update command tests to work with the new trait-based system:

- Tests now use ExecuteCommand instead of QuitCmd
- Added buffer setup with 'q' command for quit functionality
- Tests verify effects contain SetStatus or ChangeMode via debug output
- Removed direct QuitCmd construction in favor of ExecuteCommand

The tests verify that quit behavior works correctly when dirty vs
clean, ensuring the new command system produces the expected effects.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 10:56:35 -07:00
64ab352490 refactor(command): update parsing to use registry-based system
Update the command parsing layer to use the new CmdRegistry:

- parse_line() now uses default_registry() and returns Vec<Box<dyn Cmd>>
- parse_line_with() accepts a registry parameter for custom registries
- Tokenization replaced direct Command construction with registry.parse()
- Updated tests to verify command names instead of struct fields
- Removed parse_command() and helper functions (require_args, parse_coords,
  etc.)

The parser now delegates command construction to the registry, which
allows commands to be defined and registered in one place.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 10:56:35 -07:00
909c20bcbd refactor(command): remove old Command enum and dispatch system
Remove the old JSON-based command infrastructure:

- Delete Command enum and CommandResult from types.rs
- Remove QuitCmd and InitBuffer command implementations
- Delete entire dispatch.rs file that handled command execution
- Remove Command type exports from mod.rs

The old system used a monolithic Command enum with serde serialization.
The new trait-based system is more flexible and doesn't require JSON
serialization for command execution.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 10:56:35 -07:00
1e8bc7a135 feat(command): add trait-based command system with registry
Introduce a new trait-based command architecture that replaces the
previous JSON-based Command enum. The new system uses:

- Cmd trait: Commands are trait objects that produce Effects
- CmdRegistry: Central registry for parsing commands from text
- ParseFn: Function type for parsing string arguments into commands
- effect_cmd! macro: Helper macro for defining parseable commands

The registry allows commands to be registered by name and parsed from
Forth-style text arguments. This enables both TUI and headless modes
to use the same command parsing infrastructure.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 10:56:34 -07:00
4941b6f44c feat(keymap): add ImportWizard mode with Any key pattern
Add Any key pattern as lowest priority fallback in KeyPattern enum.

Add ImportWizard to ModeKey enum and its mapping from AppMode.
Modify key lookup to fall back to Any pattern for unmatched keys.

Change Enter key in command mode to execute ExecuteCommand.
Add ImportWizard keymap that binds all keys to HandleWizardKey.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 10:42:25 -07:00
630367a9b0 feat(command): add HandleWizardKey and ExecuteCommand handlers
Introduce HandleWizardKey command to dispatch keys to the import wizard.

Add ExecuteCommand implementation that parses and executes various
commands like :quit, :write, :import, :add-item, and :formula.
Handles argument parsing, validation, and mode transitions.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 10:42:25 -07:00
3c561adf05 chore: clippy send + sync warnings, drop warnings 2026-04-04 10:01:27 -07:00
0db89b1e3a chore: clippy + fmt 2026-04-04 09:59:01 -07:00
d8f7d9a501 feat(commands): add panel cursor and tile selection commands
Add comprehensive command implementations for managing panel cursors
(formula_cursor, cat_panel_cursor, view_panel_cursor), tile selection,
text buffers, and search functionality.

Update EnterEditMode to use SetBuffer effect before changing mode.
Update EnterTileSelect to use SetTileCatIdx effect before changing mode.

Add keymap bindings for all new modes with navigation (arrows/hjkl),
editing actions (Enter, Backspace, Char), and mode transitions (Esc, Tab).

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 09:58:31 -07:00
e976b3c49a feat(keymap): add AnyChar pattern and new mode variants
Add AnyChar key pattern for text-entry modes that matches any Char key.

Add new mode variants to ModeKey: FormulaPanel, CategoryPanel, ViewPanel,
TileSelect, Editing, FormulaEdit, CategoryAdd, ItemAdd, ExportPrompt,
CommandMode, and SearchMode.

Update Keymap::lookup to fall back to AnyChar for Char keys.
Update KeymapSet::get to accept search_mode parameter.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 09:58:31 -07:00
b7e4316cef feat(command): add CmdContext extensions and new effects
Add new fields to CmdContext for tracking search mode, panel cursors,
tile category index, named text buffers, and key information.

Add SetBuffer and SetTileCatIdx effects for managing application state.
Update TileBar to accept tile_cat_idx parameter for rendering.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
2026-04-04 09:58:30 -07:00
9afa13f78a improve error formatting
- Added missing comma in error message for set-cell command.
- Reformatted error messages for consistency.
- Minor formatting changes to improve readability.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gpt-oss:20b)
2026-04-04 09:31:49 -07:00
bfc30cb7b2 overhaul keymap API and add Debug
- Replaced ModeKey with direct KeyPattern keys.
- Stored bindings as Arc<dyn Cmd> for cheap sharing.
- Added Debug implementation for Keymap.
- Updated bind, bind_cmd, bind_prefix, lookup, and dispatch signatures.
- Introduced PrefixKey command and SetTransientKeymap effect.
- Added KeymapSet for mode-specific keymaps.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gpt-oss:20b)
2026-04-04 09:31:49 -07:00
c188ce3f9d add panel toggling and new command implementations
- Implemented a suite of new commands for panel visibility, editing, export
  prompts, search navigation, page cycling, and grid operations.
- Updated tests to cover new command behavior.
- Adjusted command context usage accordingly.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gpt-oss:20b)
2026-04-04 09:31:48 -07:00
f2bb8ec2a7 update CmdContext and imports
- Updated imports to include Panel and Axis.
- Added new fields to CmdContext: formula_panel_open, category_panel_open,
  view_panel_open.
- Reformatted effect vectors for consistency.
- Minor formatting changes to improve readability.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gpt-oss:20b)
2026-04-04 09:31:48 -07:00
f7436e73ba refactor: add Keymap with default bindings and wire into handle_key
Create keymap.rs with Keymap struct mapping (mode, key) to Cmd trait
objects. Wire into App::handle_key — keymap dispatch is tried first,
falling through to old handlers for unmigrated bindings. Normal mode
navigation, cell ops, mode switches, and Help mode are keymap-driven.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:40:36 -07:00
0c751b7b8b refactor: add Cmd trait with CmdContext and first command implementations
Define Cmd trait (execute returns Vec<Box<dyn Effect>>) and CmdContext
(read-only state snapshot). Implement navigation commands (MoveSelection,
JumpTo*, ScrollRows), mode commands (EnterMode, Quit, SaveAndQuit),
cell operations (ClearSelectedCell, YankCell, PasteCell), and view
commands (TransposeAxes, Save, EnterSearchMode).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:38:56 -07:00
567ca341f7 feat: Forth-style prefix command parser
Replace JSON command syntax with prefix notation: `word arg1 arg2`.
Multiple commands per line separated by `.`. Coordinate pairs use
`Category/Item`. Quoted strings for multi-word values. set-cell
uses value-first: `set-cell 100 Region/East Measure/Revenue`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:14:37 -07:00
a73fe160c7 feat: date parsing, component extraction, and wizard formulas
Extend FieldProposal with chrono-based date format detection and
configurable component extraction (Year, Month, Quarter). Add
ConfigureDates and DefineFormulas wizard steps to ImportPipeline.
build_model injects derived date categories and parses formula strings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:41:05 -07:00
fe74cc5fcb chore: clippy + fmt 2026-04-02 09:35:02 -07:00
1d5edd2c09 fix: handle PathBuf correctly 2026-04-01 22:16:56 -07:00
23e26f0e06 Add CSV import functionality
- Use csv crate for robust CSV parsing (handles quoted fields, empty values, \r\n)
- Extend --import command to auto-detect format by file extension (.csv or .json)
- Reuse existing ImportPipeline and analyzer for field type detection
- Categories detected automatically (string fields), measures for numeric fields
- Updated help text and welcome screen to mention CSV support

All 201 tests pass.
2026-04-01 01:37:04 -07:00
183b2350f7 chore: reformat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 00:07:22 -07:00
37584670eb feat: group-aware grid rendering and hide/show item
Builds out two half-finished view features:

Group collapse:
- AxisEntry enum distinguishes GroupHeader from DataItem on grid axes
- expand_category() emits group headers and filters collapsed items
- Grid renders inline group header rows with ▼/▶ indicator
- `z` keybinding toggles collapse of nearest group above cursor

Hide/show item:
- Restore show_item() (was commented out alongside hide_item)
- Add HideItem / ShowItem commands and dispatch
- `H` keybinding hides the current row item
- `:show-item <cat> <item>` command to restore hidden items
- Restore silenced test assertions for hide/show round-trip

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 00:07:11 -07:00
6038cb2d81 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>
2026-03-24 09:00:25 -07:00
a2e519efcc refactor: replace CellValue::Empty with Option<CellValue>
Previously CellValue had three variants: Number, Text, and Empty.
The Empty variant acted as a null sentinel, but the compiler could not
distinguish between "this is a real value" and "this might be empty".
Code that received a CellValue could use it without checking for Empty,
because there was no type-level enforcement.

Now CellValue has only Number and Text. The absence of a value is
represented as None at every API boundary:

  DataStore::get()    → Option<&CellValue>  (was &CellValue / Empty)
  Model::get_cell()   → Option<&CellValue>  (was &CellValue / Empty)
  Model::evaluate()   → Option<CellValue>   (was CellValue::Empty)
  eval_formula()      → Option<CellValue>   (was CellValue::Empty)

Model gains clear_cell() for explicit key removal; ClearCell dispatch
calls it instead of set_cell(key, CellValue::Empty).

The compiler now forces every caller of evaluate/get_cell to handle
the None case explicitly — accidental use of an empty value as if it
were real is caught at compile time rather than silently computing
wrong results.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 08:06:51 -07:00
e680b098ec refactor: remove Axis::Unassigned; axis_of returns Option<Axis>
Axis::Unassigned served two purposes that Option already covers:
  1. "this category has no assignment yet" → None
  2. "this category doesn't exist" → None

By removing the variant and changing axis_of to return Option<Axis>,
callers are forced by the compiler to handle the absent-category case
explicitly (via match or unwrap_or), rather than silently treating it
like a real axis value.

SetAxis { axis: String } also upgraded to SetAxis { axis: Axis }.
Previously, constructing SetAxis with an invalid string (e.g. "diagonal")
would compile and then silently fail at dispatch. Now the type only admits
valid axis values; the dispatch string-parser is gone.

Axis gains #[serde(rename_all = "lowercase")] so existing JSON command
files (smoke.jsonl, etc.) using "row"/"column"/"page" continue to work.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 07:32:48 -07:00
9ef0a72894 fix: formula evaluation and management bugs
Three bugs fixed, each with a failing regression test added first:

1. WHERE filter fallthrough: when the filter's category was absent from the
   cell key, the formula was applied unconditionally. Now returns the raw
   stored value (no formula applied) when the category is missing.

2. Agg inner/filter ignored: SUM(Revenue) was summing ALL cells in the
   partial slice rather than constraining to the Revenue item. Now resolves
   the inner Ref to its category and pins that coordinate before scanning.

3. Formula dedup by target only: add_formula and remove_formula keyed on
   target name alone, so two formulas with the same item name in different
   categories would collide. Both now key on (target, target_category).

RemoveFormula command updated to carry target_category.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 00:11:33 -07:00
0cb491901d fix: formula correctness and command validation bugs
- model.rs: division by zero now returns Empty instead of 0 so the cell
  visually signals the error rather than silently showing a wrong value.
  Updated the test to assert Empty.
- parser.rs: missing closing ')' in aggregate functions (SUM, AVG, etc.)
  and IF(...) now returns a parse error instead of silently succeeding,
  preventing malformed formulas from evaluating with unexpected results.
- dispatch.rs: SetCell validates that every category in the coords
  exists before mutating anything; previously a typo in a category name
  silently wrote an orphaned cell (stored but never visible in any grid)
  and returned ok. Now returns an error immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:32:14 -07:00
cc072e192d Chore: remove unused imports and suppress unused variable warnings
Removes dead use statements across dispatch, formula, import, model, and
UI modules. Prefixes intentionally unused variables with _ in app.rs,
analyzer.rs, and grid.rs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 23:35:50 -07:00
197b66e4e1 Refactor: split ImportWizard into pure ImportPipeline and UI wrapper
ImportPipeline holds all data and logic (raw JSON, records, proposals,
model_name, build_model). ImportWizard wraps it with UI-only state
(step, cursor, message). Rename WizardState → WizardStep throughout.
Headless import in dispatch.rs now constructs ImportPipeline directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 23:28:27 -07:00
eae00522e2 Initial implementation of Improvise TUI
Multi-dimensional data modeling terminal application with:
- Core data model: categories, items, groups, sparse cell store
- Formula system: recursive-descent parser, named formulas, WHERE clauses
- View system: Row/Column/Page axes, tile-based pivot, page slicing
- JSON import wizard (interactive TUI + headless auto-mode)
- Command layer: all mutations via typed Command enum for headless replay
- TUI: Ratatui grid, tile bar, formula/category/view panels, help overlay
- Persistence: .improv (JSON), .improv.gz (gzip), CSV export, autosave
- Static binary via x86_64-unknown-linux-musl + nix flake devShell
- Headless mode: --cmd '{"op":"..."}' and --script file.jsonl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 21:11:55 -07:00