ADR-0022 stage 8c: IdentSlot propagation + SchemaCache API
`IdentSlot` gains `expected_label()` and the round-trip
`from_expected_label()`. The four slot kinds map to the
user-facing labels "identifier" (NewName), "table name",
"column name", "relationship name".
`ident_ctx(slot)` now actually applies `slot.expected_label()`
as the chumsky label (was documentation-only after stage 6).
Parser errors and the hint panel's "expected: …" prose now
read with the slot-specific name: "expected table name"
instead of the generic "expected identifier". One parser
test updated accordingly; the four catalog `parse.token.*`
keys are unaffected (the slot labels are a parallel surface).
New `completion::SchemaCache { tables, columns,
relationships }` struct + `for_slot(slot) -> &[String]`
accessor. Empty by default; runtime wiring lands in a
follow-on substage. NewName slots return `&[]`
unconditionally.
`candidates_at_cursor` extended to accept `&SchemaCache`:
when the parser's expected-set includes a slot label,
schema candidates from the cache are added alongside the
keyword candidates. Both sources are then prefix-filtered,
combined, sorted, deduplicated. App::schema_cache field
threaded into both the App-side completion paths and the
ambient_hint computation in ui.
Tests: 738 passing, 0 failing, 1 ignored (730 baseline →
+8: 2 IdentSlot label round-trip tests, 6 completion-with-cache
cases covering table/column/relationship slots, prefix
filtering, empty cache, and NewName-no-candidates).
Clippy clean.
User-visible: identifier completion infrastructure is in
place but the cache is always empty — runtime wiring (the
next substage) will populate it on project load and after
successful DDL, at which point Tab on identifier slots
starts offering schema names.
This commit is contained in:
+19
-13
@@ -180,27 +180,29 @@ fn punct<'a>(
|
||||
/// command parsers must use `ident_ctx(slot)` so the
|
||||
/// completion engine knows what kind of identifier each
|
||||
/// position expects (ADR-0022 §8). Bare `ident_inner()` calls
|
||||
/// outside this module would skip the slot annotation.
|
||||
/// outside this module would skip the slot annotation. The
|
||||
/// label is applied by `ident_ctx` (one per call site) — none
|
||||
/// here.
|
||||
fn ident_inner<'a>()
|
||||
-> impl Parser<'a, &'a [Token], String, extra::Err<Rich<'a, Token>>> + Clone {
|
||||
select_ref! {
|
||||
Token { kind: TokenKind::Identifier(s), .. } => s.clone()
|
||||
}
|
||||
.labelled("identifier")
|
||||
.as_context()
|
||||
}
|
||||
|
||||
/// Tag-and-parse an identifier slot. `slot` is currently
|
||||
/// documentation-only — the parser does not propagate it to
|
||||
/// chumsky's `extra` data — but the call-site annotation
|
||||
/// forces every parser author to think about the slot at the
|
||||
/// moment of writing the combinator. The `no_bare_ident_inner_calls`
|
||||
/// unit test enforces that no command parser calls `ident_inner`
|
||||
/// directly (only via this wrapper).
|
||||
/// Tag-and-parse an identifier slot. The slot's user-facing
|
||||
/// label (`IdentSlot::expected_label`) replaces the generic
|
||||
/// "identifier" in the parser's expected-set machinery, so
|
||||
/// the error message reads "expected table name" /
|
||||
/// "expected column name" / "expected relationship name" /
|
||||
/// "expected identifier" depending on the call site
|
||||
/// (ADR-0022 stage 8c). The completion engine reverses the
|
||||
/// mapping via `IdentSlot::from_expected_label` to know what
|
||||
/// schema list to consult.
|
||||
fn ident_ctx<'a>(
|
||||
_slot: crate::dsl::ident_slot::IdentSlot,
|
||||
slot: crate::dsl::ident_slot::IdentSlot,
|
||||
) -> impl Parser<'a, &'a [Token], String, extra::Err<Rich<'a, Token>>> + Clone {
|
||||
ident_inner()
|
||||
ident_inner().labelled(slot.expected_label()).as_context()
|
||||
}
|
||||
|
||||
/// Match a number-literal token, returning a `Value::Number`.
|
||||
@@ -912,9 +914,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn structural_error_for_show_data_without_arg() {
|
||||
// ADR-0022 stage 8c: `ident_ctx(IdentSlot::TableName)`
|
||||
// labels the expected slot with "table name" so the
|
||||
// error reads as the more specific "expected table
|
||||
// name" rather than the generic "expected identifier".
|
||||
let msg = err_message("show data");
|
||||
assert!(msg.contains("after `show data`"), "{msg}");
|
||||
assert!(msg.contains("expected identifier"), "{msg}");
|
||||
assert!(msg.contains("expected table name"), "{msg}");
|
||||
assert!(msg.contains("found end of input"), "{msg}");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user