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:
@@ -2632,7 +2632,11 @@ fn render_lossy_diagnostic(
|
||||
lossies: &[&Outcome],
|
||||
) -> String {
|
||||
let mut headers = pk_header_cells(pk_columns);
|
||||
headers.extend(["From".to_string(), "To".to_string(), "Reason".to_string()]);
|
||||
headers.extend([
|
||||
crate::t!("db.diagnostic.header_from"),
|
||||
crate::t!("db.diagnostic.header_to"),
|
||||
crate::t!("db.diagnostic.header_reason"),
|
||||
]);
|
||||
|
||||
let mut alignments = pk_header_alignments(pk_columns, old_schema);
|
||||
alignments.extend([
|
||||
@@ -2662,18 +2666,22 @@ fn render_lossy_diagnostic(
|
||||
}
|
||||
|
||||
let mut out = format!(
|
||||
"Cannot change `{table}.{column}` from {src_ty} to {target_ty}: \
|
||||
{total} row(s) would discard information.\n\n"
|
||||
"{}\n\n",
|
||||
crate::t!(
|
||||
"db.diagnostic.lossy_summary",
|
||||
table = table,
|
||||
column = column,
|
||||
src_ty = src_ty,
|
||||
target_ty = target_ty,
|
||||
total = total,
|
||||
),
|
||||
);
|
||||
for line in render_diagnostic_table(&headers, &rows, &alignments) {
|
||||
out.push_str(&line);
|
||||
out.push('\n');
|
||||
}
|
||||
out.push('\n');
|
||||
out.push_str(
|
||||
"if you want to execute this conversion in spite of the problems, \
|
||||
re-run with `--force-conversion`.",
|
||||
);
|
||||
out.push_str(&crate::t!("db.diagnostic.force_conversion_hint"));
|
||||
out
|
||||
}
|
||||
|
||||
@@ -2688,7 +2696,10 @@ fn render_incompatible_diagnostic(
|
||||
incompatibles: &[&Outcome],
|
||||
) -> String {
|
||||
let mut headers = pk_header_cells(pk_columns);
|
||||
headers.extend(["Value".to_string(), "Reason".to_string()]);
|
||||
headers.extend([
|
||||
crate::t!("db.diagnostic.header_value"),
|
||||
crate::t!("db.diagnostic.header_reason"),
|
||||
]);
|
||||
|
||||
let mut alignments = pk_header_alignments(pk_columns, old_schema);
|
||||
alignments.extend([
|
||||
@@ -2714,8 +2725,15 @@ fn render_incompatible_diagnostic(
|
||||
}
|
||||
|
||||
let mut out = format!(
|
||||
"Cannot change `{table}.{column}` from {src_ty} to {target_ty}: \
|
||||
{total} row(s) cannot be converted.\n\n"
|
||||
"{}\n\n",
|
||||
crate::t!(
|
||||
"db.diagnostic.incompatible_summary",
|
||||
table = table,
|
||||
column = column,
|
||||
src_ty = src_ty,
|
||||
target_ty = target_ty,
|
||||
total = total,
|
||||
),
|
||||
);
|
||||
for line in render_diagnostic_table(&headers, &rows, &alignments) {
|
||||
out.push_str(&line);
|
||||
@@ -2766,9 +2784,9 @@ fn check_uniqueness_collisions(
|
||||
|
||||
let pk_label = pk_columns.join(", ");
|
||||
let headers = vec![
|
||||
"Becomes".to_string(),
|
||||
format!("Source rows ({pk_label})"),
|
||||
"Source values".to_string(),
|
||||
crate::t!("db.diagnostic.header_becomes"),
|
||||
crate::t!("db.diagnostic.header_source_rows", pk_label = pk_label),
|
||||
crate::t!("db.diagnostic.header_source_values"),
|
||||
];
|
||||
|
||||
let alignments = vec![
|
||||
@@ -2814,8 +2832,15 @@ fn check_uniqueness_collisions(
|
||||
let _ = old_schema;
|
||||
|
||||
let mut out = format!(
|
||||
"Cannot change `{table}.{column}` from {src_ty} to {target_ty}: \
|
||||
{total} collision(s) would violate uniqueness.\n\n"
|
||||
"{}\n\n",
|
||||
crate::t!(
|
||||
"db.diagnostic.uniqueness_summary",
|
||||
table = table,
|
||||
column = column,
|
||||
src_ty = src_ty,
|
||||
target_ty = target_ty,
|
||||
total = total,
|
||||
),
|
||||
);
|
||||
for line in render_diagnostic_table(&headers, &rows, &alignments) {
|
||||
out.push_str(&line);
|
||||
|
||||
Reference in New Issue
Block a user