anitnilay20 / anitnilay20/thoth

Seshat: context-ranked SQL autocomplete in the editor

Abierto
#121 0 comentarios 0 reacciones 0 asignados Ver en GitHub
feature future plugin:database priority:medium size:medium ux
Lenguaje dominante
Rust
Estrellas
70
Forks
5
Merge medio
10 h 33 min
PR fusionados (30 d)
2

Descripción

## Problem

The SQL editor's autocomplete is **prefix-only over one flat word set**. `editor_view` flattens table names into the syntax's `special` list ([editor.rs:151-157](plugins/seshat/src/ui/editor.rs#L151-L157)), and the SDK hands that straight to `egui_code_editor::Completer::new_with_syntax` ([code_editor/mod.rs:276](thoth-plugin-sdk/src/components/code_editor/mod.rs#L276)), which builds a single prefix trie over `keywords + types + special`.

Two consequences:
- **No context.** After `SELECT`, after `FROM`, after `o.`, or at statement start you get the same undifferentiated list, ranked only by prefix.
- **Columns aren't suggested at all** — only table names are fed in. The data exists (`TableNode.columns: Option>`, [state.rs:173](plugins/seshat/src/state.rs#L173)) but lazily (populated on describe).

## Goal

Context-aware, schema-aware completion that suggests the *right* subset based on the token before the caret — tables after `FROM`/`JOIN`, a table's columns after `alias.`, in-scope columns after `SELECT`/`WHERE`, keywords at statement start.

## Design sketch

### Context classifier (no SQL parser needed)
A lightweight backward scan from the caret, scoped to the current statement (reuse `crate::sql::statements`, [editor.rs:35](plugins/seshat/src/ui/editor.rs#L35)):

```
enum CompletionContext {
TableRef, // after FROM, JOIN, UPDATE, INTO → tables (+ schemas)
ColumnOf(String), // after `alias.` / `table.` → that table's columns
ColumnInScope, // after SELECT/WHERE/ON/,/AND/ORDER → columns of FROM tables + funcs
Keyword, // statement start / fallback → verbs + keywords
Suppress, // inside string / comment → nothing
}
```

### Alias resolution
~30-line token pass over the current statement's FROM/JOIN chain → `alias → table` map, so `o.` resolves to `orders`' columns. No full parser.

### Architecture (the key decision)
Do the ranking **host-side**, not plugin-side. Round-tripping text+caret to the WASM plugin on every keystroke is exactly what made the editor sluggish before. Instead:
- Plugin stops flattening into `special` and hands the host **structured, scoped schema** (a new `CompletionSchema { tables: [{ name, columns }], functions }` on `CodeEditor`).
- Host runs `classify` + ranking locally against egui's live caret — zero round-trip.

### The real cost
`egui_code_editor::Completer` is a fixed trie and can't express "show this subset now, that subset next keystroke." So context ranking means **bypassing its Completer with a small custom popup layer** (candidate list + prefix filter + kind icon + Tab/Enter accept — the Enter→Tab rewrite at [code_editor/mod.rs:299-311](thoth-plugin-sdk/src/components/code_editor/mod.rs#L299-L311) shows the shape). That popup (~200-300 lines in the SDK) is the bulk of the work; the classifier + alias map are cheap.

### Lazy columns
Columns load on describe. On the first `alias.` for a not-yet-described table, emit a describe request (reuse `Request::DescribeTable`) to prefetch; fall back to table names until they arrive — never block.

## Phasing

| Phase | Change | Effort | Payoff |
|---|---|---|---|
| **0** | Also feed loaded columns into `special` (one `.chain()` in editor.rs) | ~10 lines | Column completion works immediately (still context-free) |
| **1** | `CompletionSchema` on `CodeEditor` + host-side `classify` + custom popup | bulk | Context-scoped suggestions |
| **2** | Alias map + lazy column prefetch | moderate | `o.` → orders' columns |
| **3** | Kind icons, snippets (`SELECT * FROM`), keyword casing | small | Polish |

Phase 0 is worth doing regardless — quick win, and validates columns are available client-side before committing to the popup rebuild.

## Notes
- Keep the completer **lazy + scoped to the selected DB** — the earlier "loads everything → sluggish" regression is the guiding constraint.
- Standalone Seshat UX improvement; not part of the cross-plugin data ecosystem (#118) or the additional-data-source epic (#109).

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.