//! 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] ` 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); }