Commit Graph

350 Commits

Author SHA1 Message Date
Edward Langley 9e02245f37 refactor(ui): improve panel focus cycling logic
Refactored `CyclePanelFocus` to follow a consistent
`Formula -> Category -> View` order.

Focus now correctly wraps around and handles non-panel modes.

Add regression tests for improved cycling logic.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 21:43:13 -07:00
Edward Langley 47ad9e6032 fix(io): improve persistence robustness and CSV compliance
Improved numeric parsing in Markdown files to surface errors instead of
defaulting to 0.0.

`export_csv` now uses `csv::Writer` to ensure RFC 4180 compliance (e.g.,
quoting fields containing commas).

`export_csv` now correctly respects the view's number format.

Add regression tests for numeric error handling and RFC 4180 compliance.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 21:43:13 -07:00
Edward Langley 77a5124d16 fix(io): enforce category limit in import wizard
The import wizard now proactively checks the `MAX_CATEGORIES` limit during
the proposal and configuration steps.

Advancing is blocked with a descriptive message if the limit would be
exceeded.

Fixed UI rendering order in `ImportWizardWidget` so messages are correctly
displayed.

Add regression tests for category limit enforcement.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 21:43:13 -07:00
Edward Langley f0b9227d8f feat(io): enhance CSV import with warnings and improved headless parsing
`parse_csv` now supports `parse_csv_with_warnings` to detect and report
short rows.

Short rows are now padded with `Value::Null` instead of being silently
dropped.

`ImportJsonHeadless` now uses `parse_csv_with_warnings` and surfaces
warnings in the status message.

`ImportJsonHeadless` now reuses parsed JSON/CSV data via
`json_import_records` instead of re-parsing.

Add regression tests for short row handling and headless import.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 21:43:13 -07:00
Edward Langley f04fe517ae fix(core): improve view robustness and axis management
`records_display` now returns `None` for out-of-bounds columns.

Added `try_axis_of` to `View` for non-panicking axis retrieval.

`cycle_axis` now uses `try_axis_of` to avoid panicking on unknown
categories.

Add regression tests for out-of-bounds access and unknown category cycling.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 21:43:13 -07:00
Edward Langley 45bfe2c4c7 refactor(core): use epsilon for float comparison and IndexSet for stem collection
Use `FLOAT_EQ_EPSILON` for equality/inequality operators and
division-by-zero guards in formula evaluation to ensure consistent
semantics.

Replace `Vec` with `IndexSet` for stem collection in `recompute_formulas`
to improve performance from O(n²) to O(n).

Add regression tests for epsilon-based comparison and stem collection
performance.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 21:43:13 -07:00
Edward Langley 0fe04de53e docs(context): refresh repo-map after ModelState/ViewState refactor
Line counts, 16 AppMode variants (RecordsNormal/RecordsEditing), 16 mode
keymaps, ModelState/ViewState split, crossterm 0.29. Findings from the
2026-06-09 systematic review (issues improvise-1cz .. improvise-2ud).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 21:00:31 -07:00
Edward Langley ecb524c947 chore(deps): update dependencies
Update Cargo.lock with new versions and additional dependencies.

This includes updates to bitflags, chrono, and hashbrown, along with the
addition of new packages such as approx, critical-section, and the futures
suite.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 20:48:44 -07:00
Edward Langley 62d18ffe7c chore(dev): add universal-ctags and global to devShell
Adds pkgs.global and pkgs.universal-ctags to the development shell.

This update also includes the corresponding changes in flake.lock.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
2026-06-09 20:46:00 -07:00
Edward Langley 7249facf94 docs(ui): classify App-resident runtime/derived fields (improvise-99k)
Step 4 of vb4. After steps 1–3, App owns model_state, view_state, and a
residue of five fields that don't belong to either slice. Add a top-level
doc on App explaining the slice structure and tag each residue field as
derived cache / runtime metadata / transient / config with a one-line
rationale. No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 17:33:27 -07:00
Edward Langley 9ad8abd8a5 refactor(ui): move UI session fields into ViewState (improvise-ew0)
Step 3 of vb4. Populates ViewState with the 20 UI session fields (mode,
status_msg, wizard, search_query, search_mode, three panel-open flags,
three panel cursors, formula_cursor, yanked, tile_cat_idx, two view nav
stacks, drill_state, help_page, expanded_cats, buffers, transient_keymap)
and routes every read/write site through app.view_state.X. App now
contains only model_state, view_state, and the runtime/derived residue
(term dims, layout, last_autosave, abort_effects, keymap_set).

