walker: keep optional trailing flags completable after --
Typing `--` to start an optional trailing flag (`--create-fk` on `add 1:n relationship`, `--cascade` on `drop column`, `--force-conversion` / `--dont-convert` on `change column`) made completion go empty: the trailing `--` turns the parse into a trailing-junk Mismatch, and the Mismatch arm of the completion expected-set resolution returned only `[EndOfInput]` — the skipped optional-flag expectations, carried in `tail_expected`, were dropped. completion_probe and expected_at_input now merge `tail_expected` into a Mismatch's expected set. `tail_expected` is empty for a genuine mid-command mismatch, so this only adds the outer shape's skipped trailing optionals — exactly the continuations the trailing `--` is starting to type. This also resolves the "wrong usage hint" symptom: with `--create-fk` offered as a candidate, the hint panel shows candidates instead of falling through to the parse-error usage block. Audit outcome (the requested scan): usage_key_for_input was verified correct for every multi-form command — add / drop / show, including the digit-led `add 1:n relationship` form — and is now regression-locked. The flag-completion fix covers the whole optional-trailing-flag class. 6 tests (3 flag-completion, 3 usage-key). 1131 passing.
This commit is contained in:
+27
-4
@@ -276,8 +276,19 @@ pub fn completion_probe(
|
||||
};
|
||||
let expected = match result.outcome {
|
||||
outcome::WalkOutcome::Match { .. } => result.tail_expected,
|
||||
outcome::WalkOutcome::Incomplete { expected, .. }
|
||||
| outcome::WalkOutcome::Mismatch { expected, .. } => expected,
|
||||
// A trailing-junk Mismatch (the shape matched, then the
|
||||
// user kept typing) still carries the outer shape's
|
||||
// skipped trailing optionals in `tail_expected` — e.g.
|
||||
// an optional `--create-fk` flag the trailing `--` is
|
||||
// starting to type. Merge them so completion still
|
||||
// offers the optional continuation. A genuine
|
||||
// mid-command mismatch has an empty `tail_expected`.
|
||||
outcome::WalkOutcome::Mismatch { expected, .. } => {
|
||||
let mut merged = expected;
|
||||
merged.extend(result.tail_expected);
|
||||
merged
|
||||
}
|
||||
outcome::WalkOutcome::Incomplete { expected, .. } => expected,
|
||||
// Validation failure path: the walker matched the
|
||||
// structural shape but the AST builder rejected (e.g.
|
||||
// Form C with column-shaped items). The walker still
|
||||
@@ -699,8 +710,20 @@ pub fn expected_at_input(source: &str) -> Vec<outcome::Expectation> {
|
||||
// optional-suffix candidates at the end of a valid
|
||||
// command (`save` → `as`, etc.).
|
||||
outcome::WalkOutcome::Match { .. } => result.tail_expected,
|
||||
outcome::WalkOutcome::Incomplete { expected, .. }
|
||||
| outcome::WalkOutcome::Mismatch { expected, .. } => expected,
|
||||
// A trailing-junk Mismatch (the shape matched, then the
|
||||
// user kept typing) still carries the outer shape's
|
||||
// skipped trailing optionals in `tail_expected` — e.g.
|
||||
// an optional `--create-fk` flag the trailing `--` is
|
||||
// starting to type. Surface those alongside the
|
||||
// mismatch's own expected set so completion still offers
|
||||
// them. A genuine mid-command mismatch has an empty
|
||||
// `tail_expected`, so this is a no-op there.
|
||||
outcome::WalkOutcome::Mismatch { expected, .. } => {
|
||||
let mut merged = expected;
|
||||
merged.extend(result.tail_expected);
|
||||
merged
|
||||
}
|
||||
outcome::WalkOutcome::Incomplete { expected, .. } => expected,
|
||||
// Validation failure path: the walker matched the
|
||||
// structural shape but the AST builder rejected (e.g.
|
||||
// Form C with column-shaped items). The walker still
|
||||
|
||||
Reference in New Issue
Block a user