7f68a53f86
walk_repeated discarded the last matched item's trailing-optional expectations at a clean item boundary, so a comma-separated list offered no continuation after a complete item: `order by Name ` gave no asc/desc, `select Name ` no `as`, `create table … Code(text) ` no not/unique/default/check. Capture the last item's skipped set and surface it when the list ends at an item boundary (the separator `,` itself is deliberately not surfaced). That fix made expression-position candidate lists long, which exposed a visibility problem: the hint panel's candidate line is single-row and window-scrolls on overflow, centring on item 0 when nothing is selected — so with keywords-first, schema identifiers scrolled off behind the `>` marker. Reverse the ordering: schema identifiers (table/column/relationship names) now sort before keywords, since a name the user would have to look up is the highest-value completion and must stay visible (keywords are learned over time; the tok_identifier/tok_keyword colour split marks the boundary). This reverses the handoff-14 keywords-first call, now recorded in ADR-0022 Amendment 2. Tests: walker expected-set + completion-layer regressions for the trailing-optionals and the ordering; candidate_ordering.rs header invariant inverted; ~20 typing-surface snapshots re-baselined; a two-line hint box recorded as a deferred follow-up.
133 lines
4.8 KiB
Rust
133 lines
4.8 KiB
Rust
//! Matrix coverage for completion-candidate *ordering*.
|
|
//!
|
|
//! The order candidates appear in is load-bearing for the hint
|
|
//! panel: the candidate line is single-row and window-scrolls
|
|
//! when it overflows, so whatever sits first is what stays
|
|
//! visible by default. Two invariants:
|
|
//!
|
|
//! 1. Connective keywords appear in grammar-declaration / reading
|
|
//! order — `to` before `table` so `add column to table T`
|
|
//! reads correctly, never the jarring `table` / `to`.
|
|
//! 2. Schema identifiers (table / column names) appear *before*
|
|
//! command-part keywords. A name the user would otherwise
|
|
//! have to look up is the highest-value completion — valuable
|
|
//! even to experts, who come to know the keywords over time —
|
|
//! so it must stay visible by default rather than scroll off
|
|
//! behind the keyword run. (ADR-0022 Amendment 2; reverses the
|
|
//! earlier handoff-14 keywords-first call, which held only
|
|
//! while candidate lists were short.)
|
|
//!
|
|
//! These hold via declaration-order preservation +
|
|
//! identifiers-first sectioning in `candidates_at_cursor`.
|
|
|
|
use crate::typing_surface::*;
|
|
|
|
/// Index of `needle` in the ordered completion candidate list,
|
|
/// or panic with the full list for diagnosis.
|
|
fn pos(a: &Assessment, needle: &str) -> usize {
|
|
let cands = completion_candidate_texts(a);
|
|
cands
|
|
.iter()
|
|
.position(|c| c == needle)
|
|
.unwrap_or_else(|| panic!("{needle:?} not in candidates: {cands:?}"))
|
|
}
|
|
|
|
/// Assert `first` appears before `second` in the candidate list.
|
|
fn assert_before(a: &Assessment, first: &str, second: &str) {
|
|
let pf = pos(a, first);
|
|
let ps = pos(a, second);
|
|
assert!(
|
|
pf < ps,
|
|
"expected {first:?} (idx {pf}) before {second:?} (idx {ps}): {:?}",
|
|
completion_candidate_texts(a),
|
|
);
|
|
}
|
|
|
|
// =========================================================
|
|
// Connective ordering: the `[connective] [table] <T>` shape
|
|
// shared by the DDL commands.
|
|
// =========================================================
|
|
|
|
#[test]
|
|
fn add_column_lists_to_before_table() {
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("add column ", &schema);
|
|
assert_before(&a, "to", "table");
|
|
crate::snap!("add_column_connectives", a);
|
|
}
|
|
|
|
#[test]
|
|
fn drop_column_lists_from_before_table() {
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("drop column ", &schema);
|
|
assert_before(&a, "from", "table");
|
|
crate::snap!("drop_column_connectives", a);
|
|
}
|
|
|
|
#[test]
|
|
fn rename_column_lists_in_before_table() {
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("rename column ", &schema);
|
|
assert_before(&a, "in", "table");
|
|
crate::snap!("rename_column_connectives", a);
|
|
}
|
|
|
|
#[test]
|
|
fn change_column_lists_in_before_table() {
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("change column ", &schema);
|
|
assert_before(&a, "in", "table");
|
|
crate::snap!("change_column_connectives", a);
|
|
}
|
|
|
|
// =========================================================
|
|
// Identifiers-before-keywords: at a position where both a
|
|
// connective keyword and schema table names are valid, the
|
|
// schema identifiers come first (ADR-0022 Amendment 2).
|
|
// =========================================================
|
|
|
|
#[test]
|
|
fn add_column_identifiers_precede_table_keywords() {
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("add column ", &schema);
|
|
// Customers / Orders are schema identifiers; `to` / `table`
|
|
// are command parts — every ident precedes every keyword.
|
|
assert_before(&a, "Customers", "table");
|
|
assert_before(&a, "Customers", "to");
|
|
assert_before(&a, "Orders", "to");
|
|
crate::snap!("add_column_idents_then_keyword", a);
|
|
}
|
|
|
|
#[test]
|
|
fn drop_column_identifiers_precede_table_keywords() {
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("drop column ", &schema);
|
|
assert_before(&a, "Customers", "table");
|
|
assert_before(&a, "Orders", "from");
|
|
crate::snap!("drop_column_idents_then_keyword", a);
|
|
}
|
|
|
|
#[test]
|
|
fn insert_into_table_keyword_precedes_nothing_when_only_idents() {
|
|
// Sanity: at `insert into ` only table identifiers are
|
|
// valid — no keyword to precede them, but the ordering must
|
|
// still be deterministic (alphabetical among idents).
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("insert into ", &schema);
|
|
assert_before(&a, "Customers", "Orders");
|
|
crate::snap!("insert_into_idents_only", a);
|
|
}
|
|
|
|
// =========================================================
|
|
// After consuming the first connective, identifiers still
|
|
// surface ahead of the remaining keyword.
|
|
// =========================================================
|
|
|
|
#[test]
|
|
fn add_column_after_to_lists_identifiers_before_table() {
|
|
let schema = schema_multi_table();
|
|
let a = assess_at_end("add column to ", &schema);
|
|
assert_before(&a, "Customers", "table");
|
|
crate::snap!("add_column_after_to", a);
|
|
}
|