Fix bugs and improve robustness across the codebase

- Fix staged files being silently cleared when commit uses inline files
- Refactor step navigation to use direct go_to_step instead of fragile delta math
- Change step numbers from i32 to u32 (reject negative values at parse time)
- Add tour rm command to mark files for removal during carry-forward
- Add tour reset command to clear session and remove tracked files
- Consolidate duplicate recursive copy functions into shared copy_tree in utils
- Validate step directories are sequential (detect corruption)
- Detect binary files in diffs instead of showing garbage
- Use /// doc comments on enum variants so clap generates proper help text
- Remove custom Help subcommand in favor of clap's built-in --help
- Add CorruptedTour error variant for integrity checks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 21:23:39 +00:00
parent 399a72f380
commit 507c61fe5f
19 changed files with 1513 additions and 268 deletions

View File

@@ -16,26 +16,42 @@ cargo clippy # lint
`tour` is a CLI tool for creating and navigating code tutorials as a series of snapshots. Authors create tours by committing file snapshots with explanations; readers step through them with `next`/`prev`.
**Author workflow:** `tour init``tour commit <files> -m <msg>` (repeat) → `tour end -m <msg>`
**Author workflow:** `tour init``tour add <files>``tour commit -m <msg>` (repeat) → `tour end -m <msg>`
**Reader workflow:** `tour start``tour next [n]` / `tour prev [n]`
**Reader workflow:** `tour start``tour next [n]` / `tour prev [n]` / `tour step <n>` / `tour reset`
## Architecture
Entry point is `main.rs`, which uses clap's derive macro to parse subcommands and dispatch to per-command modules.
**On-disk format** (stored in `.tour/` in the project being toured):
- `.tour/steps/<N>/` — one numbered directory per step
- `.tour/steps/<N>/` — one numbered directory per step (each step is a complete file snapshot)
- `.tour/steps/<N>/message` — the commit message for that step
- `.tour/session` — tracks current reader position as `STEP=<n>`
- `.tour/staged` — list of files staged for the next commit
- `.tour/info` — tour metadata (author, description, language, dates)
- `.tour/removed` — list of files marked for removal in the next commit
- `.tour/ended` — marker file indicating the tour is finalized
**Module layout:**
- `init.rs` — creates `.tour/steps/` and `.tour/session`
- `commit.rs`validates files, then saves them as a new numbered step
- `end.rs`finalizes the tour
- `next.rs` / `prev.rs` — advance/retreat the session step
- `utils.rs`shared helpers: `copy_files`, `get_session_step`, `get_tour_step`, path validation
- `error.rs`custom error types (currently `CommitError`)
- `init.rs` — creates `.tour/` structure, collects tour metadata, updates `.gitignore`
- `add.rs`stages files for the next commit; `get_staged()` reads the staged file list
- `unstage.rs`removes files from staging
- `commit.rs` — commits staged files as a new step with carry-forward from previous step; only clears staging when staging was used
- `rm.rs`marks files for removal in the next commit (skipped during carry-forward)
- `end.rs`finalizes the tour (writes `.tour/ended` marker)
- `step.rs` — navigation: `next`, `prev`, `step_n`; handles file replacement, diff display, binary detection
- `reset.rs` — resets tour session and removes tracked files from working directory
- `status.rs` — shows current step position and staged files
- `list.rs` — lists all steps with their messages
- `info.rs` — tour metadata (author, description, language, dates)
- `utils.rs` — shared helpers: `require_tour`, `get_current_step`, `get_tour_step`, `copy_tree`, path validation
- `error.rs` — unified `TourError` enum with `Display` impl for user-facing messages; includes `CorruptedTour` for integrity checks
Constants `TOUR_DIR` and `SESSION_PATH` are defined in `main.rs` and imported via `crate::`.
**Key design decisions:**
- Each step is a **complete snapshot**`commit.rs` carries forward files from the previous step before overlaying new ones
- `TourError` is the unified error type across all modules, with `From<io::Error>` for automatic conversion
- `main()` catches errors and prints them with `Display` format (not `Debug`) for user-friendly messages
- Constants `TOUR_DIR` and `SESSION_PATH` are defined in `main.rs` and imported via `crate::`
**Status:** Early development. `next`, `prev`, and `end` are stubbed. `commit` validates paths but hasn't yet written the step to disk. `utils::get_tour_step` has a dead `Ok(0)` after a `match` expression (unreachable code).
**Testing:** Integration tests in `tests/integration.rs` use `tempfile` crate to create isolated tour directories and test via `Command`-based process spawning.