ViewState gets a manual Default impl mirroring the previous App::new
field initialisers; AppMode has no Default of its own so AppMode::Normal
is the explicit baseline. Effect::apply still takes &mut App; narrowing
remains step 5 (improvise-drg).

A structural test (app_view_state_owns_ui_session_fields) locks in the
20-field layout. 624 tests pass workspace-wide (+1 new). cargo clippy
--workspace --tests clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:19:31 -07:00
Edward Langley 917b928759 refactor(ui): move workbook/file_path/dirty into ModelState (improvise-x2c)
Step 2 of vb4. Populates ModelState with the document slice and routes
every read/write site (effects, draw, main, app methods, tests) through
app.model_state.X. App no longer owns workbook, file_path, or dirty
directly. Effect::apply signatures still take &mut App; narrowing happens
in step 5 (improvise-drg).

A structural test (app_model_state_owns_workbook_file_path_and_dirty)
locks in the field layout. ModelState now has a manual Default impl
that creates an "Untitled" Workbook so the existing constructibility
test keeps working.

623 tests pass workspace-wide (+1 new). cargo clippy --workspace --tests
clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 22:06:33 -07:00
Edward Langley f11d79f700 refactor(ui): scaffold ModelState and ViewState types (improvise-3vr)
Step 1 of vb4 (Split AppState into ModelState + ViewState): introduce the
named slice types in src/ui/app.rs as empty structs, with doc comments
pointing at the follow-up issues that fill them in. App still owns every
field directly; subsequent steps migrate the fields.

A structural test locks in that both types are constructible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 11:31:03 -07:00
Edward Langley 1181ffd0ab chore: update roadmap 2026-04-26 11:10:32 -07:00
Edward Langley 6756b00e4a chore: minor formatting changes 2026-04-26 11:08:41 -07:00
Ed L 3324ceef69 chore: don't use IFD for Cargo.nix 2026-04-26 10:28:37 -07:00
Ed L 452234f2d5 chore(merge): remote-tracking branch 'gh/dependabot/cargo/rand-0.8.6' 2026-04-26 10:09:29 -07:00
Ed L 782ca9dfaa chore(merge): remote-tracking branch 'me/main' 2026-04-26 10:09:16 -07:00
Ed L 36ee0e229f chore: update issues.jsonl 2026-04-26 10:08:57 -07:00
Edward Langley 9e310b9e4b chore: update agent instructions 2026-04-26 09:45:23 -07:00
dependabot[bot] 699d4d58dc chore(deps): bump rand from 0.8.5 to 0.8.6
Bumps [rand](https://github.com/rust-random/rand) from 0.8.5 to 0.8.6.
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/0.8.6/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/0.8.5...0.8.6)

---
updated-dependencies:
- dependency-name: rand
  dependency-version: 0.8.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-22 22:17:23 +00:00
Ed L 21fc03cf18 chore: save session memories via bd remember
Captures three insights from 2026-04-16 deep review session:
- review-methodology-scoped-explore-agents
- compiler-exhaustiveness-theme
- agent-issue-drift-pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 16:07:45 -07:00
Ed L 47313c4e80 chore: update repo-map 2026-04-16 16:05:42 -07:00
Ed L 6362078032 chore: bd dolt sync conf + issue jsonl 2026-04-16 11:11:30 -07:00
Ed L 8242ef3dbe bd: update sync.remote 2026-04-16 11:04:54 -07:00
Ed L c158a8b99e bd init: initialize beads issue tracking 2026-04-16 10:58:57 -07:00
Edward Langley d99cb5ac8c Merge branch 'main' into worktree-improvise-ewi-formula-crate 2026-04-15 23:43:14 -07:00
Edward Langley 4e37e12f9a style: reformat code and cleanup whitespace
Reformat code for improved readability and remove unnecessary whitespace.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 23:42:44 -07:00
Edward Langley a900f147b5 feat(cmd): use new effects to improve command behavior
Update various commands to utilize the new AbortChain and CleanEmptyRecords
effects.

