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:
@@ -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*
|
||||
Reference in New Issue
Block a user