ADR-0024 round-5 follow-up: surface tail-Optional expectations
Pre-Phase-D, `save ` parsed as a complete `save` command, so the completion engine had nothing to mine: `as` never surfaced as a Tab candidate. This is the round-5 gap the handoffs have been tracking. `WalkResult` gains a `tail_expected: Vec<Expectation>` field. The walker's top-level `Matched` branch copies the outer shape's skipped-Optional expectations into it. `expected_at_input` returns `tail_expected` on `Match` so the completion engine sees the optional-suffix continuations and offers them as Tab candidates. `hint_mode_at_input` deliberately does NOT consume `tail_expected` — surfacing prose like "Type a name" at the end of a valid command would be misleading. A new private `expected_for_hint` returns empty on `Match` to preserve this. The split distinguishes "valid + could continue" (completion helps) from "invalid + must continue" (hint resolver helps). Tests: - `save ` Tab → `as` (new test, the original round-5 gap). - `messages ` Tab → `short` and `verbose` (same shape). - Existing `hint_mode_none_for_complete_command` stays green because hint resolver ignores tail_expected. - 830 total passing, 0 failing, 1 ignored. Clippy clean.
This commit is contained in:
+21
-8
@@ -814,14 +814,27 @@ mod tests {
|
||||
assert!(cs.contains(&"advanced".to_string()), "got {cs:?}");
|
||||
}
|
||||
|
||||
// Note: `save ` and `messages ` are deliberately NOT tested
|
||||
// here. Both commands accept their bare form as a valid parse
|
||||
// — `save` opens the save modal, `messages` shows the current
|
||||
// verbosity — so the parser returns Ok at those positions
|
||||
// and the completion engine has no expected-set to mine. The
|
||||
// optional-suffix candidates (`as`, `short`, `verbose`) would
|
||||
// need a separate probe mechanism (deferred — same shape as
|
||||
// the post-complete-parse gap for `--create-fk` etc.).
|
||||
// ---- Optional-suffix completion (round-5 gap, closed in Phase D) ----
|
||||
//
|
||||
// Pre-Phase-D: `save ` parsed as a valid `save` command, so
|
||||
// the completion engine had no expected-set to mine and the
|
||||
// `as` suffix never surfaced as a Tab candidate. Phase D's
|
||||
// `WalkResult::tail_expected` carries the outer shape's
|
||||
// skipped-Optional expectations even on `Match`, so these
|
||||
// surface without a separate probe mechanism.
|
||||
|
||||
#[test]
|
||||
fn save_space_offers_as_via_tail_expected() {
|
||||
let cs = cands("save ", 5);
|
||||
assert_eq!(cs, vec!["as".to_string()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn messages_space_offers_short_and_verbose_via_tail_expected() {
|
||||
let cs = cands("messages ", 9);
|
||||
assert!(cs.contains(&"short".to_string()), "got {cs:?}");
|
||||
assert!(cs.contains(&"verbose".to_string()), "got {cs:?}");
|
||||
}
|
||||
|
||||
// ---- Value-literal slot suppression (round-6) -----------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user