docs: expand README with concrete details

Add dedicated sections for the data model (formula examples), views and
axes (tile mode, records mode, drill-down), the .improv file format
(annotated example), import wizard and headless scripting, and the
command/effect architecture. Link docs/design-notes.md from the "Why"
section. Update build instructions to use `nix build .`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Edward Langley
2026-04-09 00:11:44 -07:00
parent 4751b800fd
commit d3d1df0be2

136
README.md
View File

@ -17,18 +17,20 @@ attempt to bring that model to a modern terminal, with a formula language that
references category and item names, views that can be rearranged with a single references category and item names, views that can be rearranged with a single
keystroke, and a plain-text file format you can diff in git. keystroke, and a plain-text file format you can diff in git.
See [docs/design-notes.md](docs/design-notes.md) for the original product
vision and non-goals.
## Quick start ## Quick start
```sh ```sh
nix develop nix build .
cargo build --release ./result/bin/improvise examples/demo.improv
./target/release/improvise examples/demo.improv
``` ```
Or import your own CSV: Or import your own CSV:
```sh ```sh
./target/release/improvise import path/to/data.csv ./result/bin/improvise import path/to/data.csv
``` ```
## Key bindings to try first ## Key bindings to try first
@ -47,13 +49,12 @@ Or import your own CSV:
## Installation ## Installation
### From source with Nix (preferred) ### With Nix (preferred)
```sh ```sh
nix develop nix build .
cargo build --release # or install into your profile:
# optionally install to your PATH: nix profile install .
cargo install --path .
``` ```
### From crates.io ### From crates.io
@ -67,22 +68,109 @@ cargo install improvise
See the [GitHub releases page](https://github.com/fiddlerwoaroof/improvise/releases) See the [GitHub releases page](https://github.com/fiddlerwoaroof/improvise/releases)
for prebuilt binaries (Linux x86_64, macOS Intel and Apple Silicon). for prebuilt binaries (Linux x86_64, macOS Intel and Apple Silicon).
## What's interesting about the codebase ## The data model
The data model stores every cell at the intersection of named categories and Every cell lives at the intersection of named categories and items —
items — `(Region=East, Measure=Revenue)`rather than at a grid address like `(Region=East, Measure=Revenue)`not at a grid address like `B3`. A model
`B3`. A view is a configuration that assigns each category to a row, column, can have up to 12 categories, each with an ordered list of items that can be
page, or hidden axis, and the grid layout is computed as a pure function from organized into collapsible groups (e.g. months grouped into quarters).
`(Model, View)` to `GridLayout`. Transposing a pivot is just swapping the row
and column assignments; records mode is just assigning the virtual `_Index` and Formulas reference dimension names, not cell addresses:
`_Dim` categories to particular axes. The formula language references dimension
names (`Profit = Revenue - Cost`), so formulas survive any rearrangement ```
without rewriting. All user actions go through a command/effect pipeline: Profit = Revenue - Cost
commands are pure functions that read an immutable context and return a list of Tax = Revenue * 0.08
effects, which are the only things that mutate state. The same command registry Margin = IF(Revenue > 0, Profit / Revenue, 0)
serves both the interactive TUI and the headless `cmd`/`script` CLI BigDeal = Sum(Revenue WHERE Region = "West")
subcommands. Models persist to a markdown-like `.improv` format that is ```
human-readable, git-diffable, and optionally gzip-compressed.
The formula language supports `+` `-` `*` `/` `^`, comparisons, `IF`, and
aggregation functions (`Sum`, `Avg`, `Min`, `Max`, `Count`) with optional
`WHERE` clauses. Formulas apply uniformly across all intersections — no
copying, no dragging, no `$A$1` anchoring.
## Views and axes
A view assigns each category to one of four axes: **row**, **column**,
**page** (slicer), or **hidden**. The grid layout is a pure function of
`(Model, View)``GridLayout` — transposing is just swapping row and column
assignments, and it happens in one keystroke (`t`). Page-axis categories act
as filters: `[` and `]` cycle through items.
Press `T` to enter tile mode, where each category appears as a tile in the
tile bar. Move between tiles with `h`/`l`, then press `Space` to cycle axes
or `r`/`c`/`p` to set one directly.
Records mode (`R`) flips to a long-format view by assigning the virtual
`_Index` and `_Dim` categories to row and column axes. Drill-down (`>`) on an
aggregated cell captures a snapshot; edits accumulate in a staging area and
commit atomically on exit.
## File format
Models persist to a plain-text `.improv` format that reads like markdown and
diffs cleanly in git:
```
# Sales 2025
## Category: Region
- North
- South
- East [Coastal]
- West [Coastal]
> Coastal
## Category: Measure
- Revenue
- Cost
- Profit
## Formulas
- Profit = Revenue - Cost [Measure]
## Data
Region=East, Measure=Revenue = 1200
Region=East, Measure=Cost = 800
## View: Default (active)
Region: row
Measure: column
format: ,.2f
```
Gzip-compressed `.improv.gz` is also supported. Legacy JSON is auto-detected
for backward compatibility.
## Import and scripting
The import wizard analyzes CSV columns and proposes each as a category
(string-valued), measure (numeric), time dimension (date-like, with optional
year/month/quarter extraction), or skip. Multiple CSVs merge automatically
with a synthetic "File" category.
All model mutations go through a typed command registry, so the same
operations that back the TUI work headless:
```sh
# single commands
improvise cmd 'add-cat Region' 'add-item Region East' -f model.improv
# script file (one command per line, # comments)
improvise script setup.txt -f model.improv
```
## What's interesting about the architecture
All user actions flow through a two-phase command/effect pipeline. Commands
are pure functions: they receive an immutable `CmdContext` (model, layout,
cursor position, mode) and return a list of effects. Effects are the only
things that mutate app state, and each one is a small, debuggable struct.
This means commands are testable without a terminal, effects can be logged or
replayed, and the 40+ commands and 50+ effect types are all polymorphic —
dispatched through trait objects and a registry, not a central match block.
The keybinding system gives each of the 14 modes its own keymap, with
Emacs-style prefix keys for multi-stroke sequences.
## Expectations ## Expectations