2g: advanced-mode highlight + engine.* wiring + matrix tests
Cross-cut verification matrix for ADR-0032 Phase 2 is now fully populated with concrete test references — every row green. Filling the matrix surfaced three real gaps that this commit closes. 1. Advanced-mode syntax highlighting (ADR-0030 §8 matrix row). The `ui.rs` Advanced branch routed through `plain_input_spans`, bypassing the highlight walker entirely. In production SQL keywords past the entry word rendered as plain identifiers. Fix: mode-aware variants of `highlight_runs`, `render_input_runs`, `lex_to_runs`, and `input_diagnostics`; the Advanced render path now uses the highlighted form with `Mode::Advanced`. `plain_input_spans` removed (unused). 2. Engine.* key wiring (ADR-0032 §11.4 / §13 matrix rows + handoff §3.3 follow-up). The four Phase-2 engine.* catalog entries were authored in 2d but never reached: `translate_generic` discarded the engine message and returned a vague catalog entry. Fix: pattern-match the engine message text for the four Phase-2 categories (aggregate misuse, group-by required, compound arity mismatch fallback, scalar-subquery cardinality) inside `translate_generic`, routing each to its engine-neutral catalog entry. 3. Matrix-coverage tests. Thirteen new tests covering the rows that had no explicit coverage: - 3 SQL keyword/operator/CASE highlight tests - 4 engine.* engine-message tests - 3 sql_expr column-completion tests (WHERE, HAVING) - 3 predicate-warning slot tests (CASE, ORDER BY, projection) - 1 all-10-playground-types recovery test (tests/sql_select.rs) Plan document (docs/plans/20260520-adr-0032-phase-2.md) updated: every (TBD) row in the cross-cut matrix replaced with a concrete test file::function reference and a green status marker. Test totals: 1428 → 1441 passing (+13 new). Clippy clean.
This commit is contained in:
+45
-21
@@ -67,28 +67,39 @@ pub fn render_input_runs(
|
||||
theme: &Theme,
|
||||
cache: &crate::completion::SchemaCache,
|
||||
) -> Vec<StyledRun> {
|
||||
let mut runs = lex_to_runs(input, theme);
|
||||
// `render_input_runs` is invoked from `ui.rs` only when the
|
||||
// effective mode is plain `Simple` (advanced rendering uses
|
||||
// `plain_input_spans`), so the classification must use the
|
||||
// simple-mode walker view (ADR-0030 §2): a SQL form here
|
||||
// surfaces as a definite error overlay, consistent with the
|
||||
// dispatch path's "this is SQL" hint on submit.
|
||||
render_input_runs_in_mode(input, cursor_byte, theme, cache, Mode::Simple)
|
||||
}
|
||||
|
||||
/// Mode-aware [`render_input_runs`] (ADR-0030 §8).
|
||||
///
|
||||
/// Advanced mode runs the highlight walker with `Mode::Advanced`
|
||||
/// so SQL keywords get matched and coloured, and the
|
||||
/// definite-error / schema-existence overlays use the
|
||||
/// advanced-mode parse view.
|
||||
#[must_use]
|
||||
pub fn render_input_runs_in_mode(
|
||||
input: &str,
|
||||
cursor_byte: usize,
|
||||
theme: &Theme,
|
||||
cache: &crate::completion::SchemaCache,
|
||||
mode: Mode,
|
||||
) -> Vec<StyledRun> {
|
||||
let mut runs = lex_to_runs_in_mode(input, theme, mode);
|
||||
if let InputState::DefiniteErrorAt(pos) =
|
||||
classify_parse_result(parse_command_with_schema_in_mode(input, cache, Mode::Simple))
|
||||
classify_parse_result(parse_command_with_schema_in_mode(input, cache, mode))
|
||||
{
|
||||
overlay_error(&mut runs, pos, theme);
|
||||
}
|
||||
if let Some(inv) = crate::completion::invalid_ident_at_cursor(input, cursor_byte, cache) {
|
||||
overlay_error(&mut runs, inv.range.0, theme);
|
||||
}
|
||||
// Schema-aware diagnostics (ADR-0027 §2): an unknown table
|
||||
// or column (ERROR), or a dubious comparison (WARNING), is
|
||||
// overlaid wherever it sits in the input — not only under
|
||||
// the cursor, so a problem the user has typed past stays
|
||||
// visible. `input_diagnostics` is empty on a parse failure,
|
||||
// so this never fights the definite-error overlay above.
|
||||
for diag in walker::input_diagnostics(input, Some(cache)) {
|
||||
// Schema-aware diagnostics (ADR-0027 §2): unknown table /
|
||||
// column (ERROR), or a dubious comparison (WARNING), is
|
||||
// overlaid wherever it sits — not only under the cursor —
|
||||
// so a problem the user has typed past stays visible. The
|
||||
// mode-aware walk picks up the SQL-specific diagnostics from
|
||||
// ADR-0032 in advanced mode.
|
||||
for diag in walker::input_diagnostics_in_mode(input, Some(cache), mode) {
|
||||
let colour = match diag.severity {
|
||||
walker::Severity::Error => theme.tok_error,
|
||||
walker::Severity::Warning => theme.warning,
|
||||
@@ -503,15 +514,28 @@ fn overlay_span(runs: &mut [StyledRun], span: (usize, usize), colour: Color) {
|
||||
/// no cursor to show.
|
||||
#[must_use]
|
||||
pub fn lex_to_runs(input: &str, theme: &Theme) -> Vec<StyledRun> {
|
||||
base_runs(input, theme)
|
||||
lex_to_runs_in_mode(input, theme, Mode::Simple)
|
||||
}
|
||||
|
||||
fn base_runs(input: &str, theme: &Theme) -> Vec<StyledRun> {
|
||||
/// Mode-aware [`lex_to_runs`]. Advanced mode runs the walker
|
||||
/// with `Mode::Advanced` so SQL keywords past the entry word
|
||||
/// match and get highlighted (ADR-0030 §8).
|
||||
#[must_use]
|
||||
pub fn lex_to_runs_in_mode(
|
||||
input: &str,
|
||||
theme: &Theme,
|
||||
mode: Mode,
|
||||
) -> Vec<StyledRun> {
|
||||
base_runs(input, theme, mode)
|
||||
}
|
||||
|
||||
fn base_runs(input: &str, theme: &Theme, mode: Mode) -> Vec<StyledRun> {
|
||||
// Walker-driven highlighting (ADR-0024 §architecture, Phase F).
|
||||
// `walker::highlight_runs` returns per-byte classes for every
|
||||
// token shape in the source; whitespace gaps are not represented
|
||||
// and we fill them with the default foreground colour below.
|
||||
let classes = walker::highlight_runs(input);
|
||||
// `walker::highlight_runs_in_mode` returns per-byte classes for
|
||||
// every token shape in the source; whitespace gaps are not
|
||||
// represented and we fill them with the default foreground
|
||||
// colour below.
|
||||
let classes = walker::highlight_runs_in_mode(input, mode);
|
||||
let mut runs = Vec::with_capacity(classes.len() * 2);
|
||||
let mut pos = 0;
|
||||
for class in classes {
|
||||
|
||||
Reference in New Issue
Block a user