197 lines
12 KiB
Markdown
197 lines
12 KiB
Markdown
# viexp Roadmap — Rust + English in 20-hour sprints
|
||
|
||
Method: Josh Kaufman, **"The First 20 Hours"** — rapid skill acquisition. The project is split
|
||
into isolated 20-hour sprints (~45 min/day for a month each). Every sprint: one Rust sub-skill,
|
||
one working app increment, one English artifact. The goal of each sprint is to cross the
|
||
frustration barrier and ship something that runs — not perfect code.
|
||
|
||
**Kaufman's rules, adapted**
|
||
|
||
| Kaufman principle | How this roadmap applies it |
|
||
|---|---|
|
||
| Deconstruct the skill | The table below: each sprint = one sub-skill + one app increment |
|
||
| Learn just enough to self-correct | Per-sprint "Rust focus — the vital 20%": the minimum theory to *read your own compiler errors*. Every error goes to the ErrorJournal with a self-correction cue |
|
||
| Remove barriers to practice | Sprint 0 sets up the whole environment: toolchain, linters, fast feedback (`bacon`), Gitea board, CI. Never debug your setup during practice time |
|
||
| Fast feedback loops | `cargo check`/bacon on save, unit tests per session, immediate AI code review of each session's diff (commit → review → fix) |
|
||
| Quantity over quality | Many small commits, many small drills. Working ugly code beats beautiful unfinished code. No over-engineering before v0.1 |
|
||
|
||
## Skill deconstruction
|
||
|
||
**Rust sub-skills** (learned in order): cargo & project layout → types & control flow →
|
||
ownership/borrowing → structs, enums, pattern matching → `Option`/`Result` & `?` →
|
||
modules & crates → traits & generics → iterators → `Path`/`fs` & error handling (`thiserror`/`anyhow`) →
|
||
serde/TOML → lifetimes → trait objects & dynamic dispatch → threads & channels →
|
||
async/await & tokio → process spawning → caching & performance.
|
||
|
||
**App increments** (each demoable): `vls` CLI → 3-pane TUI → navigation & file ops →
|
||
config & openers → text previews → image previews → document previews → media & async →
|
||
script plugins → power features → performance → release.
|
||
|
||
**English track**: every commit message, every issue, all docs — English only. One written
|
||
artifact per sprint. Daily DevLog (3–5 sentences). See [[workflows/english-workflow|English workflow]].
|
||
|
||
## Session rhythm (45 min, every day)
|
||
|
||
1. **5 min** — read yesterday's DevLog + ErrorJournal; `git pull`, `bacon` starts.
|
||
2. **30 min** — today's drill or feature slice (one drill = one commit).
|
||
3. **10 min** — get the diff reviewed, fix what the reviewer flags, write the DevLog entry.
|
||
|
||
**Frustration rules**: stuck >20 min on one error → ask for a review instead of grinding;
|
||
never end a session with broken code (revert to green); a slow day is a reading day
|
||
(Rust Book chapter in English) — log it, no guilt.
|
||
|
||
## Sprints
|
||
|
||
Legend: 🎯 milestone. Each sprint gets a `docs/sprints/sprint-NN-*.md` note (Sprint template)
|
||
and a Gitea milestone with issues created from its Definition of Done.
|
||
|
||
---
|
||
|
||
### Sprint 0 — Setup & deconstruction (≈6 h, short)
|
||
- **App deliverable**: empty `viexp` cargo project that compiles, `cargo test` runs one trivial
|
||
test, CI (Gitea Actions) is green, `bacon` + `clippy` + `rustfmt` wired, Gitea board ready.
|
||
- **Rust focus**: toolchain mental model — what cargo, rustc, crates.io, `Cargo.toml` are;
|
||
read your first compiler error on purpose (break a program, fix it).
|
||
- **English**: README "Status" section + the vault (this roadmap counts).
|
||
- **DoD**: `cargo bacon` shows check+test on save; first commit pushed; Sprint-1 issues exist.
|
||
|
||
### Sprint 1 — Rust core via `vls` (20 h)
|
||
- **App deliverable**: `viexp ls` subcommand — a better `ls`: colored names by type,
|
||
human-readable sizes, `--sort name|size|mtime`, `--hidden`, `--long`; ≥10 unit tests.
|
||
- **Rust focus (vital 20%)**: variables & types, functions, `if`/`match`, loops, `Vec`/`String`
|
||
vs `&str`, structs & enums, `Option`/`Result` + `?`, modules, `#[cfg(test)]`.
|
||
Rust Book ch. 1–9 (skim 7/8), rustlings `intro→enums`.
|
||
- **English**: README usage section; article "Why build a file manager in Rust" (draft).
|
||
- **DoD**: `vls ~/` output beats `ls` for your eyes; clippy clean; tests green.
|
||
|
||
### Sprint 2 — First TUI (20 h) — the borrow-checker sprint
|
||
- **App deliverable**: three-pane Miller layout (parent / current / placeholder preview),
|
||
`j/k/gg/G` cursor movement, `:q` quits, resize-safe redraw, no flicker.
|
||
- **Rust focus**: **ownership & borrowing in anger** (the state struct owns everything),
|
||
references vs clones, lifetimes as they appear in ratatui calls, the event-loop pattern
|
||
(poll event → mutate state → redraw). Rust Book ch. 4, 10.3 (skim), ratatui official docs.
|
||
- **English**: keymap reference table in docs (precise imperative phrasing).
|
||
- **DoD**: navigate a 10k-file directory smoothly; panic-free for 15 min of use.
|
||
|
||
### Sprint 3 — Navigation & file ops (20 h) 🎯 **M1: personal daily driver**
|
||
- **App deliverable**: enter/leave directories, hidden toggle, sort cycling, `Space`/`V`
|
||
selection, `yy`/`dd`/`pp` copy/cut/paste, delete → **first-class trash** (freedescompliant)
|
||
with undo, `:mkdir :touch :rename`, status bar (path, size, free space — **not** per-frame
|
||
`statvfs`; 1 Hz poll).
|
||
- **Rust focus**: `Path`/`PathBuf`, `fs::read_dir`/`metadata`, real error handling
|
||
(`thiserror` for lib-style internals, `anyhow` at main), iterators (`map/filter/sort_by`
|
||
chains), `Display` impls.
|
||
- **English**: article "Week one of dogfooding my own file manager".
|
||
- **DoD**: use viexp instead of ranger for real work for 3 days; log every pain point as an issue.
|
||
|
||
### Sprint 4 — Config & openers (20 h)
|
||
- **App deliverable**: `viexp.toml` (defaults, theme colors, sort) + `modules.toml` registry
|
||
v0 (ADR-003): mime/glob → opener, per-module `enabled`, user rules prepend/append;
|
||
opener engine (infer + xdg-mime → rule table → `xdg-open` fallback), `r` "open with" menu,
|
||
`:open_with`.
|
||
- **Rust focus**: serde derive on enums/structs, `Default` + merge semantics, `HashMap`/
|
||
`BTreeMap`, first **trait design** (`Opener`), builder-ish config loading with helpful errors.
|
||
- **English**: configuration guide draft (reference-style writing).
|
||
- **DoD**: any file opens with your preferred app from config alone; broken TOML produces a
|
||
friendly error, not a panic.
|
||
|
||
### Sprint 5 — Text previews & bulk rename (20 h)
|
||
- **App deliverable**: preview pane v1 — syntax-highlighted text (syntect) with line numbers
|
||
and scrolling, directory preview, file metadata panel, zip/tar listing, `:bulkrename` via
|
||
`$EDITOR` (ranger's killer feature), `n/N` plain search, `:` command history.
|
||
- **Rust focus**: lifetimes in real signatures, **trait objects** (`Box<dyn Previewer>` registry),
|
||
advanced iterators, caching keyed by `(path, mtime)`.
|
||
- **English**: article "How a TUI paints text" (explaining rendering → strongest writing practice).
|
||
- **DoD**: preview parity with ranger for text/code/archive files.
|
||
|
||
### Sprint 6 — Image previews (20 h) 🎯 **M2a**
|
||
- **App deliverable**: image module through the registry; **kitty graphics adapter first**
|
||
(owner's terminal), chafa/halfblocks floor; thumbnail disk cache + LRU; runtime
|
||
disable/replace via `modules.toml` proven on images.
|
||
- **Rust focus**: the `image` crate, decode/resize pipeline, `#[cfg(feature)]` modules,
|
||
pixel data, spawning helper processes safely.
|
||
- **English**: article "How terminals display images" (kitty protocol, sixel, ueberzug++ —
|
||
your best future blog post; research notes already hold the material).
|
||
- **DoD**: PNG/JPEG/WebP/GIF preview instantly in kitty; `enabled=false` kills it in one line.
|
||
|
||
### Sprint 7 — Document previews (20 h) 🎯 **M2b: full ranger replacement**
|
||
- **App deliverable**: PDF (pdfium-render, Apache-2.0), EPUB (hand-rolled zip+XML — **GPL
|
||
trap avoided**), Markdown (comrak/termimad), DJVU (djvu-rs + `ddjvu` fallback config).
|
||
All as registry modules, all runtime-disableable.
|
||
- **Rust focus**: binary data & byte streams, feature-gated crates, error taxonomy design,
|
||
more trait objects; reading crate docs as a skill.
|
||
- **English**: module documentation pages (PDF/EPUB/DJVU) in user-guide style.
|
||
- **DoD**: your entire document library previews; ranger uninstalled.
|
||
|
||
### Sprint 8 — Media & async (20 h) 🎯 **M2c**
|
||
- **App deliverable**: video thumbnail (spawn `ffmpeg -ss … -vframes 1`), audio metadata +
|
||
cover art (`ffprobe` JSON), **background preview pipeline**: std threads + mpsc now,
|
||
generation-counter cancellation, large-directory pagination; adopt **tokio** for the
|
||
pipeline by sprint end (ADR-005).
|
||
- **Rust focus**: `std::thread`, `mpsc`, `Arc`/`Mutex`, then async/await, `tokio::spawn`,
|
||
`select!`, cancellation patterns. Rust Book ch. 16 + async book chapters (English only!).
|
||
- **English**: article "Async Rust for a skeptic" — explain threads-vs-tokio in your own words.
|
||
- **DoD**: 4K-video directory scrolls at full speed; huge directory never blocks input.
|
||
|
||
### Sprint 9 — Script plugin protocol (20 h) 🎯 **M3a: extensible**
|
||
- **App deliverable**: freeze the **external plugin contract** (ADR-002 phase 2): previewer
|
||
argv `(path, w, h, x, y)` + env context + FIFO write-back + `cleaner` hook; documented
|
||
exit codes & SIGPIPE; opener scripts; `plugins/` dir discovery; two reference plugins
|
||
(bash: torrent info; python: git repo summary).
|
||
- **Rust focus**: process spawning & pipes, timeouts, safe command construction (no shell
|
||
injection), protocol design & semver, integration tests with fixture scripts.
|
||
- **English**: **plugin author guide** — the sprint's main artifact; write it as if for strangers.
|
||
- **DoD**: a script written only from the guide (no source peeking) works.
|
||
|
||
### Sprint 10 — Power features (20 h) 🎯 **M3b: feature parity with your ranger config**
|
||
- **App deliverable**: tabs, bookmarks + marks, fuzzy finder (nucleo) with **interruptible**
|
||
search (broot lesson), `:commands` set (`:find :delete :copy…`), `push` key-simulation,
|
||
shell integration `--choosefile/--choosedir/--selectfile`, cd-on-exit wrapper script,
|
||
session restore.
|
||
- **Rust focus**: state machines (modes), Rc-free architecture review, `macro_rules!` for
|
||
keymap tables, API refactoring under tests.
|
||
- **English**: article "Vim-style UX patterns in file managers".
|
||
- **DoD**: your shell rc sources the viexp wrapper; fuzzy find feels instant.
|
||
|
||
### Sprint 11 — Performance & robustness (20 h)
|
||
- **App deliverable**: `notify`-based live directory updates, virtual scrolling, startup
|
||
<50 ms, one-week dogfood with zero panics, `tracing` logs to file, panic hook restores
|
||
the terminal, criterion benchmarks committed, crash-fix buffer.
|
||
- **Rust focus**: profiling (`cargo flamegraph`, `perf`), benchmarking (criterion), reading
|
||
someone else's code (yazi's) for patterns, hardening.
|
||
- **English**: article "Profiling a TUI app: making viexp start in 40 ms".
|
||
- **DoD**: benchmark numbers in README; a week of daily use logged.
|
||
|
||
### Sprint 12 — Release & docs (20 h) 🎯 **M4: v0.1.0 public**
|
||
- **App deliverable**: `v0.1.0` — cargo-dist release builds, AUR PKGBUILD, Gitea release +
|
||
changelog, **user guide** (mdBook in-repo), plugin examples gallery, install docs.
|
||
- **Rust focus**: release engineering, MSRV policy, feature matrix testing, rustdoc comments
|
||
on the public plugin API.
|
||
- **English**: the user guide is the largest English artifact of the project; polish it hard.
|
||
- **DoD**: a stranger installs from AUR and writes a plugin using only the docs.
|
||
|
||
### Backlog (post-1.0, priority order)
|
||
Embedded Lua plugins (mlua, ADR-002 phase 3) · sixel/iTerm2/ueberzug++ adapters · DDS-style
|
||
inter-instance pub/sub · `NNN_FIFO`-style hover event stream · themes gallery · zoxide jump ·
|
||
archive mount/browsing depth.
|
||
|
||
## Milestones
|
||
|
||
| Milestone | After sprint | Meaning |
|
||
|---|---|---|
|
||
| M1 | 3 | daily driver for basic navigation/file ops |
|
||
| M2a–c | 6–8 | full ranger replacement (images, docs, media) |
|
||
| M3a–b | 9–10 | extensible by scripts, feature parity |
|
||
| M4 | 12 | v0.1.0 released publicly |
|
||
|
||
At 45 min/day this is roughly a 12–13 month journey to v0.1.0 — the point is a working
|
||
product **and** durable skills, in that order, every single sprint.
|
||
|
||
## Cadence & safety nets
|
||
|
||
- Sprint notes live in `docs/sprints/`; each sprint's DoD becomes Gitea issues (milestone per
|
||
sprint) — see [[workflows/gitea-workflow|Gitea workflow]].
|
||
- If a sprint overruns by >30%, cut scope from the bottom of its DoD — never silently skip tests.
|
||
- One "buffer week" is allowed between sprints; more than one means the sprint was too big —
|
||
re-decompose in the retro.
|