# v0.6 — Markdown affordances > Part of the [Typoena macro plan](macroplan.md). Requirements and targets: > [qfd.md](qfd.md). Load-bearing decisions: [adr.md](adr.md). **Status:** render affordances done early; the snippet engine is the remaining work (snippets are net-new scope, added 2026-07-08; reshaped 2026-07-12 from a hard-coded table into a git-synced, Zed-compatible library with a `$` palette launcher — see [`typoena-snippets.md`](typoena-snippets.md) for the file format). - [x] Heading lines bolded in render (faux-bold double-strike) - [x] List continuation on Enter inside `- ` / `1. ` (with empty-item exit) - [x] Soft-wrap at word boundaries ## Snippets Trigger-driven text expansion for Markdown authoring (Zed-inspired, but **no completion popup**: e-ink's ~630 ms refresh rules out a live filtering menu, and it fights the distraction-free premise). The library is a git-synced, Zed-compatible JSON file — full file-format reference in [`typoena-snippets.md`](typoena-snippets.md). This section is the *editor* behaviour. - [x] **The tab-stop engine** — the shared core both surfaces drive. A body is literal text plus numbered stops `$1 … $n` and a final `$0`; on insertion the caret lands on `$1` (or the end), in Insert. Tab advances to the next stop, **forward only** (no Shift-Tab); pending stops sit after the caret and shift with edits there. The session auto-aborts on Esc, a mode change, or a motion that leaves the stops. `${n:label}` parses to a bare `$n` (the label is stripped — no selection model to fill); no dynamic values (no RTC, so no `date`). - [x] **Inline Tab-expansion (Insert mode).** If the word immediately before the caret matches a snippet prefix, Tab expands it and starts the tab-stop session; otherwise Tab inserts spaces as today. A check in the Insert handler alongside the existing `list_marker` transform (`expand_snippet(word) -> Option`). Tab already arrives as `Key::Char('\t')`, so no new key event. - [x] **Hint-on-pause.** On the typing pause (same throttle as the word-count / cursor refresh — never a per-keystroke repaint), if the word before the caret is a prefix, the right side panel shows a quiet hint (`» name`, on the row above the mode line, sharing the slot with the `NO KBD` flag — the two never co-occur since the hint means you're typing). The panel is ~15 cols, so the hint is the snippet **name**, not the whole body — the full preview is the `$` palette's job. Snapshotted in `refresh_stats` so it rides the pause, and the firmware's Insert-pause repaint already carries it (no firmware change). Latin-9 has no `↹` glyph, hence the `»` marker. - [x] **`$` palette (browse + insert).** `Cmd-P` then `$` switches the palette to the snippet list (the same sigil mechanism as `>`). Fuzzy-matches name / prefix / description; Enter inserts the body at the caret and starts the tab-stop session. Lists **all** snippets — the fuzzy filter handles clutter, so there's no hidden "inline-only vs palette-only" split. Rows read `Name [prefix]`, so browsing also teaches the inline trigger. - [ ] **Boot wiring.** The host reads `/sd/repo/.typoena.snippets.json` at boot and calls `Editor::set_snippets` (mirroring `set_prefs`); a missing or malformed file is non-fatal (no snippets, editor runs). Parse lives in the host-testable `editor` crate via `serde_json` — the one new dependency. ## The palette, generalised (`Cmd-P` · `>` · `$`) v0.5 shipped `Cmd-P` = files and `>` = a five-entry settings list (`save_on_idle`, `format_on_save`, `line_numbers` toggles + `theme`/`auto_sync` rotations). v0.6 makes the sigils a clean split by verb, and the empty-palette placeholder legends: `Go to file · > settings · $ snippets`. - **bare `Cmd-P`** → *navigate*: go to file (unchanged). - **`>`** → *act on the editor* — the command palette. The pref toggles are just its stateful entries, not a special section. Dispatch differs per entry: a **toggle** flips and the list **stays open** (as today); a **one-shot** (e.g. `format`, `publish`) runs and **closes**; a **parameterised** command morphs the palette into a second **input step** (select `New file` → the box becomes a filename prompt → Enter creates it, scope read from a `repo/`/`local/` prefix as `:enew` does today). This retires `:e` (bare `Cmd-P` covers file-opening; dotfiles get a dedicated `> edit …` command if/when wanted). - **`$`** → *insert content* — the snippet launcher above. `format` / `publish` as `>` entries are a small opportunistic add (they prove `>` is a real action registry, not a settings box); the headline is snippets. ## First-time setup — snippet catalog (`just init`) [`just init`](../firmware/README.md#provisioning-an-sd-card) gains a step that seeds the two git-tracked config files into `repo/` (so they commit + sync on the device's first `:sync`): a starter [`.typoena.toml`](typoena-toml.md) (the four keys at their defaults, or confirmed at a prompt) and a [`.typoena.snippets.json`](typoena-snippets.md) chosen from a **curated catalog** checked into the repo. The catalog is grouped and opt-in — you pick the groups you want rather than getting all of one writer's personal templates. Not every Zed snippet is worth proposing: the Slidev/blog-pipeline ones (`@[youtube]`, ``, frontmatter, mermaid) and render-dependent or hyper-specific ones are left out of the menu, since a distraction-free prose appliance can't render them and you'd never miss them. **Proposed groups (pending sign-off):** - [ ] **Symbols** (inline, keyboard can't type them): `fleche`→`→`, `different`→`≠`, `fois`→`×`, `median`→`·`, `degre`→`°`, `euro`→`€`, `edanso`→`œ` (dead keys in v0.2.5 cover accents, *not* these). - [ ] **Structure**: `todo`→`- [ ] `, `link`→`[$1]($2)$0`, `img`→`![$1]($2)$0` (net-new — obvious for Markdown), `table`, `code` (fenced block). - [ ] **Prose / PKM templates** (`${n:label}` stripped to `$n`): `fiche` (book notes), `reference`/`refangl` (reference block), `biais`, `capture`, `standard`, `5w1h`.