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:
@@ -655,25 +655,25 @@ fn render_input_panel(app: &App, theme: &Theme, frame: &mut Frame<'_>, area: Rec
|
||||
// inverted so the cursor is visible without enabling a real
|
||||
// terminal cursor.
|
||||
//
|
||||
// Simple-mode input gets per-token colouring (ADR-0022 §3)
|
||||
// via input_render::render_input_runs. Advanced-mode input
|
||||
// — DSL lexer doesn't speak SQL — renders plain (§12), with
|
||||
// the same before/under/after cursor shape we always had.
|
||||
// Per-token colouring (ADR-0022 §3 / ADR-0030 §8) in both
|
||||
// modes — `render_input_runs_in_mode` runs the highlight
|
||||
// walker with the active mode so SQL keywords / operators /
|
||||
// CASE / function calls colour correctly in Advanced mode.
|
||||
let cursor = app.input_cursor.min(app.input.len());
|
||||
let spans = match effective {
|
||||
EffectiveMode::Simple => {
|
||||
let runs = crate::input_render::render_input_runs(
|
||||
&app.input,
|
||||
cursor,
|
||||
theme,
|
||||
&app.schema_cache,
|
||||
);
|
||||
runs_to_spans(&app.input, &runs)
|
||||
}
|
||||
let mode_for_render = match effective {
|
||||
EffectiveMode::Simple => crate::mode::Mode::Simple,
|
||||
EffectiveMode::AdvancedPersistent | EffectiveMode::AdvancedOneShot => {
|
||||
plain_input_spans(&app.input, cursor, theme)
|
||||
crate::mode::Mode::Advanced
|
||||
}
|
||||
};
|
||||
let runs = crate::input_render::render_input_runs_in_mode(
|
||||
&app.input,
|
||||
cursor,
|
||||
theme,
|
||||
&app.schema_cache,
|
||||
mode_for_render,
|
||||
);
|
||||
let spans = runs_to_spans(&app.input, &runs);
|
||||
// ADR-0027 §4: the rightmost six columns of the input row
|
||||
// (a five-column label plus a one-column gap) are reserved
|
||||
// unconditionally, so the text area is always
|
||||
@@ -725,31 +725,6 @@ fn runs_to_spans<'a>(
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Plain (no token highlighting) input rendering for advanced
|
||||
/// mode. Same before/under/after cursor shape as the
|
||||
/// pre-ADR-0022 input panel; here as a deliberate fallback.
|
||||
fn plain_input_spans<'a>(input: &'a str, cursor: usize, theme: &Theme) -> Vec<Span<'a>> {
|
||||
let cursor = cursor.min(input.len());
|
||||
let before = &input[..cursor];
|
||||
let (under, after) = if cursor < input.len() {
|
||||
let mut end = cursor + 1;
|
||||
while end < input.len() && !input.is_char_boundary(end) {
|
||||
end += 1;
|
||||
}
|
||||
(&input[cursor..end], &input[end..])
|
||||
} else {
|
||||
(" ", "")
|
||||
};
|
||||
vec![
|
||||
Span::styled(before, Style::default().fg(theme.fg)),
|
||||
Span::styled(
|
||||
under,
|
||||
Style::default().fg(theme.fg).add_modifier(Modifier::REVERSED),
|
||||
),
|
||||
Span::styled(after, Style::default().fg(theme.fg)),
|
||||
]
|
||||
}
|
||||
|
||||
fn render_hint_panel(app: &App, theme: &Theme, frame: &mut Frame<'_>, area: Rect) {
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
|
||||
Reference in New Issue
Block a user