diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 6a30808..cf3adfa 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -49,7 +49,7 @@ Requirements for initial release. Each maps to roadmap phases. ### Live Content - [ ] **LIVE-01**: App watches filesystem for changes and auto-refreshes current page -- [ ] **LIVE-02**: User can browse a vault-wide directory listing +- [x] **LIVE-02**: User can browse a vault-wide directory listing ### Configuration @@ -129,7 +129,7 @@ Which phases cover which requirements. Updated during roadmap creation. | BBS-01 | Phase 4 | Pending | | BBS-02 | Phase 4 | Pending | | LIVE-01 | Phase 4 | Pending | -| LIVE-02 | Phase 4 | Pending | +| LIVE-02 | Phase 4 | Complete | **Coverage:** - v1 requirements: 32 total diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index ec53ca0..f1d37b1 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -75,7 +75,7 @@ Plans: 2. Each page shows the file's last-modified timestamp 3. When a markdown file in the vault is modified on disk, the currently displayed page auto-refreshes without the user doing anything 4. User can navigate to a vault-wide directory listing showing all available documents -**Plans:** 3 plans +**Plans:** 2/3 plans executed Plans: - [x] 04-01-PLAN.md — ANSI splash screen on index.md and file metadata in status bar - [ ] 04-02-PLAN.md — Virtual directory listing via [[Directory]] wiki-link @@ -91,4 +91,4 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 | 1. Safety Foundation | 3/3 | Complete | 2026-02-28 | | 2. Vault Core and Rendering | 3/3 | Complete | 2026-02-28 | | 3. Navigation and Links | 2/2 | Complete | 2026-02-28 | -| 4. BBS Polish and Live Content | 1/3 | In progress | - | +| 4. BBS Polish and Live Content | 2/3 | In Progress| | diff --git a/.planning/STATE.md b/.planning/STATE.md index 15627e6..85845c3 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,23 +5,23 @@ 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 4 IN PROGRESS — Plan 01 done (splash screen, file metadata, all Phase 4 deps), Plans 02-03 remaining +**Current focus:** Phase 4 IN PROGRESS — Plans 01-02 done, Plan 03 (live reload) remaining ## Current Position Phase: 4 of 4 (BBS Polish and Live Content) — IN PROGRESS -Plan: 1 of 3 in current phase (04-01 done, 04-02 next) -Status: 04-01 complete — splash screen, file metadata in status bar, Phase 4 dependencies added -Last activity: 2026-03-01 — Plan 01 complete (splash.rs, PageMeta, ansi-to-tui/notify/walkdir deps) +Plan: 2 of 3 in current phase (04-01, 04-02 done, 04-03 next) +Status: 04-02 complete — [[Directory]] virtual page with tree view, Tab-cycling, history back/forward +Last activity: 2026-03-01 — Plan 02 complete (DirEntry, list_vault_files, navigate_to_directory, build_directory_lines) -Progress: [████████░░] 80% +Progress: [█████████░] 87% ## Performance Metrics **Velocity:** -- Total plans completed: 8 -- Average duration: 2.9 min -- Total execution time: 0.39 hours +- Total plans completed: 9 +- Average duration: 3.1 min +- Total execution time: 0.44 hours **By Phase:** @@ -30,10 +30,10 @@ Progress: [████████░░] 80% | 01-safety-foundation | 3 | 7 min | 2.3 min | | 02-vault-core-and-rendering | 3 | 9 min | 3.0 min | | 03-navigation-and-links | 2 | 7 min | 3.5 min | -| 04-bbs-polish-and-live-content | 1 | 4 min | 4.0 min | +| 04-bbs-polish-and-live-content | 2 | 12 min | 6.0 min | **Recent Trend:** -- Last 5 plans: 2 min, 2 min, 4 min, 3 min, 4 min +- Last 5 plans: 2 min, 4 min, 3 min, 4 min, 8 min - Trend: Stable *Updated after each plan completion* @@ -73,6 +73,9 @@ Recent decisions affecting current work: - [Phase 03-02]: navigate_back/forward re-loads from disk (no render cache) per research recommendation - [Phase 03-02]: Draw-time REVERSED uses lines.clone() per frame — stored lines unchanged for resize re-render - [Phase 03-02]: Span overlap detection extended beyond plan spec — catches spans starting before col_offset that extend into link range +- [Phase 04]: resolve_wiki_link() Directory sentinel placed before rfind('/') split — prevents 'directory' being misinterpreted as a subpath prefix +- [Phase 04]: navigate_back/forward use if/else-if branch for __directory__ not load_document — avoids spurious Missing document state for virtual page +- [Phase 04]: handle_resize() returns early for __directory__ — raw_content is None for virtual pages, prevents stale-content confusion ### Pending Todos @@ -86,6 +89,6 @@ None. ## Session Continuity -Last session: 2026-02-28 -Stopped at: Completed 03-02-PLAN.md (Phase 3 complete) -Resume file: .planning/phases/04-live-reload/04-01-PLAN.md +Last session: 2026-03-01 +Stopped at: Completed 04-02-PLAN.md +Resume file: .planning/phases/04-bbs-polish-and-live-content/04-03-PLAN.md diff --git a/.planning/phases/04-bbs-polish-and-live-content/04-02-SUMMARY.md b/.planning/phases/04-bbs-polish-and-live-content/04-02-SUMMARY.md new file mode 100644 index 0000000..a1d0678 --- /dev/null +++ b/.planning/phases/04-bbs-polish-and-live-content/04-02-SUMMARY.md @@ -0,0 +1,114 @@ +--- +phase: 04-bbs-polish-and-live-content +plan: 02 +subsystem: ui +tags: [walkdir, ratatui, rust, directory-listing, virtual-page, tab-cycling, navigation-history] + +# Dependency graph +requires: + - phase: 04-01 + provides: "walkdir = 2.5 in Cargo.toml, navigation history (navigate_back/forward), link_records + Tab-cycling, splash prepend pattern" +provides: + - "resolve_wiki_link() returns PathBuf::from('__directory__') for case-insensitive 'Directory' wiki-link" + - "DirEntry struct and list_vault_files() in vault.rs using WalkDir::new().sort_by_file_name()" + - "navigate_to_directory() method builds tree view via build_directory_lines() and pushes history entry" + - "build_directory_lines() emits yellow-bold directory entries and cyan bracketed file links with LinkRecord" + - "navigate_back/forward handle __directory__ sentinel — regenerate listing fresh each visit" + - "handle_resize() skips re-render for __directory__ pages (fixed-width text, no markdown)" +affects: [04-03-live-reload] + +# Tech tracking +tech-stack: + added: [] + patterns: + - "Virtual page pattern: current_path == '__directory__' sentinel distinguishes virtual pages from real vault documents" + - "Directory builder pattern: build_directory_lines() returns (Vec>, Vec) — same shape as render_markdown output" + - "Always-fresh pattern: navigate_back/forward call list_vault_files() again on __directory__ — never stale cache" + - "Resize guard pattern: early return in handle_resize() for virtual pages avoids crash on None raw_content" + +key-files: + created: [] + modified: + - "src/vault.rs — resolve_wiki_link() Directory sentinel, DirEntry struct, list_vault_files() with WalkDir" + - "src/app.rs — navigate_to_directory(), build_directory_lines(), follow_selected_link() sentinel routing, navigate_back/forward __directory__ branches, handle_resize() guard" + +key-decisions: + - "resolve_wiki_link() sentinel check placed BEFORE rfind('/') split — prevents 'directory' being misinterpreted as a filename" + - "build_directory_lines() computes line_index as lines.len() before push — matches renderer pattern for Tab-cycling correctness" + - "navigate_back/forward use if/else-if chain (not load_document for __directory__) — avoids spurious Missing document state" + - "handle_resize() returns early for __directory__ (raw_content is None for virtual pages) — prevents stale-content confusion" + - "link_records for directory entries use is_wiki: false with direct vault_path strings — navigate_to() handles them without resolve step" + +patterns-established: + - "Virtual page sentinel: __directory__ string as current_path distinguishes virtual page from real file throughout app" + - "Tab-cycling for directory entries: same LinkRecord model as rendered markdown — no special-case in key handling" + - "Directory listing always regenerated: list_vault_files() called on every visit (forward/back/direct) — always reflects current vault state" + +requirements-completed: [LIVE-02] + +# Metrics +duration: 8min +completed: 2026-03-01 +--- + +# Phase 4 Plan 02: Directory Listing Summary + +**Virtual [[Directory]] page with WalkDir tree view — yellow-bold dirs, cyan bracketed file links, Tab-cycling, and history back/forward all wired through existing link model** + +## Performance + +- **Duration:** 8 min +- **Started:** 2026-03-01T00:00:00Z +- **Completed:** 2026-03-01T00:08:00Z +- **Tasks:** 2 +- **Files modified:** 2 + +## Accomplishments + +- `resolve_wiki_link()` intercepts case-insensitive "Directory" before filesystem scan and returns `PathBuf::from("__directory__")` sentinel — zero false positives, works with `[[directory]]`, `[[DIRECTORY]]`, `[[Directory]]` +- `DirEntry` struct and `list_vault_files()` added to `vault.rs` using `WalkDir::new().sort_by_file_name()` — alphabetically sorted, skips hidden entries and non-.md files, reports depth for tree indentation +- `build_directory_lines()` module-level helper produces `(Vec>, Vec)` matching `render_markdown` output shape — directories as yellow-bold `name/`, files as cyan `[name]` with full LinkRecord for Tab-cycling +- `navigate_to_directory()` saves/truncates history, builds listing, sets `current_path = "__directory__"`, pushes HistoryEntry — full history participation +- `navigate_back()` and `navigate_forward()` detect `target_path == "__directory__"` and regenerate listing fresh — never stale +- `handle_resize()` guards with early return for `current_path == "__directory__"` — prevents crash on `None` raw_content + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Add [[Directory]] interception and vault file listing** - `fe69cf5` (feat) +2. **Task 2: Wire directory as virtual page with Tab-cycling navigation** - `600b46a` (feat) + +## Files Created/Modified + +- `src/vault.rs` - `resolve_wiki_link()` Directory sentinel check; `DirEntry` pub struct; `list_vault_files()` using `walkdir::WalkDir` +- `src/app.rs` - `navigate_to_directory()`; `build_directory_lines()`; `follow_selected_link()` `__directory__` routing; `navigate_back/forward` `__directory__` branch; `handle_resize()` early return guard + +## Decisions Made + +- Sentinel placed at the top of `resolve_wiki_link()` before `rfind('/')` — ensures "directory" is never split as a subpath prefix +- `build_directory_lines()` records `line_index = lines.len()` before the `lines.push()` call — matches the renderer's pattern exactly, Tab-cycling targets the correct line +- `navigate_back/forward` use an `if target_path == "__directory__"` branch rather than passing `"__directory__"` to `load_document()` — avoids a `VaultDocument::Missing` error state for a valid virtual page +- Directory entries stored with `is_wiki: false` — `navigate_to()` handles them directly as vault-relative paths without needing `resolve_wiki_link()` + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered + +None. `walkdir 2.5` was already in `Cargo.toml` from Plan 01. The `DirEntry` struct, `list_vault_files()`, and `build_directory_lines()` all compiled on the first attempt. The `navigate_back/forward` branching was straightforward given the clear sentinel convention. + +## User Setup Required + +None - no external service configuration required. The `[[Directory]]` wiki-link works out of the box in any vault. + +## Next Phase Readiness + +- Phase 4 Plan 03 (live reload via `notify`) can now start — `notify = "6.1"` was added to `Cargo.toml` in Plan 01 +- Directory listing is always regenerated fresh on each visit — will automatically reflect vault changes even before live reload is wired +- All navigation paths handle `__directory__` sentinel consistently — no special cases needed in Plan 03 + +--- +*Phase: 04-bbs-polish-and-live-content* +*Completed: 2026-03-01*