round-5 follow-up: completion + i18n sweep
Four user-reported gaps from the round-4 testing pass:
1. Empty-prompt hint reworded from "(no active hint)" to
"Type a command — press Tab for options, `help` for a
list" (6 snapshots updated to reflect 80-col truncation).
2. App-lifecycle commands (quit/q, help, rebuild, save/save as,
new, load, export, import, mode, messages) now flow through
the DSL parser:
- 15 new keywords + catalog token entries
- new Command::App(AppCommand) AST with 11 variants
- parse-first dispatch in submit() (app commands work in
both simple and advanced modes)
- pre-chumsky source-slice for `export <path>` /
`import <zip> [as <target>]` mirrors the replay precedent
- UsageEntry registry entries so parse errors surface
relevant usage templates
- `mode <bad>` / `messages <bad>` use try_map for the
friendly "unknown mode/messages" wording
3. DSL completion gaps:
- `1:n` surfaces as a composite candidate at `add `
- --all-rows / --create-fk / --force-conversion /
--dont-convert surface as new CandidateKind::Flag
candidates (coloured with tok_flag in hint panel)
- filter_clause .labelled() wrap removed so chumsky's
expected-set surfaces the constituent options
4. Hardcoded user-facing strings migrated to catalog:
- 4 parser custom errors (incl. the known "tables need at
least one column" wart)
- UnknownType Display now via parse.custom.unknown_type
- UI panel titles + mode labels (Output / Hint / SIMPLE /
ADVANCED / Advanced:)
- app.rs cascade rendering (action labels + summary)
- runtime --resume CLI stderr
- db.rs change-column diagnostic tables (7 headers + 3
wrapper summaries + force-conversion hint)
Tests: 765 → 769 passing, 0 failed, 1 ignored (same doctest
as before). Clippy clean with -D warnings.
Deferred:
- ~25 thiserror #[error] attributes still hand-rolled
(DbError, ArgsError, ArchiveError, PersistenceError,
LockError). Tracked separately.
- DSL/SQL relationship in advanced mode — clarified
implicitly via parse-first dispatch; broader ADR
amendment to follow.
- Post-complete-parse completion gap (e.g. `save ` Tab
can't offer `as` because `save` parses bare; same shape
as `--create-fk` after a complete `add relationship`).
This commit is contained in:
@@ -142,6 +142,60 @@ pub enum Command {
|
||||
Replay {
|
||||
path: String,
|
||||
},
|
||||
/// App-lifecycle command (per ADR-0003). These work in both
|
||||
/// simple and advanced modes; the dispatcher branches on the
|
||||
/// `Command::App(...)` variant before mode-specific routing.
|
||||
/// Folded into the DSL parser so they participate in Tab
|
||||
/// completion + parse-error usage templates alongside the
|
||||
/// data commands.
|
||||
App(AppCommand),
|
||||
}
|
||||
|
||||
/// App-level commands surfaced through the DSL parser. These do
|
||||
/// not touch the database schema or data — they affect app
|
||||
/// lifecycle, mode, persistence, and verbosity.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum AppCommand {
|
||||
/// Exit cleanly. Accepts the `q` alias.
|
||||
Quit,
|
||||
/// Show in-app help. Body comes from `help.in_app_body`.
|
||||
Help,
|
||||
/// Rebuild `playground.db` from `project.yaml` + data/, with
|
||||
/// confirmation modal.
|
||||
Rebuild,
|
||||
/// Save the current project under a name (modal-driven).
|
||||
Save,
|
||||
/// Save the current project as a copy under a new path
|
||||
/// (modal-driven).
|
||||
SaveAs,
|
||||
/// Close current, create a fresh temp project.
|
||||
New,
|
||||
/// Open the project picker modal.
|
||||
Load,
|
||||
/// Write a zip of project.yaml + data/. `path` is the user-
|
||||
/// typed target (may be a name under the data root or an
|
||||
/// absolute path). `None` opens the path prompt modal.
|
||||
Export { path: Option<String> },
|
||||
/// Unpack a zip into a new project and switch to it.
|
||||
/// `target` overrides the project name (default: taken from
|
||||
/// the zip).
|
||||
Import { path: String, target: Option<String> },
|
||||
/// Switch the persistent input mode.
|
||||
Mode { value: ModeValue },
|
||||
/// Show or set the messages verbosity.
|
||||
Messages { value: Option<MessagesValue> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ModeValue {
|
||||
Simple,
|
||||
Advanced,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum MessagesValue {
|
||||
Short,
|
||||
Verbose,
|
||||
}
|
||||
|
||||
/// Conversion mode for `change column …` (ADR-0017 §5).
|
||||
@@ -218,6 +272,19 @@ impl Command {
|
||||
Self::Delete { .. } => "delete from",
|
||||
Self::ShowData { .. } => "show data",
|
||||
Self::Replay { .. } => "replay",
|
||||
Self::App(app) => match app {
|
||||
AppCommand::Quit => "quit",
|
||||
AppCommand::Help => "help",
|
||||
AppCommand::Rebuild => "rebuild",
|
||||
AppCommand::Save => "save",
|
||||
AppCommand::SaveAs => "save as",
|
||||
AppCommand::New => "new",
|
||||
AppCommand::Load => "load",
|
||||
AppCommand::Export { .. } => "export",
|
||||
AppCommand::Import { .. } => "import",
|
||||
AppCommand::Mode { .. } => "mode",
|
||||
AppCommand::Messages { .. } => "messages",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,6 +321,11 @@ impl Command {
|
||||
// Replay isn't tied to a single table; the path is
|
||||
// the most identifying thing for log output.
|
||||
Self::Replay { path } => path,
|
||||
// App commands aren't tied to schema entities — the
|
||||
// verb is the most identifying thing. The
|
||||
// display_subject override below provides a richer
|
||||
// form when one exists.
|
||||
Self::App(_) => "",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user