fix(input): thread the : one-shot escape into live SQL feedback
The `:` one-shot escape (ADR-0003) is stripped at submission, but the *live* feedback kept the leading `:` in the buffer it handed the walker — so Tab completion, the validity verdict, and the highlight overlays all bailed at the `:` and treated the SQL as an unknown command. Effect: in `:`-mode, Tab completed nothing and a valid query could flash an error, while the identical line in full `mode advanced` worked. (The ambient hint already stripped it, which is why the hint showed the right column name while Tab did nothing.) Add `App::feedback_view()` — the `:`-stripped SQL view, the cursor mapped into it, and the stripped byte offset — and route all four live paths through it: - completion (Tab): complete against the view, then shift the returned `replaced_range` back by the offset so the edit lands in the buffer; - validity verdict: verdict the SQL, not the sigil; - highlight/overlays: new `render_input_runs_feedback` highlights and diagnoses the view (shifted by the offset) while the `:` renders as plain text; - ambient hint: consolidated onto `feedback_view`, replacing the duplicate local `strip_one_shot_prefix`.
This commit is contained in:
@@ -1438,12 +1438,19 @@ fn render_input_one_row(
|
||||
let offset = input_scroll_offset(line_cols, cursor_col, tw, app.input_scroll_offset);
|
||||
app.input_scroll_offset = offset;
|
||||
|
||||
let runs = crate::input_render::render_input_runs_in_mode(
|
||||
// Strip the `:` one-shot prefix for the SQL highlighting/overlays
|
||||
// (ADR-0003); the `:` itself renders as plain text. Identity for
|
||||
// non-one-shot input.
|
||||
let (fb_view, fb_cursor, fb_off) = app.feedback_view();
|
||||
let runs = crate::input_render::render_input_runs_feedback(
|
||||
&app.input,
|
||||
cursor,
|
||||
theme,
|
||||
&app.schema_cache,
|
||||
mode_for_render,
|
||||
fb_view,
|
||||
fb_cursor,
|
||||
fb_off,
|
||||
);
|
||||
let spans = runs_to_spans(&app.input, &runs);
|
||||
|
||||
@@ -1507,12 +1514,19 @@ fn render_input_two_rows(
|
||||
let offset = input_scroll_offset(line_cols, cursor_col, capacity, app.input_scroll_offset);
|
||||
app.input_scroll_offset = offset;
|
||||
|
||||
let runs = crate::input_render::render_input_runs_in_mode(
|
||||
// Strip the `:` one-shot prefix for the SQL highlighting/overlays
|
||||
// (ADR-0003); the `:` itself renders as plain text. Identity for
|
||||
// non-one-shot input.
|
||||
let (fb_view, fb_cursor, fb_off) = app.feedback_view();
|
||||
let runs = crate::input_render::render_input_runs_feedback(
|
||||
&app.input,
|
||||
cursor,
|
||||
theme,
|
||||
&app.schema_cache,
|
||||
mode_for_render,
|
||||
fb_view,
|
||||
fb_cursor,
|
||||
fb_off,
|
||||
);
|
||||
let cells = expand_runs_to_cells(&app.input, &runs);
|
||||
let len = cells.len();
|
||||
@@ -1621,23 +1635,6 @@ fn runs_to_spans<'a>(
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Strip a leading one-shot `:` sigil (and the whitespace after
|
||||
/// it) from `input`, returning the advanced command slice and the
|
||||
/// cursor remapped into it. Mirrors `App::submit`'s `:` handling
|
||||
/// so the hint panel hints at the command, not the sigil
|
||||
/// (ADR-0022 Amendment 1). Used only when the effective mode is
|
||||
/// `AdvancedOneShot`, where `input` is guaranteed to start (after
|
||||
/// any leading whitespace) with `:`.
|
||||
fn strip_one_shot_prefix(input: &str, cursor: usize) -> (&str, usize) {
|
||||
let lead_ws = input.len() - input.trim_start().len();
|
||||
let after_colon = lead_ws + 1; // skip the `:`
|
||||
let ws_after = input[after_colon..].len() - input[after_colon..].trim_start().len();
|
||||
let prefix_len = (after_colon + ws_after).min(input.len());
|
||||
let effective = &input[prefix_len..];
|
||||
let effective_cursor = cursor.saturating_sub(prefix_len).min(effective.len());
|
||||
(effective, effective_cursor)
|
||||
}
|
||||
|
||||
/// Resolve the Hint panel body into its rendered lines, pre-wrapped
|
||||
/// to the panel's inner width and clamped to `max_rows` with an
|
||||
/// ellipsis backstop (issue #12). `max_rows` is the geometry-fixed row
|
||||
@@ -1679,14 +1676,9 @@ fn resolve_hint_lines(
|
||||
|
||||
// In one-shot advanced mode (`:` prefix in simple mode) the
|
||||
// raw input carries the `:` sigil, which is not part of the
|
||||
// grammar. Strip it for the ambient computation so the hint
|
||||
// reflects the advanced command — mirroring `App::submit`.
|
||||
let (hint_input, hint_cursor) = match app.effective_mode() {
|
||||
EffectiveMode::AdvancedOneShot => {
|
||||
strip_one_shot_prefix(&app.input, app.input_cursor)
|
||||
}
|
||||
_ => (app.input.as_str(), app.input_cursor),
|
||||
};
|
||||
// grammar. The shared feedback view strips it so the hint reflects
|
||||
// the advanced command — mirroring `App::submit` (ADR-0003).
|
||||
let (hint_input, hint_cursor, _off) = app.feedback_view();
|
||||
let ambient = crate::input_render::ambient_hint_in_mode(
|
||||
hint_input,
|
||||
hint_cursor,
|
||||
|
||||
Reference in New Issue
Block a user