diff --git a/.config/dot/.claude/spec/tree-sitter-cooklang-integration.md b/.config/dot/.claude/spec/tree-sitter-cooklang-integration.md new file mode 100644 index 0000000..2bc662f --- /dev/null +++ b/.config/dot/.claude/spec/tree-sitter-cooklang-integration.md @@ -0,0 +1,49 @@ +## Problem Statement + +This machine's Neovim config (`~/.config/nvim`, tracked in the `dot` dotfiles repo, using `lazy.nvim` + `nvim-treesitter`) has no Cooklang support today: no filetype detection for `.cook` files, and no highlighting. +Once the standalone `tree-sitter-cooklang` grammar (see the companion spec) exists, this repo's Neovim config needs to be wired up to actually use it. + +## Solution + +Add a new `lua/plugins/filetypes.lua` to the Neovim config. It registers `.cook` as filetype `cooklang` via `vim.filetype.add`, and extends the existing `nvim-treesitter` plugin spec (currently defined in `ui.lua`) — via `lazy.nvim`'s spec-merging for a single plugin across multiple files — to register the `cooklang` parser's `install_info` and add it to `ensure_installed`. +This lets `nvim-treesitter`'s existing eager-load behavior and `dot setup nvim`'s existing headless bootstrap (`Lazy! restore`, which already drives `ensure_installed` as a side effect) pick up, build, and attach the new parser with no changes to either of those existing mechanisms. + +## User Stories + +1. As the machine owner, I want opening a `.cook` file to be recognized as filetype `cooklang` automatically, so I don't have to set it by hand. +2. As the machine owner, I want that filetype to get tree-sitter-based syntax highlighting from the from-scratch grammar, so recipes are visually readable. +3. As the machine owner, I want the custom-parser registration to live in its own file (`filetypes.lua`) rather than inside `ui.lua`'s generic colorscheme/treesitter block, so a one-off, filetype-specific hack stays separated from generic editor infrastructure, and any future custom filetype has an established home to go in. +4. As the machine owner, I want `filetypes.lua` to hold both the filetype-detection call and the parser registration together, so "everything about custom filetypes" is one discoverable file, rather than split between a native `ftdetect/` file and a `lua/plugins/` file. +5. As the machine owner, I want this to piggyback on the existing `dot setup nvim` headless bootstrap without requiring any change to that command, so a fresh-machine setup keeps working for this new filetype the same way it already does for every other pinned plugin/parser. +6. As the machine owner, I want no folding or indentation behavior changes for `.cook` files, so this change stays scoped to highlighting only, matching what was actually asked for. +7. As the machine owner, I want to verify the result by opening a real `.cook` file and checking the highlighting by eye (plus `:InspectTree`/`:Inspect` for node-level checks), so I don't have to stand up new automated test infrastructure for one query file in a personal config that has no existing automated-test story of its own. + +## Implementation Decisions + +- New file: `~/.config/nvim/lua/plugins/filetypes.lua`. No wiring changes needed elsewhere — `lazy.nvim`'s existing `{ import = "plugins" }` spec (in `init.lua`/`plugin.lua`) already imports every file under `lua/plugins/`. +- Top of the file: a plain `vim.filetype.add({ extension = { cook = "cooklang" } })` call, executed as a side effect when the module is required (every file under `lua/plugins/` is required unconditionally as part of `lazy.nvim`'s spec collection, so this runs at startup regardless of any plugin's load timing). Deliberately not using the native `ftdetect/` runtime-directory convention, to keep all custom-filetype logic in the one file. +- Below that: the file's returned plugin-spec table contains one entry for `"nvim-treesitter/nvim-treesitter"` using an `opts` function that merges into the plugin's existing options (already defined in `ui.lua`). `lazy.nvim` supports multiple partial specs for the same plugin across different imported files and merges them — this avoids touching or duplicating the existing spec in `ui.lua`. +- That `opts` function registers the `cooklang` parser via `require("nvim-treesitter.parsers").get_parser_configs()` (setting `install_info.url`/`branch`/`files`, pointing at the companion `tree-sitter-cooklang` spec's eventual repo, and `filetype = "cooklang"`), and appends `"cooklang"` to the existing `ensure_installed` list. +- `install_info.url`/`branch` are placeholders until the companion grammar repo actually exists and is hosted somewhere (see companion spec — hosting is explicitly out of scope there too). Filling these in is a mechanical last step once that repo exists, not a design decision this spec needs to resolve. +- No changes needed to `ui.lua` itself, nor to the `dot setup nvim` command or its spec: `nvim-treesitter` already loads eagerly (no lazy-load trigger), and `dot setup nvim`'s headless `Lazy! restore` already drives `ensure_installed` as a side effect of that eager load (per the existing `dot-setup-nvim` spec). The new `cooklang` entry is automatically picked up by both an interactive launch and a headless `dot setup nvim` run with zero code changes to that command. +- No `after/ftplugin/cooklang.lua` or other filetype-specific settings (e.g. no `conceallevel` override, unlike `markdown.lua`'s) — not requested; scope is highlighting only. + +## Testing Decisions + +- Manual verification only: open a sample `.cook` file, confirm the expected highlight groups render, use `:InspectTree`/`:Inspect` for node-level spot checks. +- No automated test is added to this Neovim config for this change — the config has no existing automated-test story of its own (unlike the `dot` CLI, which has real `fishtape` coverage). Parsing correctness itself is covered by the companion grammar spec's `canonical.yaml`-derived corpus, which is the appropriate seam for that concern — this integration is a downstream consumer of it, not a place to re-test it. +- The existing `dot setup nvim` `fishtape` coverage (fake-`nvim`-binary pattern) is not extended for this change. It already only asserts "every pinned plugin has a directory," not individual tree-sitter parser success — an intentional, pre-existing scope boundary from the `dot-setup-nvim` spec that this integration doesn't change. + +## Out of Scope + +- Building the grammar itself (fully covered by the companion `tree-sitter-cooklang` spec). +- Hosting or publishing that grammar repository (the maintainer's own responsibility, not detailed in either spec). +- Any `folds.scm`/`indents.scm`-driven behavior for `.cook` files (deferred, matching the companion spec's scope decision). +- Any change to `dot setup nvim`'s own success-check logic. +- A `~/.github/README.md` command-table row — not applicable, since this isn't a `dot` subcommand. +- Automated highlight-assertion tests for the Neovim config. + +## Further Notes + +- This integration can't actually be completed end-to-end until the companion `tree-sitter-cooklang` repo exists and is reachable by a normal git URL — `install_info.url`/`branch` here are placeholders until then. +- Mirrors the existing `gitea-axi` / `gitea-axi-integration` spec pair already in this `.claude/spec/` directory: one spec for the generic, reusable tool, one for how this specific repo adopts it. diff --git a/.config/dot/.claude/spec/tree-sitter-cooklang.md b/.config/dot/.claude/spec/tree-sitter-cooklang.md new file mode 100644 index 0000000..4622087 --- /dev/null +++ b/.config/dot/.claude/spec/tree-sitter-cooklang.md @@ -0,0 +1,50 @@ +## Problem Statement + +Editors with tree-sitter support (Neovim, Helix, Zed, Emacs) have no reliable way to get syntax highlighting for Cooklang recipe files today. +Cooklang's own documentation recommends wiring up the community grammar `addcninblue/tree-sitter-cooklang` via `nvim-treesitter`, but that grammar ships no highlight queries at all: it has no `queries/` directory, and its own README lists "Syntax highlighting" as an unchecked TODO item. +The documented setup snippet also has a bug (`branch = "main"`, but the repo's actual default branch is `master`). +Following the documented path exactly produces a parser that compiles and attaches to `.cook` buffers, but renders no highlighting whatsoever, because nothing tells tree-sitter which grammar nodes map to which highlight groups. + +## Solution + +Write a new, standalone tree-sitter grammar for Cooklang from scratch, grounded in the official EBNF spec (`cooklang/spec`) and validated against that same repo's official `canonical.yaml` conformance test suite — the same correctness bar every official and community Cooklang parser implementation (Rust, Swift, Go, and others) is held to. +Pair the grammar with a hand-authored `highlights.scm` query file, so the result actually produces working syntax highlighting once wired into any tree-sitter-consuming editor, rather than a parser with no highlighting story. + +## User Stories + +1. As a Cooklang recipe author, I want ingredients, cookware, timers, quantities/units, comments, and metadata each highlighted distinctly, so recipes are visually parseable at a glance. +2. As a grammar maintainer, I want the grammar to correctly parse the full Cooklang canonical test suite, so the highlighting reflects real document structure rather than an approximation. +3. As a grammar maintainer, I want corpus tests derived directly from `canonical.yaml`, so the grammar's correctness tracks the same bar every other Cooklang implementation must pass, rather than a bespoke set of hand-picked examples. +4. As a grammar maintainer, I want the grammar published as a normal, git-clonable repository, so any tree-sitter consumer's parser-install mechanism (e.g. nvim-treesitter's `install_info.url`) can point at it exactly like any other community grammar. +5. As an editor user on any tree-sitter-consuming editor (not just Neovim), I want the grammar to be generic and editor-agnostic, so it's reusable beyond one person's personal config. +6. As a grammar maintainer, I want `highlights.scm` to map onto standard tree-sitter highlight captures (`@string`, `@number`, `@comment`, etc.), so it renders correctly under any standard colorscheme without bespoke handling. + +## Implementation Decisions + +- New standalone repository, with its own git history — not bundled into any other project. Hosting, naming, and publishing logistics are the maintainer's own call and deliberately not specified here. +- Grammar authored from scratch using tree-sitter's `grammar.js` DSL. A hand-written external scanner (in C) is expected to be necessary, for the same reason the community grammar needed one: Cooklang's comment syntax (`-- ...`, `[- ... -]`), metadata lines, and ingredient/cookware/timer modifier braces (`{...}`) require context-sensitive lexing that a pure CFG can't express. +- Ground truth for grammar structure: `cooklang/spec`'s EBNF (`EBNF.md`). Ground truth for correctness: `cooklang/spec/tests/canonical.yaml` (837 lines as of writing) — every case in that file gets converted into a tree-sitter corpus test (`.cook` source in, expected parse tree out). Passing the full derived corpus is the grammar's release bar, in the same sense "conforming" is used across the other official/community implementations. +- `highlights.scm` is authored by hand against this grammar's own node types — full control over naming, since the grammar is written fresh alongside it, rather than reverse-engineering someone else's node names. +- Scope is highlighting only: no `folds.scm` or `indents.scm`. Nothing in this project calls for code folding or custom indentation behavior for Cooklang files; adding those query files would be building capability nobody asked for. +- Explicitly rejected: reusing `addcninblue/tree-sitter-cooklang` as the grammar. It has real strengths worth recording — a working custom C scanner, and contributions from two recognized tree-sitter-ecosystem contributors (`amaanq`, who did a scanner rewrite; `clason`, who regenerated the parser/bindings) — but it ships no query files at all, and its own README acknowledges highlighting was never finished. The existence of `canonical.yaml` as a rigorous, official test oracle de-risks writing a fresh grammar enough that starting clean (full control over node naming, no inherited "hacky" workarounds — the existing grammar's own README flags one, around punctuation in ingredient names) was judged better than building on an incomplete, unofficial base. + +## Testing Decisions + +- Correctness: `tree-sitter test` against a corpus derived from `cooklang/spec/tests/canonical.yaml` — each canonical case becomes a corpus fixture. Passing 100% of the derived corpus is the bar for calling the grammar done. +- `highlights.scm` itself is not covered by automated tests as part of this spec. Verification of the query file's output is manual/visual, done from the consuming editor side (see the companion integration spec for how this plays out in this machine's Neovim config). Automated highlight-assertion tests could be added later by a consumer that needs stronger guarantees, but nothing in this spec calls for that. +- No CI/build pipeline decisions are made here — ownership of hosting and any CI is the maintainer's call, out of scope for this spec. + +## Out of Scope + +- Reusing `addcninblue/tree-sitter-cooklang` as the underlying grammar (evaluated and rejected — see Implementation Decisions). +- `folds.scm` / `indents.scm` (a possible future addition, not built now). +- Any specific editor's integration wiring (the companion `tree-sitter-cooklang-integration` spec covers this machine's Neovim config; no other editor or consumer is addressed here). +- Repository hosting, naming, and CI/publishing logistics. +- Automated highlight-assertion testing. +- Installing or provisioning `tree-sitter-cli`/Node build tooling — a normal prerequisite of grammar authoring, not a design decision this spec needs to make. + +## Further Notes + +- `addcninblue/tree-sitter-cooklang` (evaluated and passed over): no `queries/` directory, README lists syntax highlighting as an unchecked TODO. The official cooklang.org blog's own documented Neovim setup snippet for it also has a bug — `branch = "main"` in the `install_info`, when the repo's actual default branch is `master` — which would make `:TSInstall cooklang` fail as written. +- `cooklang/spec/tests/canonical.yaml` is the same conformance suite used to validate roughly ten official/community Cooklang parser implementations across languages (Rust's `cooklang-rs`, Swift's `CookInSwift`, Go's `cooklang-go`, and others). Using it here gives this from-scratch grammar the same correctness bar as those. +- Mirrors the existing `gitea-axi` / `gitea-axi-integration` spec pair in this same `.claude/spec/` directory: one spec for the generic, reusable tool, one for how a specific project adopts it.