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:
@@ -444,7 +444,7 @@ fn render_output_panel(app: &mut App, theme: &Theme, frame: &mut Frame<'_>, area
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(theme.border))
|
||||
.title(Span::styled(
|
||||
" Output ",
|
||||
format!(" {} ", crate::t!("panel.output_title")),
|
||||
Style::default()
|
||||
.fg(theme.fg)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
@@ -576,15 +576,23 @@ fn render_output_line<'a>(line: &'a OutputLine, theme: &Theme) -> Line<'a> {
|
||||
fn render_input_panel(app: &App, theme: &Theme, frame: &mut Frame<'_>, area: Rect) {
|
||||
let effective = app.effective_mode();
|
||||
let (border_color, mode_color, label) = match effective {
|
||||
EffectiveMode::Simple => (theme.border, theme.mode_simple, "SIMPLE"),
|
||||
EffectiveMode::AdvancedPersistent => {
|
||||
(theme.border_advanced, theme.mode_advanced, "ADVANCED")
|
||||
}
|
||||
EffectiveMode::Simple => (
|
||||
theme.border,
|
||||
theme.mode_simple,
|
||||
crate::t!("mode.label_simple"),
|
||||
),
|
||||
EffectiveMode::AdvancedPersistent => (
|
||||
theme.border_advanced,
|
||||
theme.mode_advanced,
|
||||
crate::t!("mode.label_advanced"),
|
||||
),
|
||||
// Mixed-case label distinguishes the one-shot (`:`-triggered)
|
||||
// state from a persistent advanced mode at a glance.
|
||||
EffectiveMode::AdvancedOneShot => {
|
||||
(theme.border_advanced, theme.mode_advanced, "Advanced:")
|
||||
}
|
||||
EffectiveMode::AdvancedOneShot => (
|
||||
theme.border_advanced,
|
||||
theme.mode_advanced,
|
||||
crate::t!("mode.label_advanced_one_shot"),
|
||||
),
|
||||
};
|
||||
|
||||
let title = Line::from(vec![
|
||||
@@ -681,7 +689,7 @@ fn render_hint_panel(app: &App, theme: &Theme, frame: &mut Frame<'_>, area: Rect
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(theme.border))
|
||||
.title(Span::styled(
|
||||
" Hint ",
|
||||
format!(" {} ", crate::t!("panel.hint_title")),
|
||||
Style::default()
|
||||
.fg(theme.fg)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
@@ -757,6 +765,7 @@ fn render_candidate_line(
|
||||
let base_fg = match items[i].kind {
|
||||
crate::completion::CandidateKind::Keyword => theme.tok_keyword,
|
||||
crate::completion::CandidateKind::Identifier => theme.tok_identifier,
|
||||
crate::completion::CandidateKind::Flag => theme.tok_flag,
|
||||
};
|
||||
let mut s = Style::default().fg(base_fg);
|
||||
if Some(i) == selected {
|
||||
|
||||
Reference in New Issue
Block a user