- CommitAndAdvance now pushes a mode change effect when aborting.
- ToggleRecordsMode now cleans up empty records upon exiting.
- EnterAdvance now emits AbortChain when at the bottom-right corner.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 23:42:44 -07:00
Edward Langley 489e2805e8 feat(ui): implement AbortChain and CleanEmptyRecords effects
Implement AbortChain and CleanEmptyRecords effects to allow
short-circuiting effect batches and purging cells with empty coordinates.
Update the App struct to support aborting effects during the application of
an effect batch.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 23:42:44 -07:00
Edward Langley f272a9d459 chore: update roadmap 2026-04-15 23:35:08 -07:00
Edward Langley ff74d619a3 docs(io): note improvise-io layout in repo-map
Reflect improvise-8zh: `persistence/` and `import/` now live in the
`improvise-io` sub-crate under `crates/`.

- Sub-crate list expanded to describe improvise-io's scope, its
  dependencies (improvise-core, improvise-formula), and the
  standalone-build guarantee.
- File Inventory reorganized: "Import layer" + persistence entries
  collapsed into a single "I/O crate layers" block with paths rooted at
  `crates/improvise-io/src/`.
- Updated line/test counts to current contents.
- Top-level block trimmed (persistence/format no longer live there) and
  lib.rs annotated as a re-export facade.

No consumer-facing path changes; `crate::persistence::*` and
`crate::import::*` still resolve via the main crate's re-exports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 23:08:55 -07:00
Edward Langley 5807464fc7 refactor(io): move persistence and import into improvise-io (improvise-8zh)
Relocate the two I/O module trees into the improvise-io sub-crate
scaffolded in the previous commit:

  git mv src/persistence -> crates/improvise-io/src/persistence
  git mv src/import      -> crates/improvise-io/src/import

The grammar file `improv.pest` moves alongside `persistence/mod.rs`;
the `#[grammar = "persistence/improv.pest"]` attribute resolves relative
to the new crate root and keeps working unchanged.

