docs(04-02): complete directory listing plan

- 04-02-SUMMARY.md created with full deviations, decisions, and dependency graph
- STATE.md updated: position to plan 2/3, decisions, session continuity, metrics
- ROADMAP.md updated: phase 4 progress 2/3 plans complete
- REQUIREMENTS.md: LIVE-02 marked complete
This commit is contained in:
2026-03-01 11:19:21 +01:00
parent 600b46a83b
commit 5a083238b2
4 changed files with 134 additions and 17 deletions
+2 -2
View File
@@ -49,7 +49,7 @@ Requirements for initial release. Each maps to roadmap phases.
### Live Content ### Live Content
- [ ] **LIVE-01**: App watches filesystem for changes and auto-refreshes current page - [ ] **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 ### Configuration
@@ -129,7 +129,7 @@ Which phases cover which requirements. Updated during roadmap creation.
| BBS-01 | Phase 4 | Pending | | BBS-01 | Phase 4 | Pending |
| BBS-02 | Phase 4 | Pending | | BBS-02 | Phase 4 | Pending |
| LIVE-01 | Phase 4 | Pending | | LIVE-01 | Phase 4 | Pending |
| LIVE-02 | Phase 4 | Pending | | LIVE-02 | Phase 4 | Complete |
**Coverage:** **Coverage:**
- v1 requirements: 32 total - v1 requirements: 32 total
+2 -2
View File
@@ -75,7 +75,7 @@ Plans:
2. Each page shows the file's last-modified timestamp 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 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 4. User can navigate to a vault-wide directory listing showing all available documents
**Plans:** 3 plans **Plans:** 2/3 plans executed
Plans: Plans:
- [x] 04-01-PLAN.md — ANSI splash screen on index.md and file metadata in status bar - [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 - [ ] 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 | | 1. Safety Foundation | 3/3 | Complete | 2026-02-28 |
| 2. Vault Core and Rendering | 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 | | 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| |
+16 -13
View File
@@ -5,23 +5,23 @@
See: .planning/PROJECT.md (updated 2026-02-28) 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 **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 ## Current Position
Phase: 4 of 4 (BBS Polish and Live Content) — IN PROGRESS Phase: 4 of 4 (BBS Polish and Live Content) — IN PROGRESS
Plan: 1 of 3 in current phase (04-01 done, 04-02 next) Plan: 2 of 3 in current phase (04-01, 04-02 done, 04-03 next)
Status: 04-01 complete — splash screen, file metadata in status bar, Phase 4 dependencies added Status: 04-02 complete — [[Directory]] virtual page with tree view, Tab-cycling, history back/forward
Last activity: 2026-03-01 — Plan 01 complete (splash.rs, PageMeta, ansi-to-tui/notify/walkdir deps) Last activity: 2026-03-01 — Plan 02 complete (DirEntry, list_vault_files, navigate_to_directory, build_directory_lines)
Progress: [████████░] 80% Progress: [████████░] 87%
## Performance Metrics ## Performance Metrics
**Velocity:** **Velocity:**
- Total plans completed: 8 - Total plans completed: 9
- Average duration: 2.9 min - Average duration: 3.1 min
- Total execution time: 0.39 hours - Total execution time: 0.44 hours
**By Phase:** **By Phase:**
@@ -30,10 +30,10 @@ Progress: [████████░░] 80%
| 01-safety-foundation | 3 | 7 min | 2.3 min | | 01-safety-foundation | 3 | 7 min | 2.3 min |
| 02-vault-core-and-rendering | 3 | 9 min | 3.0 min | | 02-vault-core-and-rendering | 3 | 9 min | 3.0 min |
| 03-navigation-and-links | 2 | 7 min | 3.5 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:** **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 - Trend: Stable
*Updated after each plan completion* *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]: 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]: 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 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 ### Pending Todos
@@ -86,6 +89,6 @@ None.
## Session Continuity ## Session Continuity
Last session: 2026-02-28 Last session: 2026-03-01
Stopped at: Completed 03-02-PLAN.md (Phase 3 complete) Stopped at: Completed 04-02-PLAN.md
Resume file: .planning/phases/04-live-reload/04-01-PLAN.md Resume file: .planning/phases/04-bbs-polish-and-live-content/04-03-PLAN.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<Line<'static>>, Vec<LinkRecord>) — 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<Line<'static>>, Vec<LinkRecord>)` 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*