ADR-0024 Phase F (full) step 2: usage via CommandNode.usage_ids

Migrates parse-error usage-block rendering from the legacy
`dsl::usage::matched_entry` (which scanned a `Vec<Token>` for the
first matched Keyword) to walker-side lookup driven by each
`CommandNode`'s `usage_ids` slice.

`CommandNode.usage_id: Option<&'static str>` becomes
`usage_ids: &'static [&'static str]`. Multi-form families
(`drop`, `add`, `show`) carry every variant — `drop` lists
table/column/relationship templates; `add` lists column /
relationship; `show` lists data / table. The single-shape
commands carry their single catalog key.

App-lifecycle CommandNodes had pointed at non-existent
`parse.usage.app.*` keys (never noticed because the field was
unused); they now point at the real catalog entries
(`parse.usage.quit`, `parse.usage.help`, …).

New helpers in `dsl::grammar`:
- `usage_keys_for_input(source) -> Option<(entry_word, usage_ids)>`
  resolves the first identifier-shape token to a CommandNode and
  returns its usage_ids list. Used by `app::render_usage_block`
  and `input_render::ambient_hint`.
- `entry_words_alphabetised() -> Vec<&'static str>` replaces
  `dsl::usage::entry_keywords_alphabetised`.

`dsl::usage` is deleted. The "available commands:" fallback in
`render_usage_block` now formats entry words as `` `<word>` ``
directly (matching the `parse.token.keyword.*` catalog renders);
the per-keyword catalog wrappers will collapse in the next step
(ADR-0024 §cleanup-pass §F).

`parse_command` and `parse_tokens` slim down:
- `parse_command(input)` no longer pre-lexes — the walker scans
  source bytes directly.
- `parse_tokens` (internal-only `pub` for "future I3/I4 work")
  is removed; its body folded into `parse_command`.
- `unknown_command_error` reads the walker registry directly.

Touched modules also drop their `crate::dsl::lexer::lex` and
`crate::dsl::usage` imports: `app.rs`, `input_render.rs`,
`completion.rs`.

Tests: 852 passing, 0 failing, 1 ignored (down from 860 because
the 8 `dsl::usage::tests::*` tests are gone with the module).
This commit is contained in:
claude@clouddev1
2026-05-15 08:27:16 +00:00
parent 7bdd3987e1
commit a41400e532
10 changed files with 103 additions and 402 deletions
+10 -10
View File
@@ -176,7 +176,7 @@ pub static QUIT: CommandNode = CommandNode {
shape: EMPTY_SEQ,
ast_builder: build_quit,
help_id: Some("app.quit"),
usage_id: Some("parse.usage.app.quit"),
usage_ids: &["parse.usage.quit"],
hint_mode: None,
};
@@ -185,7 +185,7 @@ pub static HELP: CommandNode = CommandNode {
shape: EMPTY_SEQ,
ast_builder: build_help,
help_id: Some("app.help"),
usage_id: Some("parse.usage.app.help"),
usage_ids: &["parse.usage.help"],
hint_mode: None,
};
@@ -194,7 +194,7 @@ pub static REBUILD: CommandNode = CommandNode {
shape: EMPTY_SEQ,
ast_builder: build_rebuild,
help_id: Some("app.rebuild"),
usage_id: Some("parse.usage.app.rebuild"),
usage_ids: &["parse.usage.rebuild"],
hint_mode: None,
};
@@ -203,7 +203,7 @@ pub static SAVE: CommandNode = CommandNode {
shape: SAVE_AS_OPT,
ast_builder: build_save,
help_id: Some("app.save"),
usage_id: Some("parse.usage.app.save"),
usage_ids: &["parse.usage.save"],
hint_mode: None,
};
@@ -212,7 +212,7 @@ pub static NEW: CommandNode = CommandNode {
shape: EMPTY_SEQ,
ast_builder: build_new,
help_id: Some("app.new"),
usage_id: Some("parse.usage.app.new"),
usage_ids: &["parse.usage.new"],
hint_mode: None,
};
@@ -221,7 +221,7 @@ pub static LOAD: CommandNode = CommandNode {
shape: EMPTY_SEQ,
ast_builder: build_load,
help_id: Some("app.load"),
usage_id: Some("parse.usage.app.load"),
usage_ids: &["parse.usage.load"],
hint_mode: None,
};
@@ -230,7 +230,7 @@ pub static EXPORT: CommandNode = CommandNode {
shape: EXPORT_PATH_OPT,
ast_builder: build_export,
help_id: Some("app.export"),
usage_id: Some("parse.usage.app.export"),
usage_ids: &["parse.usage.export"],
hint_mode: None,
};
@@ -239,7 +239,7 @@ pub static IMPORT: CommandNode = CommandNode {
shape: IMPORT_BODY_OPT,
ast_builder: build_import,
help_id: Some("app.import"),
usage_id: Some("parse.usage.app.import"),
usage_ids: &["parse.usage.import"],
hint_mode: None,
};
@@ -248,7 +248,7 @@ pub static MODE: CommandNode = CommandNode {
shape: MODE_VALUE,
ast_builder: build_mode,
help_id: Some("app.mode"),
usage_id: Some("parse.usage.app.mode"),
usage_ids: &["parse.usage.mode"],
hint_mode: None,
};
@@ -257,6 +257,6 @@ pub static MESSAGES: CommandNode = CommandNode {
shape: MESSAGES_VALUE_OPT,
ast_builder: build_messages,
help_id: Some("app.messages"),
usage_id: Some("parse.usage.app.messages"),
usage_ids: &["parse.usage.messages"],
hint_mode: None,
};