Promote grammar rendering to a top-level grammar <locator> [rule] command, backed by a rewrite of the renderer. The current GrammarRenderer (crates/plotnik-cli/src/commands/lang.rs) is the v1 format this redesign explicitly replaces.
Why the v1 format is wrong
The current renderer descends into token internals as if they were children, shows inline-listed rules as queryable nodes, leaks hidden rules into supertype member lists, prints underscore-prefixed category names the query language can't even say, and is unconditionally one-item-per-line (a mid-size grammar → ~2,500 lines). It renders how text parses; query authors need how trees are shaped.
Design: three registers
Every definition body is in exactly one register, each lexically distinct so they can't be confused:
| Register |
Definitions |
Body syntax |
Example |
| Pattern |
node shapes, hidden rules |
real plotnik query syntax |
pair = {key: (string) ":" value: (value#)} |
| Type |
categories (supertypes) |
bare names joined by | |
value# = object | array | number | string |
| Text |
tokens |
string literal or regex |
number = /-?(0|[1-9]\d*)(\.\d*)?/ |
This replaces v1's single overloaded notation that used the same marker ((_x ...)) for opposite things.
First-class categories
Tree-sitter supertypes become a named feature with suffix-# syntax (expression#, (expression#call_expression)), de-underscored names, and contextual-refinement semantics. Uses #, not the deprecated tree-sitter /. The dump's category section is the discovery surface for that feature.
Current state (audit)
Entirely unbuilt. The renderer uses a single uniform render_rule() (lang.rs:135-233), emits :: supertype = (not # / |-union), taps RawGrammar at the start of the pipeline (not ExtractedSyntaxGrammar + node-shapes), lives in plotnik-cli, and has no fragment API or single-rule retrieval.
Scope
Acceptance
plotnik grammar typescript and plotnik grammar typescript call_expression (rule + referenced shapes).
- Native plotnik syntax with
# refinements; tokens in the text register; no hidden-rule leakage; compact (not one-per-line).
- Unknown rule → did-you-mean.
- Diagnostics consume the same fragment API.
Companion to the grammar-based-validation issues (diagnostics consumer) and the supertype work (#417 interim reject, #423 implementation). Locator support: #429.
Promote grammar rendering to a top-level
grammar <locator> [rule]command, backed by a rewrite of the renderer. The currentGrammarRenderer(crates/plotnik-cli/src/commands/lang.rs) is the v1 format this redesign explicitly replaces.Why the v1 format is wrong
The current renderer descends into token internals as if they were children, shows
inline-listed rules as queryable nodes, leaks hidden rules into supertype member lists, prints underscore-prefixed category names the query language can't even say, and is unconditionally one-item-per-line (a mid-size grammar → ~2,500 lines). It renders how text parses; query authors need how trees are shaped.Design: three registers
Every definition body is in exactly one register, each lexically distinct so they can't be confused:
pair = {key: (string) ":" value: (value#)}|value# = object | array | number | stringnumber = /-?(0|[1-9]\d*)(\.\d*)?/This replaces v1's single overloaded notation that used the same marker (
(_x ...)) for opposite things.First-class categories
Tree-sitter supertypes become a named feature with suffix-
#syntax (expression#,(expression#call_expression)), de-underscored names, and contextual-refinement semantics. Uses#, not the deprecated tree-sitter/. The dump's category section is the discovery surface for that feature.Current state (audit)
Entirely unbuilt. The renderer uses a single uniform
render_rule()(lang.rs:135-233), emits:: supertype =(not#/|-union), tapsRawGrammarat the start of the pipeline (notExtractedSyntaxGrammar+ node-shapes), lives in plotnik-cli, and has no fragment API or single-rule retrieval.Scope
crates/plotnik-core/src/grammar/render/— a model + width-aware pretty-printer, tapping the existing pipeline (postextract_tokens/resolve_symbols, joined withextract_default_aliases+ node-shapes closures).Def::fragmentdepth-capped,kind_listlength-capped, category member lists).analyze/link.rs:382hand-rolls aformat_listfor field hints that belongs here; the grammar-based validation messages (Grammar-based query validation: structural checks from existing grammar metadata #443, Grammar-based query validation: StructureTable + SAT/THREAD engine for sequence & anchor impossibility #444) are the driving consumer.grammar <locator> [rule](locator from-las a grammar locator #429). Optional second positional narrows to one rule + the rules it references. No--rulesubcommand — the format is engineered so grep is the focused view (rg '^call_expression =').Acceptance
plotnik grammar typescriptandplotnik grammar typescript call_expression(rule + referenced shapes).#refinements; tokens in the text register; no hidden-rule leakage; compact (not one-per-line).Companion to the grammar-based-validation issues (diagnostics consumer) and the supertype work (#417 interim reject, #423 implementation). Locator support: #429.