▍ humdrum codex / glint v1.0.2

Add glint design spec

a3f7acb7d128ae90925bb9db36fe0a4420ebb073
humdrum-tiv <45084903+humdrum-tiv@users.noreply.github.com> · 2026-06-27 17:28

Add glint design spec

Modeless terminal markdown editor with live inline styling (markup
visible), glow-style glamour preview, vault file picker, and
configurable daily-note path. Go + Bubbletea + Glamour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

3 files changed

.gitignore +0 −3
@@ -1,3 +0,0 @@
-/glint
-*.out
-dist/
README.md +0 −3
@@ -1,3 +0,0 @@
-# glint
-
-Pretty terminal markdown editor (Go + Bubbletea + Glamour). Obsidian-vault companion.
docs/superpowers/specs/2026-06-27-glint-design.md +0 −159
@@ -1,159 +0,0 @@
-# glint — design spec
-
-**Date:** 2026-06-27
-**Status:** design approved, pre-implementation
-**Stack:** Go + Bubbletea (MVU) + Lipgloss + Glamour
-
-## What it is
-
-A pretty terminal markdown editor with glow-style rendering, used as an
-Obsidian-vault companion (not a replacement — the Obsidian GUI stays primary).
-Open a file, edit it with **live inline styling** (bold renders bold, headings
-colored/bold, links colored — while the raw markup characters stay visible),
-save it. Plus: jump to today's daily note, fuzzy-pick any vault file, and toggle
-a full glamour-rendered read view.
-
-Motivation: existing vault TUIs (ekphos, clin-rs, basalt, kimun) almost fit but
-hardcode the wrong things. ekphos was closest, but: (1) its editor leaves plain
-text at the terminal default foreground — unreadable in a light terminal;
-(2) daily-note path/format is hardcoded to `journal.<date>.md` in the vault root,
-incompatible with the user's `Daily/<date>.md` convention; (3) sort default is
-hardcoded and never persisted. glint fixes all three by design.
-
-## Non-goals (v1)
-
-Wikilink follow, in-content search, graph view, tag browsing, multi-pane layout,
-sort persistence, vim modality. Modeless editing only. These may come later.
-
-## Editing model (decided)
-
-- **Modeless.** Standard typing + arrows. No vim modes in v1.
-- **Live inline styling, markup NOT concealed.** `**bold**` shows the asterisks,
-  styled bold. `## Head` shows the `##`, styled. No cursor-reveal logic, no width
-  changes from hidden characters — this is what keeps the editor tractable.
-- Terminals can't resize text, so "big heading" = bold + color (+ optional
-  underline), not a larger font.
-
-## Architecture
-
-Bubbletea MVU. A top-level `model` holds a `mode` enum (Editor | Picker |
-Preview) and the sub-models. Exactly one view is active at a time. Each unit
-below has one purpose, a defined interface, and is testable in isolation.
-
-### 1. `editor` (core — the real work)
-
-Owns the buffer and all editing. **Knows nothing about files or the vault** —
-it is a pure text buffer + renderer. Save/load are wired by the top model.
-
-State: `lines []string` (per-line rune content; v1 plain slice is fine for
-vault-sized files), `cursor {row, col}`, `scroll` (viewport top), `dirty bool`.
-
-Responsibilities:
-- Input: insert/delete runes, newline/split, backspace/join, cursor movement
-  (char/word/line/home/end/page), viewport scroll-follow.
-- Render: produce styled lines for the visible viewport via the styling layer.
-
-### 2. Styling layer (inside `editor`)
-
-For each **visible** line, a hand-rolled markdown scanner emits a list of spans
-`{text, style}`, where `style` is a Lipgloss style. The rendered line is the
-concatenation of styled spans, character-for-character aligned with the raw line
-(no insertions/deletions — markup stays visible).
-
-- **Block context** tracked across lines: fenced code blocks (```), YAML
-  frontmatter (leading `---` … `---`), so inline rules are suppressed inside
-  them.
-- Inline rules: headings (`#`..`######`), bold (`**`/`__`), italic (`*`/`_`),
-  inline code (`` ` ``), links `[text](url)`, wikilinks `[[..]]` (styled only,
-  not followed in v1), list markers (`-`/`*`/`+`/`N.`), blockquote (`>`).
-- **Every span — including plain prose — gets an explicit foreground from the
-  theme. Never `Style{}` / terminal default.** This is the root-cause fix for the
-  ekphos light-terminal bug.
-- Not a goldmark AST: an AST reflows and drops markup characters, which breaks
-  char-exact alignment to the editable raw text. A line-oriented scanner with
-  carried block state is the right tool here.
-
-### 3. `preview`
-
-Toggle key renders the current buffer text through **Glamour** (configured style)
-into a scrollable, read-only `viewport`. Here markup IS concealed — the full glow
-read experience. Esc returns to the editor at the same position.
-
-### 4. `picker`
-
-Vault file browser with fuzzy filter (Bubbles `list`). Walks `vault_dir` for
-`.md` files, ignoring dot-directories. Enter opens the selection in the editor.
-
-Daily-note action (own keybind): builds
-`<vault_dir>/<daily_subdir>/<format(today)>.md`; if missing, creates the
-directory and the file (optionally seeded from a template); opens it in the
-editor.
-
-### 5. `config` (TOML)
-
-The things ekphos hardcoded, made configurable:
-
-```toml
-vault_dir     = "/Users/kortum/Humdrum"
-daily_subdir  = "Daily"
-daily_format  = "2006-01-02"   # Go reference-time layout
-glamour_style = "dark"          # builtin name or path to a style JSON
-```
-
-Loaded from `~/.config/glint/config.toml`. Sensible defaults if absent. A `theme`
-section (or reuse of `glamour_style`'s palette) supplies the explicit editor
-foreground/accent colors used by the styling layer.
-
-## Keybindings (v1, modeless)
-
-| Key      | Action                         |
-|----------|--------------------------------|
-| `Ctrl+S` | Save current file              |
-| `Ctrl+P` | Open file picker (fuzzy)       |
-| `Ctrl+D` | Open/create today's daily note |
-| `Ctrl+R` | Toggle glamour read-preview    |
-| `Esc`    | Leave picker/preview → editor  |
-| `Ctrl+Q` | Quit (prompt if dirty)         |
-| arrows / typing | Normal text editing     |
-
-(Exact chords finalizable during implementation; avoid clashes with terminal.)
-
-## Data flow
-
-1. Launch: parse flags (`glint [path]`, `glint --daily`), load config, build top
-   model. With a path → load file into editor. With `--daily` → daily-note path.
-   Bare → picker.
-2. Keystrokes → top model `Update` routes by `mode` to the active sub-model.
-3. Editor edits mutate buffer + set `dirty`. `Ctrl+S` writes `lines` to disk,
-   clears `dirty`.
-4. `Ctrl+R` feeds buffer text to Glamour → preview viewport.
-5. Picker/daily selection → load file bytes → editor buffer → `mode = Editor`.
-
-## Error handling
-
-- File read/write errors surface in the status bar; never silent. A failed save
-  keeps `dirty` true and shows the error.
-- Missing config → defaults. Malformed config → report the parse error and fall
-  back to defaults rather than crashing.
-- Daily-note dir creation failure → status-bar error, stay in current view.
-
-## Testing
-
-- **Styling scanner:** pure unit tests — raw markdown line(s) + carried block
-  state → expected spans. The highest-value tests; cover headings, bold/italic,
-  code, links, wikilinks, lists, blockquotes, fence/frontmatter boundaries, and
-  the plain-text-gets-explicit-fg invariant.
-- **Editor ops:** unit tests on the model — insert/delete/split/join/movement
-  against expected buffer + cursor state.
-- **Update routing:** Bubbletea `Update` is testable by feeding messages and
-  asserting resulting model state / mode transitions.
-- `preview` and `picker` are thin wrappers over Glamour / Bubbles `list`; smoke
-  tests only.
-
-## Open items for implementation
-
-- Final keybinding chords (collision check vs terminal/Ghostty).
-- Whether the editor foreground/accent palette is its own `[theme]` table or
-  derived from the chosen glamour style.
-- Daily-note template content (if any) — likely mirror the user's existing daily
-  template minus script-generated callouts.