--- phase: 02-vault-core-and-rendering plan: 01 type: execute wave: 1 depends_on: [] files_modified: - Cargo.toml - src/vault.rs - src/highlighter.rs autonomous: true requirements: - REND-03 - REND-10 - NAV-06 - NAV-07 must_haves: truths: - "pulldown-cmark, syntect, and syntect-tui compile without errors alongside existing ratatui 0.30" - "vault.rs can load a markdown file from a vault path and return structured success/missing/error states" - "highlighter.rs initializes syntect once and can highlight a code string into Vec> with CGA 16-color palette" artifacts: - path: "Cargo.toml" provides: "pulldown-cmark, syntect, syntect-tui dependencies" contains: "pulldown-cmark" - path: "src/vault.rs" provides: "VaultDocument enum and load_document function" contains: "VaultDocument" - path: "src/highlighter.rs" provides: "syntect initialization, CGA color mapping, highlight_code function" contains: "syntect_color_to_cga" key_links: - from: "src/highlighter.rs" to: "syntect" via: "OnceLock and OnceLock initialized once" pattern: "OnceLock.*SyntaxSet" - from: "src/vault.rs" to: "std::fs" via: "read_to_string for markdown file loading" pattern: "read_to_string" --- Add Phase 2 dependencies (pulldown-cmark, syntect, syntect-tui) to Cargo.toml, create the vault file-loading module, and create the syntax highlighter module with CGA 16-color mapping. Purpose: Establish the foundation libraries and I/O layer that the markdown renderer (Plan 02) and app integration (Plan 03) build upon. Output: Three files modified/created; `cargo build` succeeds with all new dependencies. @/Users/ruohki/.claude/get-shit-done/workflows/execute-plan.md @/Users/ruohki/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/02-vault-core-and-rendering/02-RESEARCH.md @.planning/phases/02-vault-core-and-rendering/02-CONTEXT.md @src/config.rs @Cargo.toml Task 1: Add dependencies and create vault file-loading module Cargo.toml, src/vault.rs **Cargo.toml:** Add three new dependencies alongside the existing ones: ```toml pulldown-cmark = "0.13.1" syntect = { version = "5.3", default-features = false, features = ["default-fancy"] } syntect-tui = "3.0" ``` Note: `default-features = false, features = ["default-fancy"]` avoids the Oniguruma C library — pure Rust regex engine for clean SSH server builds. **src/vault.rs:** Create a new module with: 1. `VaultDocument` enum with three variants: - `Loaded { path: PathBuf, content: String }` — file read successfully - `Missing { path: PathBuf }` — file does not exist (io::ErrorKind::NotFound) - `ReadError { path: PathBuf, reason: String }` — other I/O error 2. `load_document(vault_path: &Path, relative: &str) -> VaultDocument`: - Join `vault_path` with `relative` to get the full path - Use `std::fs::read_to_string()` with proper match on the Result - Map `ErrorKind::NotFound` to `VaultDocument::Missing` - Map other errors to `VaultDocument::ReadError` - Return `VaultDocument::Loaded` on success The function takes `vault_path` (from Config) and a relative filename (e.g., "index.md"). Do NOT register the module in main.rs yet — Plan 03 handles wiring. `cargo check` passes with no errors (new deps resolve, vault.rs compiles). Run `cargo check 2>&1` and confirm exit code 0. Cargo.toml has pulldown-cmark 0.13.1, syntect 5.3 with default-fancy, and syntect-tui 3.0. vault.rs exists with VaultDocument enum and load_document function. `cargo check` succeeds. Task 2: Create syntax highlighter module with CGA color mapping src/highlighter.rs Create `src/highlighter.rs` with these components: 1. **Module-level OnceLock statics** for one-time initialization: ```rust static SYNTAX_SET: OnceLock = OnceLock::new(); static THEME_SET: OnceLock = OnceLock::new(); ``` 2. **`init_highlighter()`** — call once from main.rs before App::new(): - `SYNTAX_SET.get_or_init(SyntaxSet::load_defaults_newlines);` - `THEME_SET.get_or_init(ThemeSet::load_defaults);` 3. **`syntax_set() -> &'static SyntaxSet`** and **`theme_set() -> &'static ThemeSet`** accessor functions that call `.get().expect(...)`. 4. **`syntect_color_to_cga(c: syntect::highlighting::Color) -> ratatui::style::Color`** — RGB-to-CGA Euclidean distance mapper using the 16 CGA palette entries exactly as documented in the research (Pattern 8). The CGA palette entries: - Black(0,0,0), Red(170,0,0), Green(0,170,0), Yellow(170,170,0), Blue(0,0,170), Magenta(170,0,170), Cyan(0,170,170), Gray(170,170,170) - DarkGray(85,85,85), LightRed(255,85,85), LightGreen(85,255,85), LightYellow(255,255,85), LightBlue(85,85,255), LightMagenta(255,85,255), LightCyan(85,255,255), White(255,255,255) 5. **`highlight_code(code: &str, lang: &str) -> Vec>`** — the public API for code block highlighting: - Look up syntax by token first, then by name, fall back to plain text - Use `HighlightLines::new(syntax, &theme_set().themes["base16-ocean.dark"])` - For each line in `code.lines()`: call `highlight_line()`, map each `(Style, &str)` tuple to a `Span::styled(text.to_string(), Style::default().fg(syntect_color_to_cga(style.foreground)))`, collect into `Line::from(spans)` - Return `Vec>` (all owned strings, no lifetime leakage) Do NOT register the module in main.rs yet — Plan 03 handles wiring. But do ensure the file compiles in isolation (no unresolved imports that depend on other new modules). `cargo check` passes. Verify highlighter.rs compiles by temporarily adding `mod highlighter;` to main.rs, running `cargo check`, then removing it. Or simply verify the file has no syntax errors by checking `cargo check` output. highlighter.rs exists with init_highlighter(), syntax_set(), theme_set(), syntect_color_to_cga(), and highlight_code() functions. All use OnceLock for one-time init. Output is Vec> with CGA 16-color palette. 1. `cargo build` succeeds with all new dependencies 2. `src/vault.rs` contains `VaultDocument` enum with `Loaded`, `Missing`, `ReadError` variants 3. `src/vault.rs` contains `load_document()` function 4. `src/highlighter.rs` contains `init_highlighter()`, `highlight_code()`, `syntect_color_to_cga()` 5. No changes to existing Phase 1 files (app.rs, main.rs, config.rs, signals.rs, terminal.rs) other than Cargo.toml - `cargo build` compiles cleanly with pulldown-cmark 0.13.1, syntect 5.3, and syntect-tui 3.0 - vault.rs provides file loading with structured error states (Loaded/Missing/ReadError) - highlighter.rs provides one-shot syntect initialization and CGA-mapped syntax highlighting - Both new modules produce `'static` lifetime outputs (no borrowed data leaking) After completion, create `.planning/phases/02-vault-core-and-rendering/02-01-SUMMARY.md`