No path edits inside the moved code: the `crate::model::*`,
`crate::view::*`, `crate::workbook::*`, `crate::format::*`, and
`crate::formula::*` imports inside persistence and import all continue
to resolve because improvise-io's lib.rs re-exports those modules from
improvise-core and improvise-formula, mirroring the pattern improvise-core
uses for `formula`. Verified no `crate::ui::*`, `crate::command::*`,
`crate::draw::*` imports exist in the moved code (per improvise-8zh
acceptance criterion #3).

Main-crate `src/lib.rs` now re-exports `import` and `persistence` from
improvise-io, keeping every `crate::persistence::*` and `crate::import::*`
path in the 4 consumer files (ui/app.rs, ui/effect.rs,
ui/import_wizard_ui.rs, main.rs) resolving unchanged — no downstream
edits needed.

`examples/gen-grammar.rs` had `include_str!("../src/persistence/improv.pest")`;
updated the relative path to the new location under
`crates/improvise-io/src/persistence/`.

Verification:
- cargo check --workspace --examples: clean
- cargo test --workspace: 616 passing (219 main + 190 core + 65 formula + 142 io)
- cargo clippy --workspace --tests: clean
- cargo build -p improvise-io: standalone build succeeds, confirming no
  UI/command leakage into the IO crate (improvise-8zh acceptance #2, #3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 23:08:00 -07:00
Edward Langley bd17aed169 refactor(io): scaffold empty improvise-io sub-crate
Lay groundwork for Phase 3 of the workspace split (improvise-8zh): a new
`crates/improvise-io/` sub-crate that will house the persistence and
import layers once the files move in the next commit.

Only scaffolding here:
- New `crates/improvise-io/Cargo.toml` declares deps on improvise-core,
  improvise-formula, and the external crates persistence+import already
  use: anyhow, chrono, csv, flate2, indexmap, pest, pest_derive, serde,
  serde_json. Dev-deps: pest_meta, proptest, tempfile.
- New `crates/improvise-io/src/lib.rs` re-exports the core modules under
  their conventional names (`format`, `model`, `view`, `workbook`,
  `formula`) so in the next commit the moved code's `crate::model::*`,
  `crate::view::*`, `crate::workbook::*`, `crate::format::*`, and
  `crate::formula::*` paths resolve unchanged.
- Root `Cargo.toml` adds the new crate to workspace members and the main
  crate's `[dependencies]`, ready to receive the move.

No source files change yet; cargo check --workspace still compiles as
before.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 23:05:17 -07:00
Edward Langley 79dc54de21 Merge branch 'main' into worktree-improvise-ewi-formula-crate
# Conflicts:
#	TAGS
2026-04-15 22:47:51 -07:00
Edward Langley 9efbed403a chore: update tags 2026-04-15 22:46:03 -07:00
Edward Langley 03c7c00b25 chore: update tags 2026-04-15 22:45:35 -07:00
Edward Langley 08f190a036 chore: update gitignore 2026-04-15 22:45:18 -07:00
Edward Langley d20eb75a0b feat: roadmap from beads 2026-04-15 22:44:47 -07:00
Edward Langley 30383f203e refactor(keymap): pass mode arguments in keybindings
Update keybindings for normal, records-normal, editing, and records-editing
modes to pass the appropriate mode names as arguments to the parameterized
commands.

This ensures that the correct mode is entered when using commands like
`edit-or-drill` , `enter-edit-at-cursor` , `commit-cell-edit` , and
`commit-and-advance-right` .

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 22:44:13 -07:00
Edward Langley cece34a1d4 refactor(command): parameterize mode-related commands and effects
Make mode-related commands and effects mode-agnostic by passing the target
mode as an argument instead of inspecting the current application mode.

- `CommitAndAdvance` now accepts `edit_mode` .
- `EditOrDrill` now accepts `edit_mode` .
- `EnterEditAtCursorCmd` now accepts `target_mode` .
- `EnterEditAtCursor` effect now accepts `target_mode` .

Update the command registry to parse mode names from arguments and pass
them to the corresponding commands.

Add tests to verify the new mode-passing behavior.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 22:44:13 -07:00
Edward Langley 79f78c496e docs(core): note improvise-core layout in repo-map
Reflect Phase B of improvise-36h: `model/`, `view/`, `workbook.rs`, and
`format.rs` now live in the `improvise-core` sub-crate under `crates/`.

- Sub-crate list expanded to describe improvise-core's scope, its
  dependency on improvise-formula, and the standalone-build guarantee.
- File Inventory reorganized into a single "Core crate layers" block
  covering model/view/workbook/format, with paths rooted at
  `crates/improvise-core/src/`.
- Updated line/test counts to match current contents (Phase A + merge
  with main brought in records mode, IndexMap-backed DataStore, etc).

No architectural change; the main crate's re-exports keep every
`crate::model`/`crate::view`/`crate::workbook`/`crate::format` path
resolving unchanged, so no "How to Find Things" table edits are needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:33:45 -07:00
Edward Langley fc9d9cb52a refactor(core): move model, view, workbook, format into improvise-core
Relocate the four pure-data module trees into the improvise-core
sub-crate scaffolded in the previous commit. Phase A already made
these modules UI/IO-free; this commit is purely mechanical:

  git mv src/format.rs   -> crates/improvise-core/src/format.rs
  git mv src/workbook.rs -> crates/improvise-core/src/workbook.rs
  git mv src/model       -> crates/improvise-core/src/model
  git mv src/view        -> crates/improvise-core/src/view

The moved code contains no path edits: the `crate::formula::*`,
`crate::model::*`, `crate::view::*`, `crate::workbook::*`,
`crate::format::*` imports inside the four trees all continue to
resolve because the new crate mirrors the same module layout and
re-exports improvise_formula under `formula` via its lib.rs.

Main-crate `src/lib.rs` flips from declaring these as owned modules
(`pub mod model;` etc.) to re-exporting them from improvise-core
(`pub use improvise_core::model;` etc.). This keeps every
`crate::model::*`, `crate::view::*`, `crate::workbook::*`,
`crate::format::*` path inside the 26 consumer files in src/ (ui,
command, persistence, import, draw, main) resolving unchanged — no
downstream edits needed.

Verification:
- cargo check --workspace: clean
- cargo test --workspace: 612 passing (357 main + 190 core + 65 formula)
- cargo clippy --workspace --tests: clean
- cargo build -p improvise-core: standalone build succeeds, confirming
  zero UI/IO leakage into the core crate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:31:42 -07:00
Edward Langley 0d75c7bd0b refactor(core): scaffold empty improvise-core sub-crate
Lay the groundwork for Phase B of improvise-36h: a new
`crates/improvise-core/` sub-crate that will house the pure-data core
(model, view, workbook, format) once the files move in the next commit.

Only scaffolding here:
- New `crates/improvise-core/Cargo.toml` mirroring improvise-formula's
  structure; declares deps on improvise-formula, anyhow, indexmap, serde.
- New `crates/improvise-core/src/lib.rs` with the single re-export
  `pub use improvise_formula as formula;` so that in the next commit the
  moved code's `crate::formula::*` paths resolve unchanged.
- Root `Cargo.toml` adds the new crate to the workspace members and the
  main crate's `[dependencies]`, ready to receive the move.

No source files change yet; cargo check --workspace still compiles as
before.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:21:58 -07:00
Edward Langley a22478eb87 Merge branch 'main' into worktree-improvise-ewi-formula-crate
# Conflicts:
#	src/ui/app.rs
#	src/ui/effect.rs
#	src/view/layout.rs
2026-04-15 21:39:00 -07:00
Edward Langley 242ddebb49 chore: matches -> method 2026-04-15 21:33:18 -07:00
Edward Langley 030865a0ff feat(records): implement records mode for data entry
Implement a new "Records" mode for data entry.
- Add `RecordsNormal` and `RecordsEditing` to `AppMode` and `ModeKey` .
- `DataStore` now uses `IndexMap` and supports `sort_by_key()` to ensure
  deterministic row order.
- `ToggleRecordsMode` command now sorts data and switches to
  `RecordsNormal` .
- `EnterEditMode` command now respects records editing variants.
- `RecordsNormal` mode includes a new `o` keybinding to add a record row.
- `RecordsEditing` mode inherits from `Editing` and adds an `Esc` binding
  to return to `RecordsNormal` .
- Added `SortData` effect to trigger data sorting.
- Updated UI to display "RECORDS" and "RECORDS INSERT" mode names and
  styles.
- Updated keymaps, command registry, and view navigation to support these
  new modes.
- Added comprehensive tests for records mode behavior, including sorting
  and boundary conditions for Tab/Enter.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 21:32:35 -07:00
Edward Langley ded35f705c feat(model): use IndexMap for deterministic insertion order in DataStore
Replace `HashMap` with `IndexMap` in `DataStore::cells` to preserve
insertion order. This allows records mode to display rows in the order they
were added. Update `remove` to use `shift_remove` to maintain order during
deletions.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 21:32:35 -07:00
Edward Langley 7c00695398 refactor(navigation): include AppMode in view navigation stack
Introduce `ViewFrame` to store both the view name and the `AppMode` when
pushing to the navigation stack. Update `view_back_stack` and
`view_forward_stack` to use `ViewFrame` instead of `String` . Update
`CmdContext` and `Effect` implementations (SwitchView, ViewBack,
ViewForward) to handle the new `ViewFrame` structure. Add `is_editing()`
helper to `AppMode` .

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 21:32:34 -07:00
Edward Langley 23c7c530e3 refactor(parser): simplify tests and generator logic
Refactor formula parser tests to use more concise assert!(matches!(...))
syntax. Simplify the formula generator implementation by removing unused
expression variants and using expect() for mandatory grammar rules. Add a
regression test for hyphenated identifiers in bare names.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-26B-A4B-it-UD-Q5_K_XL.gguf)
2026-04-15 21:32:34 -07:00