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:
@@ -116,6 +116,19 @@ pub fn hint_resolution_at_input_in_mode(
|
||||
use crate::dsl::grammar::HintMode;
|
||||
|
||||
let snap = expected_for_hint_snapshot(source, schema, mode);
|
||||
// Issue #26: an optional positional slot with no candidate text
|
||||
// (the `seed <table>` row count) left an `IntroProse` hint that
|
||||
// survived the trailing optionals. It is shown even for an
|
||||
// otherwise-complete command (empty expected set) — that is exactly
|
||||
// the `seed users ▮` case where the count is invisible. Checked
|
||||
// first, before the complete-command short-circuit below.
|
||||
if let Some(key) = snap.surviving_intro_hint {
|
||||
return Some(HintResolution {
|
||||
mode: HintMode::IntroProse(key),
|
||||
column: None,
|
||||
form_b_autogen_skipped: Vec::new(),
|
||||
});
|
||||
}
|
||||
// Empty expected set means the command is already complete
|
||||
// (`WalkOutcome::Match`) — no slot to hint at.
|
||||
if snap.expected.is_empty() {
|
||||
@@ -2599,6 +2612,11 @@ struct HintWalkSnapshot {
|
||||
/// The grammar-declared `HintMode` at the cursor's slot
|
||||
/// (`Node::Hinted` annotation, ADR-0024 §HintMode-per-node).
|
||||
pending_hint_mode: Option<crate::dsl::grammar::HintMode>,
|
||||
/// An `IntroProse` catalog key for an *optional* positional slot at
|
||||
/// the cursor that produced no candidate (issue #26 — `seed <table>`
|
||||
/// row count). Survives the trailing optional siblings that clear
|
||||
/// `pending_hint_mode`; already filtered to the cursor position.
|
||||
surviving_intro_hint: Option<&'static str>,
|
||||
current_table_columns: Option<Vec<crate::completion::TableColumn>>,
|
||||
/// `Some` when the input used Form A's explicit column list.
|
||||
/// `None` for Form B (`insert into T values …`) and for
|
||||
@@ -2625,6 +2643,7 @@ fn expected_for_hint_snapshot(
|
||||
pending_value_type: None,
|
||||
pending_value_column: None,
|
||||
pending_hint_mode: None,
|
||||
surviving_intro_hint: None,
|
||||
current_table_columns: None,
|
||||
user_listed_columns: None,
|
||||
};
|
||||
@@ -2652,6 +2671,14 @@ fn expected_for_hint_snapshot(
|
||||
pending_value_type: ctx.pending_value_type,
|
||||
pending_value_column: ctx.pending_value_column,
|
||||
pending_hint_mode: ctx.pending_hint_mode,
|
||||
// Issue #26: only surface the skipped-optional hint when the
|
||||
// optional was skipped *at the cursor* (the end of the walked
|
||||
// slice). Captured earlier (before a later clause consumed past
|
||||
// it) → stale, so drop it.
|
||||
surviving_intro_hint: ctx
|
||||
.surviving_intro_hint
|
||||
.filter(|(_, pos)| *pos == source.len())
|
||||
.map(|(key, _)| key),
|
||||
current_table_columns: ctx.current_table_columns,
|
||||
user_listed_columns: ctx.user_listed_columns,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user