diff --git a/context/repo-map.md b/context/repo-map.md index 1bbd2d5..f7bfe98 100644 --- a/context/repo-map.md +++ b/context/repo-map.md @@ -1,7 +1,8 @@ # Repository Map (LLM Reference) Terminal pivot-table modeling app. Rust, Ratatui TUI, command/effect architecture. -Crate `improvise` v0.1.0, Apache-2.0, edition 2021. +Crate `improvise` v0.1.0-rc2, Apache-2.0, edition 2024. +Library + binary crate: `src/lib.rs` exports public modules, `src/main.rs` is the CLI entry. --- @@ -94,8 +95,10 @@ pub struct Model { // evaluate(&self, key: &CellKey) -> Option [formulas + raw data] // evaluate_aggregated(&self, key, none_cats) -> Option [sums over hidden dims] // recompute_formulas(&mut self, none_cats) [fixed-point formula cache] -// add_formula(&mut self, formula: Formula) [replaces same target+category, adds item] +// add_formula(&mut self, formula: Formula) [replaces same target+category] // remove_formula(&mut self, target, category) +// measure_item_names(&self) -> Vec [_Measure items + formula targets] +// effective_item_names(&self, cat) -> Vec [_Measure dynamic, others ordered_item_names] // category_names(&self) -> Vec<&str> [includes virtual] // regular_category_names(&self) -> Vec<&str> [excludes _Index, _Dim, _Measure] @@ -262,8 +265,10 @@ pub enum ModeKey { SearchMode, ImportWizard, } +// Keymap::with_parent(parent: Arc) -> Self [Emacs-style inheritance] // Keymap::lookup(&self, key, mods) -> Option<&Binding> -// Fallback chain: exact(key,mods) → Char with NONE mods → AnyChar → Any +// Fallback chain: exact(key,mods) → Char with NONE mods → AnyChar → Any → parent +// Minibuffer modes: Enter and Esc use Binding::Sequence to include clear-buffer // KeymapSet::default_keymaps() -> Self [builds all 14 mode keymaps] // KeymapSet::dispatch(&self, ctx, key, mods) -> Option>> @@ -293,7 +298,8 @@ collapsed: |Time Period|/|2024| format: ,.2f ## Formulas -- Profit = Revenue - Cost [Measure] ← [TargetCategory] +- Profit = Revenue - Cost ← defaults to [_Measure] +- Tax = Revenue * 0.1 [CustomCat] ← explicit [TargetCategory] for non-_Measure ## Category: Region - North, South, East, West ← bare items, comma-separated @@ -323,7 +329,7 @@ The parser accepts sections in any order. ### Key design choices -- Version line (`v2025-04-09`) enables future format changes. +- Version line is exact match (`v2025-04-09`) — grammar enforces valid versions only. - `Initial View:` is a top-level header, not embedded in view sections. - Text cell values are always pipe-quoted to distinguish from numbers. - Bare items are comma-separated on one line; grouped items get one line each. @@ -349,7 +355,7 @@ Import flags: `--category`, `--measure`, `--time`, `--skip`, `--extract`, `--axi | Crate | Purpose | |-------|---------| -| ratatui 0.29 | TUI framework | +| ratatui 0.30 | TUI framework | | crossterm 0.28 | Terminal backend | | clap 4.6 (derive) | CLI parsing | | serde + serde_json | Serialization | @@ -442,11 +448,18 @@ command/cmd/ Cmd trait, CmdContext, CmdRegistry, 40+ comma ``` 400 / 0t draw.rs TUI event loop (run_tui), frame composition 391 / 0t main.rs CLI entry (clap): open, import, cmd, script + 10 / 0t lib.rs Public module exports (enables examples) 228 / 29t format.rs Number display formatting (view-only rounding) 124 / 0t persistence/improv.pest PEG grammar — single source of truth for .improv format 2291 / 83t persistence/mod.rs .improv save/load (pest parser + format + gzip + legacy JSON) ``` +### Examples +``` +examples/gen-grammar.rs Grammar-walking random file generator (pest_meta) +examples/pretty-print.rs Parse stdin, print formatted .improv to stdout +``` + ### Context docs ``` context/design-principles.md Architectural principles @@ -455,7 +468,7 @@ context/repo-map.md This file docs/design-notes.md Product vision & non-goals (salvaged from former SPEC.md) ``` -**Total: ~21,400 lines, 568 tests.** +**Total: ~22,000 lines, 572 tests.** --- @@ -519,7 +532,7 @@ examples). 1. **Commands never mutate.** They receive `&CmdContext` (read-only) and return `Vec>`. 2. **CellKey is always sorted.** Use `CellKey::new()` — never construct the inner Vec directly. 3. **`category_mut()` for adding items.** `Model` has no `add_item` method; get the category first: `m.category_mut("Region").unwrap().add_item("East")`. -4. **Virtual categories** `_Index`, `_Dim`, and `_Measure` always exist. `is_empty_model()` checks whether any *non-virtual* categories exist. `_Measure` holds numeric data fields and formula targets; `add_formula` auto-adds the target item. +4. **Virtual categories** `_Index`, `_Dim`, and `_Measure` always exist. `is_empty_model()` checks whether any *non-virtual* categories exist. `_Measure` items come from two sources: explicit data items (in category) + formula targets (dynamically via `measure_item_names()`). `add_formula` does NOT add items to `_Measure` — use `effective_item_names("_Measure")` to get the full list. `_Index` and `_Dim` are never persisted to `.improv` files; `_Measure` only persists non-formula items. 5. **Display rounding is view-only.** `format_f64` (half-away-from-zero) is only called in rendering. Formula eval uses full f64. 5b. **Formula evaluation is fixed-point.** `recompute_formulas(none_cats)` iterates formula evaluation until values stabilize, using a cache. `evaluate_aggregated` checks the cache for formula results. Circular refs produce `CellValue::Error("circular")`. 6. **Keybindings are per-mode.** `ModeKey::from_app_mode()` resolves the current mode, then the corresponding `Keymap` is looked up. Normal + `search_mode=true` maps to `SearchMode`. @@ -527,3 +540,6 @@ examples). 8. **`.improv` format is defined by a PEG grammar** (`persistence/improv.pest`). Parsed by pest. Names use CL-style `|...|` pipe quoting when they aren't valid bare identifiers. JSON is legacy only. 9. **`IndexMap`** is used for categories and views to preserve insertion order. 10. **`MAX_CATEGORIES = 12`** applies only to `CategoryKind::Regular`. Virtual/Label categories are exempt. +11. **Drill into formula cells** strips the `_Measure` coordinate from the drill key when it names a formula target, so `matching_cells` finds the raw data records that feed the formula instead of returning empty. +12. **`App::new` calls `recompute_formulas`** before building the initial layout, so formula values appear on the first rendered frame. +13. **Minibuffer buffer clearing** is handled by `Binding::Sequence` in keymaps: Enter and Esc sequences include `clear-buffer` to reset the text buffer. The `clear-buffer` command is registered in the registry.