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:
+16
-15
@@ -16,8 +16,6 @@ use crate::db::{
|
||||
AddColumnResult, CascadeEffect, ChangeColumnTypeResult, DataResult, DeleteResult,
|
||||
InsertResult, TableDescription, UpdateResult,
|
||||
};
|
||||
use crate::dsl::lexer::lex;
|
||||
use crate::dsl::usage;
|
||||
use crate::dsl::{Command, ParseError, parse_command};
|
||||
use crate::event::AppEvent;
|
||||
use crate::mode::Mode;
|
||||
@@ -1073,8 +1071,8 @@ impl App {
|
||||
// ADR-0021 §2: append the usage block (if a
|
||||
// known command-entry keyword was consumed) or
|
||||
// the available-commands fallback (§5).
|
||||
if let ParseError::Invalid { position, .. } = &err {
|
||||
self.note_error(render_usage_block(input, *position));
|
||||
if let ParseError::Invalid { .. } = &err {
|
||||
self.note_error(render_usage_block(input));
|
||||
}
|
||||
Vec::new()
|
||||
}
|
||||
@@ -1720,12 +1718,14 @@ fn parse_error_message(err: &ParseError) -> String {
|
||||
/// command-entry keyword was consumed, otherwise an
|
||||
/// "available commands:" fallback (§5).
|
||||
///
|
||||
/// `position` is a byte offset into the original input
|
||||
/// identifying where the parser stopped — same value the
|
||||
/// caret uses.
|
||||
fn render_usage_block(input: &str, position: usize) -> String {
|
||||
let tokens = lex(input);
|
||||
if let Some((_kw, catalog_keys)) = usage::matched_entry(&tokens, position) {
|
||||
/// Driven by the walker registry (ADR-0024 §architecture).
|
||||
/// If the input's first identifier-shape token is a registered
|
||||
/// `CommandNode` entry word, the node's `usage_ids` slice
|
||||
/// renders every catalog template — multi-form families like
|
||||
/// `drop` show every variant. Otherwise the fallback lists every
|
||||
/// entry keyword alphabetically.
|
||||
fn render_usage_block(input: &str) -> String {
|
||||
if let Some((_word, catalog_keys)) = crate::dsl::grammar::usage_keys_for_input(input) {
|
||||
let mut out = String::from("usage:");
|
||||
for key in catalog_keys {
|
||||
let template = crate::friendly::translate(key, &[]);
|
||||
@@ -1737,12 +1737,13 @@ fn render_usage_block(input: &str, position: usize) -> String {
|
||||
}
|
||||
return out;
|
||||
}
|
||||
// No-prefix fallback. Render every command-entry keyword via
|
||||
// its `parse.token.keyword.*` catalog key, plain
|
||||
// comma-joined.
|
||||
let names: Vec<String> = usage::entry_keywords_alphabetised()
|
||||
// No-prefix fallback. Each entry word renders backticked
|
||||
// verbatim (replaces the old `parse.token.keyword.*` catalog
|
||||
// lookup; ADR-0024 §cleanup-pass §F prescribes the same
|
||||
// wrapping helper).
|
||||
let names: Vec<String> = crate::dsl::grammar::entry_words_alphabetised()
|
||||
.into_iter()
|
||||
.map(|kw| crate::friendly::translate(&kw.catalog_token_key(), &[]))
|
||||
.map(|w| format!("`{w}`"))
|
||||
.collect();
|
||||
crate::t!(
|
||||
"parse.available_commands",
|
||||
|
||||
Reference in New Issue
Block a user