Help: consume CommandNode.help_id — REGISTRY-driven in-app help
Every CommandNode declared a help_id that nothing read; the in-app `help` body was a single hand-kept catalog block that drifted from the command set (handoff-12 §2.1). note_help now iterates the command REGISTRY and translates each CommandNode's help_id (`help.<id>`), framed by help.intro / help.dsl_section / help.types_reference. A newly-registered command appears in `help` automatically — no edit to note_help or a hand-kept list. Added 20 per-command help entries plus the 3 framing entries; removed help.in_app_body. Per-command entries use block scalars: a libyml 0.0.5 scanner bug panics on long internal space runs in double-quoted scalars, and the entries are space-aligned.
This commit is contained in:
+38
-14
@@ -1595,22 +1595,46 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note a flat list of currently-supported app-level
|
/// Note the list of currently-supported commands to the
|
||||||
/// commands to the output panel.
|
/// output panel.
|
||||||
///
|
///
|
||||||
/// This is the simple Iteration-4 stand-in for a richer
|
/// Assembled from the command REGISTRY (ADR-0024 §help_id):
|
||||||
/// help system (H3 in the requirements doc); it gives the
|
/// the framing (`help.intro`, `help.dsl_section`,
|
||||||
/// user a quick "what can I type?" reference that's
|
/// `help.types_reference`) comes from the catalog, and each
|
||||||
/// always accurate against the build they're running. As
|
/// command's body is the catalog entry named by its
|
||||||
/// new commands land, append them here.
|
/// `help_id`. A newly-registered command appears here
|
||||||
|
/// automatically — no edit to this function or a hand-kept
|
||||||
|
/// list. Each catalog line becomes its own `OutputLine` so
|
||||||
|
/// the scroll-position math (one logical line = one display
|
||||||
|
/// row) stays accurate per the renderer's invariant.
|
||||||
fn note_help(&mut self) {
|
fn note_help(&mut self) {
|
||||||
// Body lives in the i18n catalog (`help.in_app_body`).
|
use crate::dsl::grammar::REGISTRY;
|
||||||
// Each YAML line becomes its own `OutputLine` so the
|
|
||||||
// scroll-position math (one logical line = one display
|
let mut lines: Vec<String> = Vec::new();
|
||||||
// row) stays accurate per the renderer's invariant.
|
lines.push(crate::t!("help.intro"));
|
||||||
let body = crate::t!("help.in_app_body");
|
// REGISTRY is ordered app-commands first; emit the
|
||||||
for line in body.lines() {
|
// "DSL data commands" sub-header at the first command
|
||||||
self.note_system(line.to_string());
|
// whose help_id leaves the `app.` namespace.
|
||||||
|
let mut dsl_header_done = false;
|
||||||
|
for command in REGISTRY {
|
||||||
|
let Some(help_id) = command.help_id else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if !dsl_header_done && !help_id.starts_with("app.") {
|
||||||
|
lines.push(crate::t!("help.dsl_section"));
|
||||||
|
dsl_header_done = true;
|
||||||
|
}
|
||||||
|
let key = format!("help.{help_id}");
|
||||||
|
let body = crate::friendly::translate(&key, &[]);
|
||||||
|
lines.extend(body.lines().map(str::to_string));
|
||||||
|
}
|
||||||
|
lines.extend(
|
||||||
|
crate::t!("help.types_reference")
|
||||||
|
.lines()
|
||||||
|
.map(str::to_string),
|
||||||
|
);
|
||||||
|
for line in lines {
|
||||||
|
self.note_system(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -351,7 +351,11 @@ pub struct CommandNode {
|
|||||||
/// as a per-node validator (Phase A: none — every app
|
/// as a per-node validator (Phase A: none — every app
|
||||||
/// command's ast_builder is infallible).
|
/// command's ast_builder is infallible).
|
||||||
pub ast_builder: fn(&MatchedPath) -> Result<Command, ValidationError>,
|
pub ast_builder: fn(&MatchedPath) -> Result<Command, ValidationError>,
|
||||||
#[allow(dead_code)]
|
/// Catalog key (`help.<id>`) for this command's in-app
|
||||||
|
/// `help` entry. Consumed by `App::note_help`, which
|
||||||
|
/// iterates the REGISTRY and translates each `help_id` —
|
||||||
|
/// so a newly-registered command appears in `help`
|
||||||
|
/// automatically (ADR-0024 §help_id).
|
||||||
pub help_id: Option<&'static str>,
|
pub help_id: Option<&'static str>,
|
||||||
/// Catalog keys under `parse.usage.*` to render in the
|
/// Catalog keys under `parse.usage.*` to render in the
|
||||||
/// "usage:" block when a parse error fires for this command
|
/// "usage:" block when a parse error fires for this command
|
||||||
|
|||||||
+25
-1
@@ -120,7 +120,31 @@ pub const KEYS_AND_PLACEHOLDERS: &[(&str, &[&str])] = &[
|
|||||||
),
|
),
|
||||||
// ---- Help text ----
|
// ---- Help text ----
|
||||||
("help.cli_banner", &[]),
|
("help.cli_banner", &[]),
|
||||||
("help.in_app_body", &[]),
|
// In-app `help` — framing + per-command entries keyed by
|
||||||
|
// each CommandNode's `help_id` (ADR-0024 §help_id).
|
||||||
|
("help.intro", &[]),
|
||||||
|
("help.dsl_section", &[]),
|
||||||
|
("help.types_reference", &[]),
|
||||||
|
("help.app.quit", &[]),
|
||||||
|
("help.app.help", &[]),
|
||||||
|
("help.app.rebuild", &[]),
|
||||||
|
("help.app.save", &[]),
|
||||||
|
("help.app.new", &[]),
|
||||||
|
("help.app.load", &[]),
|
||||||
|
("help.app.export", &[]),
|
||||||
|
("help.app.import", &[]),
|
||||||
|
("help.app.mode", &[]),
|
||||||
|
("help.app.messages", &[]),
|
||||||
|
("help.ddl.create", &[]),
|
||||||
|
("help.ddl.drop", &[]),
|
||||||
|
("help.ddl.add", &[]),
|
||||||
|
("help.ddl.rename", &[]),
|
||||||
|
("help.ddl.change", &[]),
|
||||||
|
("help.data.show", &[]),
|
||||||
|
("help.data.insert", &[]),
|
||||||
|
("help.data.update", &[]),
|
||||||
|
("help.data.delete", &[]),
|
||||||
|
("help.data.replay", &[]),
|
||||||
// ---- Hint panel ambient typing assistance (ADR-0022 §6) ----
|
// ---- Hint panel ambient typing assistance (ADR-0022 §6) ----
|
||||||
("hint.ambient_complete", &[]),
|
("hint.ambient_complete", &[]),
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -208,46 +208,77 @@ help:
|
|||||||
import <zip> [as <t>] Unpack <zip> into a new project and
|
import <zip> [as <t>] Unpack <zip> into a new project and
|
||||||
switch to it. <t> overrides the target
|
switch to it. <t> overrides the target
|
||||||
name (else taken from the zip).
|
name (else taken from the zip).
|
||||||
# In-app `help` command output. Same shape as
|
# In-app `help` command output (ADR-0024 §help_id). The
|
||||||
# `cli_banner` — multi-line block, consumers iterate
|
# renderer iterates the command REGISTRY and translates each
|
||||||
# lines and emit each as its own output row so scroll
|
# CommandNode's `help_id` — so a newly-registered command
|
||||||
# math stays accurate.
|
# appears in `help` automatically, with no edit here. `intro`
|
||||||
in_app_body: |
|
# and `dsl_section` frame the two command groups; each
|
||||||
Supported commands:
|
# `app.*` / `ddl.*` / `data.*` entry is keyed by a command's
|
||||||
quit — exit
|
# `help_id`; `types_reference` closes the block. All entries
|
||||||
help — this list
|
# are multi-line-capable — the renderer emits one output row
|
||||||
mode simple|advanced — switch input mode
|
# per line so scroll math stays accurate.
|
||||||
messages — show current verbosity
|
intro: "Supported commands:"
|
||||||
messages short|verbose— switch error wording (verbose is the default)
|
dsl_section: "DSL data commands (in simple mode):"
|
||||||
rebuild — rebuild .db from project.yaml + data/ (with confirmation)
|
# Per-command help, keyed by `CommandNode.help_id`. Block
|
||||||
save — save current temp project under a name
|
# scalars (`|-`) so the column alignment survives — the
|
||||||
save as — copy current project to a new name/path
|
# double-quoted form trips a libyml scanner bug on long
|
||||||
new — close current, start a fresh temp project
|
# internal space runs. The renderer emits one output row per
|
||||||
load — open the project picker
|
# line, so multi-form commands list each form on its own line.
|
||||||
export [<path>] — write a zip of project.yaml + data/ (excludes .db, history.log)
|
app:
|
||||||
import <zip> [as <t>] — unpack a zip and switch to the new project
|
quit: |-
|
||||||
DSL data commands (in simple mode):
|
quit — exit the app
|
||||||
create table <T> with pk [<col>:<type>...]
|
help: |-
|
||||||
drop table <T>
|
help — show this command list
|
||||||
add column [to] [table] <T>: <col> (<type>)
|
rebuild: |-
|
||||||
(for serial/shortid on a non-empty table: existing rows auto-filled)
|
rebuild — rebuild the project database from project.yaml + data/ (with confirmation)
|
||||||
drop column [from] [table] <T>: <col>
|
save: |-
|
||||||
rename column [in] [table] <T>: <old> to <new>
|
save — save the current temp project under a name
|
||||||
change column [in] [table] <T>: <col> (<newtype>)
|
save as — copy the current project to a new name/path
|
||||||
[--force-conversion | --dont-convert]
|
new: |-
|
||||||
(to serial/shortid: null cells auto-filled with generated values)
|
new — close the current project, start a fresh temp project
|
||||||
add 1:n relationship [as <name>] from <P>.<col> to <C>.<col>
|
load: |-
|
||||||
[on delete <action>] [on update <action>] [--create-fk]
|
load — open the project picker
|
||||||
drop relationship <name>
|
export: |-
|
||||||
insert into <T> [(cols)] [values] (vals)
|
export [<path>] — write a zip of project.yaml + data/ (excludes the database file and history.log)
|
||||||
update <T> set <c>=<v>... where <c>=<v> | --all-rows
|
import: |-
|
||||||
delete from <T> where <c>=<v> | --all-rows
|
import <zip> [as <target>] — unpack a zip into a new project and switch to it
|
||||||
show table <T>
|
mode: |-
|
||||||
show data <T>
|
mode simple|advanced — switch input mode
|
||||||
replay <path> — run each non-blank, non-`#`-comment line
|
messages: |-
|
||||||
of <path> as a command. Stops at the first
|
messages [short|verbose] — show or switch error-message verbosity (verbose is the default)
|
||||||
error (no rollback). Relative paths resolve
|
ddl:
|
||||||
under the current project's directory.
|
create: |-
|
||||||
|
create table <T> with pk [<col>:<type>, ...] — create a table
|
||||||
|
drop: |-
|
||||||
|
drop table <T> — remove a table
|
||||||
|
drop column [from] [table] <T>: <col> — remove a column
|
||||||
|
drop relationship <name> — remove a relationship
|
||||||
|
add: |-
|
||||||
|
add column [to] [table] <T>: <col> (<type>) — add a column
|
||||||
|
(for serial/shortid on a non-empty table: existing rows auto-filled)
|
||||||
|
add 1:n relationship [as <name>] from <P>.<col> to <C>.<col>
|
||||||
|
[on delete <action>] [on update <action>] [--create-fk] — declare a relationship
|
||||||
|
rename: |-
|
||||||
|
rename column [in] [table] <T>: <old> to <new> — rename a column
|
||||||
|
change: |-
|
||||||
|
change column [in] [table] <T>: <col> (<newtype>) [--force-conversion | --dont-convert]
|
||||||
|
— change a column's type (to serial/shortid: null cells auto-filled with generated values)
|
||||||
|
data:
|
||||||
|
show: |-
|
||||||
|
show table <T> — show a table's structure
|
||||||
|
show data <T> — show a table's rows
|
||||||
|
insert: |-
|
||||||
|
insert into <T> [(cols)] [values] (vals) — add a row
|
||||||
|
update: |-
|
||||||
|
update <T> set <c>=<v>, ... where <c>=<v> | --all-rows — change matching rows
|
||||||
|
delete: |-
|
||||||
|
delete from <T> where <c>=<v> | --all-rows — remove matching rows
|
||||||
|
replay: |-
|
||||||
|
replay <path> — run each non-blank, non-`#`-comment line of <path>
|
||||||
|
as a command. Stops at the first error (no rollback);
|
||||||
|
relative paths resolve under the project directory.
|
||||||
|
# Type reference, appended after the command list.
|
||||||
|
types_reference: |
|
||||||
Types: text, int, real, decimal, bool, date, datetime, blob, serial, shortid
|
Types: text, int, real, decimal, bool, date, datetime, blob, serial, shortid
|
||||||
Auto-generated types (serial, shortid):
|
Auto-generated types (serial, shortid):
|
||||||
serial — integer that auto-fills with the next sequence value
|
serial — integer that auto-fills with the next sequence value
|
||||||
|
|||||||
Reference in New Issue
Block a user