feat: curated SQL function list — Tab completion (#15) + typing-time typo hint (#16)

Add src/dsl/sql_functions.rs (KNOWN_SQL_FUNCTIONS) as the shared source
of truth at sql_expr_ident slots:

- #15: offer the functions as Tab candidates under a new
  CandidateKind::Function + ninth Theme colour tok_function (blue,
  distinct from keyword/identifier/type).
- #16: restore the column-typo flag the #6 fix had dropped wholesale —
  invalid_ident_at_cursor now bails only when the partial prefix-matches
  a known function, else falls through to the schema-column check.

A column named like a function (e.g. `count`) is deduped (column wins).
`cast` is excluded — CAST(x AS type) is not a plain-call shape.
The no-validation-allowlist posture stands: the list drives completion +
the typo hint only, never parse-time acceptance.

Docs: ADR-0022 Amendment 6, ADR-0031 status note, README index,
requirements I3/I4 + refreshed test baseline.
This commit is contained in:
claude@clouddev1
2026-05-31 11:49:10 +00:00
parent 01ec926ec8
commit 6d8c9eea36
10 changed files with 570 additions and 25 deletions
+23
View File
@@ -61,6 +61,13 @@ pub struct Theme {
pub tok_punct: Color,
pub tok_flag: Color,
pub tok_error: Color,
/// SQL function-name candidate colour (ADR-0022 Amendment 6,
/// issue #15) — a dedicated tone distinct from `tok_keyword`,
/// `tok_identifier`, and `tok_type` so a learner can tell a
/// callable (`sum`, `upper`) apart from a clause keyword, a
/// column reference, and a column type. Drives the
/// `CandidateKind::Function` colour in the hint panel.
pub tok_function: Color,
}
impl Theme {
@@ -95,6 +102,7 @@ impl Theme {
tok_punct: Color::Rgb(0x8B, 0x90, 0x9A), // == muted
tok_flag: Color::Rgb(0xFF, 0xCB, 0x6B), // amber
tok_error: Color::Rgb(0xFF, 0x6B, 0x6B), // == error
tok_function: Color::Rgb(0x82, 0xCF, 0xFD), // sky blue — cool like keyword but bluer, clearly apart from purple keyword + teal identifier + pink type
}
}
@@ -125,6 +133,7 @@ impl Theme {
tok_punct: Color::Rgb(0x60, 0x66, 0x73), // == muted
tok_flag: Color::Rgb(0xB0, 0x88, 0x00), // mustard
tok_error: Color::Rgb(0xC0, 0x39, 0x2B), // == error
tok_function: Color::Rgb(0x1A, 0x5F, 0xB0), // strong blue — cool like keyword but bluer, apart from royal-purple keyword + teal identifier + magenta type
}
}
@@ -169,6 +178,7 @@ mod tests {
("tok_string", t.tok_string),
("tok_flag", t.tok_flag),
("tok_error", t.tok_error),
("tok_function", t.tok_function),
("warning", t.warning),
] {
assert_ne!(
@@ -188,6 +198,7 @@ mod tests {
("tok_string", t.tok_string),
("tok_flag", t.tok_flag),
("tok_error", t.tok_error),
("tok_function", t.tok_function),
("warning", t.warning),
] {
assert_ne!(
@@ -220,4 +231,16 @@ mod tests {
assert_ne!(t.tok_type, t.tok_identifier);
}
}
#[test]
fn function_colour_is_distinct_from_keyword_identifier_and_type() {
// ADR-0022 Amendment 6 / issue #15: function-name candidates
// get their own tone so a callable reads apart from a clause
// keyword, a column reference, and a column type.
for t in [Theme::dark(), Theme::light()] {
assert_ne!(t.tok_function, t.tok_keyword);
assert_ne!(t.tok_function, t.tok_identifier);
assert_ne!(t.tok_function, t.tok_type);
}
}
}