feat(hint): advertise the optional seed count in the hint panel (#26)
At `seed <table> ▮` the hint showed only the `set`/`--seed` chips and
never mentioned the optional row count — a bare positional number with no
candidate, on an already-complete command, so neither the candidate
ladder nor the resolver surfaced it. (A prior IntroProse attempt was
reverted: pending_hint_mode is cleared by the trailing optionals.)
Carry a skipped Optional's IntroProse hint: walk_optional stashes the
inner's key into a new WalkContext.surviving_intro_hint (key + position)
before the empty match clears pending_hint_mode; the snapshot keeps it
only when the skip position is the cursor (so it never leaks past a
later-consumed `set …` clause, nor once the count is given); the
resolver returns it ahead of the empty-expected short-circuit. The seed
count is wrapped Hinted{IntroProse("hint.seed_count")}; the prose names
the count (default 20), the `.column` column-fill form, and `set` /
`--seed`. Tab still cycles the keywords.
Only IntroProse is carried; ProseOnly/ForceProse and the CREATE-TABLE
element (a required Repeated) are untouched. No AmbientHint/renderer
change. Fires in both modes.
ADR-0022 Amendment 7; +3 tests.
This commit is contained in:
@@ -990,6 +990,21 @@ fn walk_seq(
|
||||
}
|
||||
}
|
||||
|
||||
/// Issue #26: when an `Optional` is skipped (its inner didn't engage),
|
||||
/// stash any `IntroProse` hint the inner left in `pending_hint_mode`
|
||||
/// into the surviving slot before it is cleared by this empty match.
|
||||
/// `position` is where the optional was skipped — the resolver compares
|
||||
/// it to the cursor so the hint only shows while the cursor sits at that
|
||||
/// optional, not after a later clause consumes input past it. Only
|
||||
/// `IntroProse` is carried (it is the "introduce an optional position"
|
||||
/// mode); `ProseOnly` / `ForceProse` mark active slots and reach the
|
||||
/// resolver through the normal `pending_hint_mode` path.
|
||||
const fn capture_skipped_intro_hint(ctx: &mut WalkContext, position: usize) {
|
||||
if let Some(crate::dsl::grammar::HintMode::IntroProse(key)) = ctx.pending_hint_mode {
|
||||
ctx.surviving_intro_hint = Some((key, position));
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_optional(
|
||||
source: &str,
|
||||
position: usize,
|
||||
@@ -1008,6 +1023,7 @@ fn walk_optional(
|
||||
// Inner didn't engage at all — skip the Optional
|
||||
// but carry the inner's expectations so the caller's
|
||||
// expected-set sees them.
|
||||
capture_skipped_intro_hint(ctx, position);
|
||||
path.items.truncate(saved_path_len);
|
||||
per_byte.truncate(saved_byte_len);
|
||||
NodeWalkResult::Matched {
|
||||
@@ -1019,6 +1035,7 @@ fn walk_optional(
|
||||
// Inner reported Incomplete without consuming
|
||||
// anything — same as NoMatch from the user's
|
||||
// perspective. Roll back and skip.
|
||||
capture_skipped_intro_hint(ctx, position);
|
||||
path.items.truncate(saved_path_len);
|
||||
per_byte.truncate(saved_byte_len);
|
||||
let _ = p;
|
||||
|
||||
Reference in New Issue
Block a user