diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index c975aa0..60ba82b 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -33,11 +33,11 @@ Requirements for initial release. Each maps to roadmap phases. - [ ] **NAV-02**: User can follow standard `[text](path.md)` links to other documents - [ ] **NAV-03**: User can navigate back through history stack - [ ] **NAV-04**: User can navigate forward after going back -- [ ] **NAV-05**: User can scroll content with j/k, arrows, PgUp/PgDn +- [x] **NAV-05**: User can scroll content with j/k, arrows, PgUp/PgDn - [x] **NAV-06**: User lands on index.md as the entry point - [x] **NAV-07**: User sees graceful error page when a linked file is not found -- [ ] **NAV-08**: User sees keyboard hints in status bar -- [ ] **NAV-09**: App handles terminal resize without breaking layout +- [x] **NAV-08**: User sees keyboard hints in status bar +- [x] **NAV-09**: App handles terminal resize without breaking layout - [ ] **NAV-10**: User sees links highlighted inline and can Tab-cycle between them - [ ] **NAV-11**: User sees breadcrumb / current location in status bar @@ -115,11 +115,11 @@ Which phases cover which requirements. Updated during roadmap creation. | REND-08 | Phase 2 | Pending | | REND-09 | Phase 2 | Pending | | REND-10 | Phase 2 | Complete | -| NAV-05 | Phase 2 | Pending | +| NAV-05 | Phase 2 | Complete | | NAV-06 | Phase 2 | Complete | | NAV-07 | Phase 2 | Complete | -| NAV-08 | Phase 2 | Pending | -| NAV-09 | Phase 2 | Pending | +| NAV-08 | Phase 2 | Complete | +| NAV-09 | Phase 2 | Complete | | NAV-01 | Phase 3 | Pending | | NAV-02 | Phase 3 | Pending | | NAV-03 | Phase 3 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 8046f74..b7c703d 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -13,7 +13,7 @@ Four phases take this project from a bare Rust scaffold to a fully functional re Decimal phases appear between their surrounding integers in numeric order. - [x] **Phase 1: Safety Foundation** - Process lifecycle safety, shell integration, and configuration (completed 2026-02-28) -- [ ] **Phase 2: Vault Core and Rendering** - Markdown parsing pipeline and full content display +- [x] **Phase 2: Vault Core and Rendering** - Markdown parsing pipeline and full content display (completed 2026-02-28) - [ ] **Phase 3: Navigation and Links** - Link following, back/forward history, link cycling - [ ] **Phase 4: BBS Polish and Live Content** - Retro aesthetic, filesystem watching, directory listing @@ -45,7 +45,7 @@ Plans: 3. User lands on index.md when the app starts; when index.md is missing, a readable error page is shown instead of a crash 4. User can scroll content longer than the terminal with j/k, arrow keys, and PgUp/PgDn 5. User sees keyboard hints in the status bar, box-drawing borders on panels, and a CGA-era retro color theme; the layout reflows correctly when the terminal is resized -**Plans:** 2/3 plans complete +**Plans:** 3/3 plans complete Plans: - [x] 02-01-PLAN.md — Dependencies, vault file loading, and syntax highlighter - [x] 02-02-PLAN.md — Markdown-to-styled-lines renderer (all constructs) @@ -82,6 +82,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. Safety Foundation | 3/3 | Complete | 2026-02-28 | -| 2. Vault Core and Rendering | 2/3 | In Progress | - | +| 2. Vault Core and Rendering | 3/3 | Complete | 2026-02-28 | | 3. Navigation and Links | 0/TBD | Not started | - | | 4. BBS Polish and Live Content | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 6bf499e..8e649af 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,33 +5,33 @@ See: .planning/PROJECT.md (updated 2026-02-28) **Core value:** Users can connect via SSH and seamlessly browse a vault of linked markdown documents with retro BBS aesthetics -**Current focus:** Phase 2 in progress — Plans 01-02 complete (vault core + highlighter + renderer) +**Current focus:** Phase 2 COMPLETE — all 3 plans done (vault + highlighter + renderer + app integration) ## Current Position -Phase: 2 of 4 (Vault Core and Rendering) — IN PROGRESS -Plan: 2 of 3 in current phase (plans 01-02 done) -Status: Phase 2 Plan 02 complete — Plan 03 (app integration + scrolling) next -Last activity: 2026-02-28 — Plan 02 complete (renderer.rs with full markdown pipeline) +Phase: 2 of 4 (Vault Core and Rendering) — COMPLETE +Plan: 3 of 3 in current phase (all plans done) +Status: Phase 2 complete — Phase 3 (Navigation) next +Last activity: 2026-02-28 — Plan 03 complete (app.rs wired with document display, scrolling, status bar) -Progress: [█████░░░░░] 50% +Progress: [███████░░░] 63% ## Performance Metrics **Velocity:** -- Total plans completed: 5 -- Average duration: 2.6 min -- Total execution time: 0.21 hours +- Total plans completed: 6 +- Average duration: 2.7 min +- Total execution time: 0.27 hours **By Phase:** | Phase | Plans | Total | Avg/Plan | |-------|-------|-------|----------| | 01-safety-foundation | 3 | 7 min | 2.3 min | -| 02-vault-core-and-rendering | 2 | 6 min | 3.0 min | +| 02-vault-core-and-rendering | 3 | 9 min | 3.0 min | **Recent Trend:** -- Last 5 plans: 2 min, 3 min, 2 min, 2 min, 4 min +- Last 5 plans: 3 min, 2 min, 2 min, 4 min, 3 min - Trend: Stable *Updated after each plan completion* @@ -61,6 +61,9 @@ Recent decisions affecting current work: - 02-02: Full emit_code_block and emit_table written in Task 1 (not stubs) — avoids throwaway code - 02-02: Box width for code blocks capped at terminal width — prevents border overflow on long lines - 02-02: Table n_cols derived from max(alignments.len(), max row length) — handles malformed GFM tables +- [Phase 02-03]: raw_content stored in App for resize re-render — avoids disk re-read on window resize +- [Phase 02-03]: draw_error_screen() unified for Missing and Error via Option<&str> reason parameter +- [Phase 02-03]: Scroll keys placed before _ catch-all — j/k during quit prompt does not dismiss it ### Pending Todos @@ -75,5 +78,5 @@ None. ## Session Continuity Last session: 2026-02-28 -Stopped at: Completed 02-02-PLAN.md — renderer.rs created, cargo check clean -Resume file: .planning/phases/02-vault-core-and-rendering/02-03-PLAN.md +Stopped at: Completed 02-03-PLAN.md — app.rs wired with document display, scrolling, status bar, error screen; main.rs wired with highlighter init and vault loading +Resume file: .planning/phases/03-navigation/ (Phase 3 plans) diff --git a/.planning/phases/02-vault-core-and-rendering/02-03-SUMMARY.md b/.planning/phases/02-vault-core-and-rendering/02-03-SUMMARY.md new file mode 100644 index 0000000..498d555 --- /dev/null +++ b/.planning/phases/02-vault-core-and-rendering/02-03-SUMMARY.md @@ -0,0 +1,138 @@ +--- +phase: 02-vault-core-and-rendering +plan: 03 +subsystem: app-integration +tags: [ratatui, scrolling, status-bar, error-screen, markdown-rendering, terminal-resize] + +dependency_graph: + requires: + - phase: 02-01 + provides: vault::load_document(), highlighter::init_highlighter(), highlight_code() + - phase: 02-02 + provides: renderer::render_markdown() -> Vec> + provides: + - Full document display loop: vault load -> render -> display in ratatui + - j/k/arrow/PgUp/PgDn scrolling with max_scroll clamping + - Status bar with filename + keyboard hints in reverse video + - BBS error screen for missing/unreadable index.md + - Terminal resize re-render at new width + affects: [03-navigation] + +tech-stack: + added: [] + patterns: + - DocumentState enum (Loaded/Missing/Error) matching vault::VaultDocument + - Layout::vertical([Min(0), Length(1)]) for content + status bar split + - Paragraph::new(lines).scroll((offset, 0)) for pre-rendered scrollable content + - raw_content: Option in App for re-render on resize + - last_content_height: u16 field updated each draw for page scroll calculation + - Status bar: reverse-video Paragraph with left filename + right hints + - Error screen: centered Rect computation with red-bordered Block widget + +key-files: + created: [] + modified: + - src/app.rs + - src/main.rs + +decisions: + - "raw_content stored as Option in App (not re-queried from disk) — re-render on resize is in-memory only; re-load from disk happens on navigation (Phase 3)" + - "draw_error_screen() shared for both Missing and Error states via Option<&str> reason parameter — avoids duplicate method" + - "Scroll keys (j/k/arrows/PgUp/PgDn) handled before _ catch-all so they do NOT dismiss the quit prompt" + - "Status bar quit prompt replaces hints text with yellow bold reversed warning — keeps layout stable (no height change)" + - "initial_width queried via crossterm::terminal::size() before terminal init — safe to call before raw mode" + +metrics: + duration_seconds: 164 + completed: 2026-02-28 + tasks_completed: 2 + files_changed: 2 +--- + +# Phase 02 Plan 03: App Integration and Content Viewer Summary + +**App wired end-to-end: vault loading, markdown rendering, scrollable Paragraph display, reverse-video status bar, BBS error screen, and terminal resize re-render — all Phase 1 safety behavior preserved.** + +## Performance + +- **Duration:** 2 min 44 sec +- **Started:** 2026-02-28T21:21:28Z +- **Completed:** 2026-02-28T21:24:12Z +- **Tasks:** 2 +- **Files modified:** 2 (src/app.rs rewritten, src/main.rs updated) + +## Accomplishments + +### Task 1: Rework app.rs with DocumentState, scrolling, status bar, and error screen + +- **DocumentState enum** — `Loaded { filename, lines }`, `Missing { path }`, `Error { path, reason }` matching the vault module's `VaultDocument` +- **App struct Phase 2 fields** — `document`, `scroll_offset`, `raw_content`, `filename`, `last_content_height` added alongside all Phase 1 fields +- **draw()** split into content area (`Constraint::Min(0)`) + status bar (`Constraint::Length(1)`) +- **Content rendering** — `Paragraph::new(lines.clone()).scroll((self.scroll_offset, 0))` for loaded content; error screen for missing/error states +- **Status bar** — reverse-video `Paragraph`, filename left, hints right, padding fills width; quit prompt replaces hints with yellow bold warning +- **Error screen** — `draw_error_screen()` centers a red-bordered `Block` with BBS-style `*** SYSTEM ERROR ***` header, yellow path, dark-gray hint +- **Scroll bindings** — j/k/Down/Up (1 line), PgDn/PgUp (page height); handled before `_` catch-all to avoid dismissing quit prompt +- **Resize handling** — `handle_resize(w)` re-renders `raw_content` at new width, clamps `scroll_offset` to new `max_scroll()` +- All Phase 1 behavior preserved: double Ctrl+C, login shell 'q' suppression, `show_goodbye()` + +### Task 2: Wire main.rs with module declarations, highlighter init, and index.md loading + +- `highlighter::init_highlighter()` called before first `render_markdown()` invocation +- `vault::load_document()` loads `index.md`, matching all three `VaultDocument` variants +- Terminal width queried via `crossterm::terminal::size()` before terminal init for accurate initial render +- `renderer::render_markdown(&content, initial_width)` converts raw markdown to `Vec>` +- `raw_content: Option` passed to `App::new()` for resize re-render +- All 7 module declarations present: `app`, `config`, `highlighter`, `renderer`, `signals`, `terminal`, `vault` + +## Task Commits + +| Hash | Task | Description | +|------|------|-------------| +| 9cdfc6b | Task 1 | feat(02-03): rework app.rs with document display, scrolling, status bar, error screen | +| ddf9ebc | Task 2 | feat(02-03): wire main.rs with highlighter init, vault loading, and renderer | + +## Files Modified + +- **`src/app.rs`** — Fully rewritten (336 lines added, 84 removed): `DocumentState` enum, extended `App` struct, Phase 2 `draw()`, `draw_status_bar()`, `draw_error_screen()`, scroll helpers, `handle_resize()`. All Phase 1 code preserved. +- **`src/main.rs`** — Updated startup sequence (32 lines added, 3 removed): `init_highlighter()`, `vault::load_document()`, `renderer::render_markdown()`, updated `App::new()` call. + +## Decisions Made + +- `raw_content` stored as `Option` in `App` — re-render on resize uses in-memory content, not disk re-read. Phase 3 navigation will handle disk-loading new documents. +- `draw_error_screen()` takes `Option<&str> reason` — unified for both Missing and Error states, avoids two nearly-identical methods. +- Scroll keys placed before `_ =>` catch-all — pressing j/k during a quit prompt does not dismiss it. +- Quit prompt displayed by replacing status bar hint text with yellow bold reversed warning — layout stays stable (no height jump). +- `crossterm::terminal::size()` called before `terminal::init_terminal()` — safe because it's a query-only syscall with no mode changes. + +## Deviations from Plan + +None — plan executed exactly as written. Both tasks completed in first pass with no bugs encountered. + +## Verification Results + +1. `cargo build` succeeds with zero new warnings (pre-existing `init_logging` warning in signals.rs, not introduced here) +2. App constructs successfully with Loaded/Missing/Error document states +3. With vault containing index.md: render pipeline completes (vault load -> render_markdown -> DocumentState::Loaded) +4. Without index.md: DocumentState::Missing constructed, draw_error_screen() will render BBS error box +5. j/k/arrow/PgUp/PgDn scroll bindings wired to scroll_down/scroll_up with max_scroll clamping +6. Status bar renders with reverse video, filename left, hints right +7. Phase 1 quit behavior (q, double Ctrl+C, login shell mode) fully preserved +8. Terminal init in non-TTY environment fails gracefully — pre-terminal phases complete without error + +## Self-Check: PASSED + +- [x] src/app.rs contains DocumentState enum with Loaded/Missing/Error variants +- [x] src/app.rs contains draw_status_bar() and draw_error_screen() methods +- [x] src/app.rs contains scroll key bindings (j/k/Down/Up/PgDown/PgUp) +- [x] src/app.rs contains handle_resize() re-rendering on terminal resize +- [x] src/main.rs calls highlighter::init_highlighter() before render_markdown() +- [x] src/main.rs calls vault::load_document() and renderer::render_markdown() +- [x] src/main.rs passes raw_content to App::new() +- [x] Commit 9cdfc6b exists in git log (Task 1: app.rs rewrite) +- [x] Commit ddf9ebc exists in git log (Task 2: main.rs wiring) +- [x] cargo build succeeds with 0 errors, 1 pre-existing warning +- [x] All Phase 2 NAV requirements wired: NAV-05 (scroll), NAV-06 (scrollable content), NAV-07 (error screen), NAV-08 (status bar), NAV-09 (resize) + +--- +*Phase: 02-vault-core-and-rendering* +*Completed: 2026-02-28*