Documentation
¶
Overview ¶
Package sqlcomplete answers "what may stand where the caret is" for a ClickHouse buffer (ADR-0190).
It is built on one commitment, §SD1: a candidate is offered only from a source of truth — a registry, the grammar's own vocabulary, the parsed statement's names, or a catalog answer for the buffer's endpoint. Where none exists the engine offers nothing and says why. There is no "plausible" band below an "exact" one, and no ranking that quietly promotes a guess.
The three inputs ¶
- The *site* (github.com/stergiotis/boxer/public/db/clickhouse/dsl/nanopass/highlight.CaretSite), which answers every frame from the lex tier: the enclosing call, the argument ordinal, the literal being typed, the member access.
- The *vocabulary* (github.com/stergiotis/boxer/public/db/clickhouse/dsl/sqlvocab), which says what each argument position *is* — a component kind, a section, a tuple element of a sibling argument.
- The *providers*, wired by the host per buffer (ADR-0147 §SD7), which turn a domain into candidates. A provider that has not answered yet reports "not ready", which is not the same as "empty": the engine stays silent rather than claiming the domain has no members.
What the engine does not do ¶
It does not rank, it does not fuzzy-match, and it does not lex or parse. The match state is a case-sensitive prefix and equality test over the token the site reports, computed per frame; anything needing the tree arrives through Request.Scope a quiescence window later.
Index ¶
Constants ¶
const Sentinel = "__caret__"
Sentinel is the identifier a repair puts where the caret is.
It has to be something no buffer contains and something grammar1 accepts as an identifier wherever a partial token can sit — which rules out a comment marker or a punctuation glyph. The leading and trailing underscores are what keep it out of a user's own naming.
Variables ¶
var PackageProps = packageprops.Props{ WASMWASI: packageprops.WASMCompiles, WASMJS: packageprops.WASMCompiles, WASMFreestanding: packageprops.WASMCompiles, }
PackageProps records this package's curated properties (ADR-0080). Seeded by `boxer code analysis golang wasmsurvey props generate`; curate by hand. The same group's `props verify` reconciles it.
Functions ¶
func Repair ¶
Repair rewrites the caret's statement into something the parser accepts (ADR-0190 §SD3).
The repair is deterministic rather than heuristic, because the site already knows what is open: the token being completed is replaced by Sentinel, an unterminated literal is closed around it, and the brackets the walk reports unclosed get their closers.
Two attempts, in order:
- the tail after the caret is kept, which is what a caret moved back into a finished statement needs;
- the tail is cut, which is what a statement whose tail is itself unfinished needs — and then every bracket open AT the caret is closed, not only those the whole statement left open.
sentinelAt is where the sentinel starts in each attempt, so a consumer that finds several matches in a pathological buffer can pick the right one.
Types ¶
type Catalog ¶
type Catalog struct {
Databases ItemsFn
// Tables answers a named database's tables, views and table functions, or
// the buffer's default database when the argument is empty.
Tables ItemsOfFn
// Columns answers a table's columns, or the statement's own sources' when
// the argument is empty.
Columns ItemsOfFn
// ColumnType answers one column's type, for the typer. table may be
// empty, meaning the buffer's single source.
ColumnType func(table string, column string) (t chtype.Type, ok bool)
Functions ItemsFn
Settings ItemsFn
TypeNames ItemsFn
TimeZones ItemsFn
Dictionaries ItemsFn
DictionaryAttributes ItemsOfFn
Formats ItemsFn
// EnumValues answers a column's Enum members, derived from its type
// string (§SD12 B11).
EnumValues ItemsOfFn
}
Catalog is the endpoint-dependent half: what `system.*` answers for the buffer this engine serves. Routed per buffer because two buffers may point at different endpoints, and because ad-hoc datasets contribute tables no `system.tables` enumerates (ADR-0190 §SD12).
type Engine ¶
type Engine struct {
// Vocab is the host's function registry — what the rosters declare.
Vocab *sqlvocab.Registry
// Builtins is the curated ClickHouse table; nil means [sqlvocab.Builtins].
Builtins []sqlvocab.Function
// Providers resolve a domain to candidates.
Providers Providers
// Typer answers the type-dependent domains; nil means one is built on
// first use over Providers.
Typer *Typer
// NamedTupleAccess reports that the buffer's pipeline accepts `expr.name`
// on a named tuple (ADR-0190 §SD11). Until it does, offering the fields of
// a call receiver would offer a spelling that does not parse, so §SD7 gates
// that one receiver on this.
NamedTupleAccess bool
// contains filtered or unexported fields
}
Engine answers completion requests for one buffer.
Render-thread-only, like the typer it owns: the memo is unsynchronised and each buffer has its own engine.
func (*Engine) Complete ¶
Complete answers one request.
The resolution order is member access, then the innermost call frame whose signature is known, then the clause. It stops at the first that answers: an argument position's domain is what belongs there, and a clause rule that overrode it would be the coarse answer ADR-0190 was written to replace.
type Finding ¶
type Finding struct {
// Range is the literal's content, quotes excluded — what a tint covers.
Range highlight.Range
// Text is the content.
Text string
// Domain is the domain the position declares.
Domain sqlvocab.Domain
// Resolved is true when the domain has a member equal to Text.
Resolved bool
// Callee is the enclosing call, for a message.
Callee string
}
Finding is one literal and what the engine could say about it.
type Item ¶
type Item struct {
// Text is the candidate's identity — the value, unquoted: `SysMem`,
// `TotalBytes`, `system.parts`. It is what a match compares against and
// what the pane's first column shows.
Text string
// Insert is the spelling that names it at the caret's position. It equals
// Text inside a string literal, and carries the quotes when the position
// takes a literal and none has been opened. Filled by the engine, not by
// the provider, because only the engine knows where the caret is.
Insert string
Kind ItemKindE
// Type is the candidate's ClickHouse type where it has one — a component
// field, a column. Empty otherwise.
Type string
// Doc is one line, for the pane's last column.
Doc string
// Source names the provider, so a row can say where it came from (§SD1's
// provenance requirement).
Source string
// Marks are the provisioning marks the Vocabulary tab shows — `✓`,
// `MISSING`, a dependency note. Carried through rather than filtered on:
// hiding a MISSING function would hide the provisioning fact (§SD8).
Marks []string
}
Item is one candidate.
type ItemKindE ¶
type ItemKindE uint8
ItemKindE says what a candidate is, for the pane's kind column and for an embedder choosing an icon. It is presentation, not semantics: the domain the candidate came from is what says where it is valid.
const ( ItemUnspecified ItemKindE = iota ItemComponentKind ItemField ItemTable ItemDatabase ItemColumn ItemFunction ItemKeyword ItemSection ItemMembership ItemChannel ItemSupportRole ItemAspect ItemCanonicalType ItemGloss ItemGlossKey ItemIdentityTag ItemTypeName ItemTimeZone ItemSetting ItemDictionary ItemFormat ItemAlias ItemEnumValue ItemParam )
type ItemsFn ¶
ItemsFn answers a closed domain. ready=false means "not known yet" — an ADR-0147 §SD6 probe that has not come back — and is deliberately distinct from an empty answer, which is a claim that the domain has no members. The engine says nothing either way, but says a different why (§SD1, and ADR-0174's `?`-never-`MISSING` rule).
type MatchE ¶
type MatchE uint8
MatchE is the state of the token under the caret against the candidates.
type Providers ¶
type Providers struct {
ComponentKinds ItemsFn
// ComponentType answers the whole named Tuple a kind projects.
//
// A type rather than a list of rows, because that is what composes: the
// typer needs the element's own type for
// `tupleElement(tupleElement(LW_COMPONENT(k),'a'),'b')`, and the field
// list falls out of the type. A provider keyed on a kind and answering
// rows would serve the LW_COMPONENT spelling and nothing else.
ComponentType func(kind string) (t chtype.Type, ok bool)
IntrospectionTables ItemsFn
Sections ItemsFn
SectionColumns ItemsOfFn
ExtractionTokens ItemsOfFn
Memberships ItemsFn
Channels ItemsFn
SupportRoles ItemsFn
Aspects ItemsFn
CanonicalTypes ItemsFn
Glosses ItemsFn
GlossKeys ItemsOfFn
IdentityTags ItemsFn
StatementParams ItemsFn
// Expressions answers a free expression position — the columns of the
// statement's single source, the functions the endpoint has, the names
// this build's vocabulary declares. Its argument is that source, qualified,
// or empty when the statement has none or more than one.
//
// It exists because "any expression" is not one catalogue: a column and a
// function are both valid at a SELECT position, and a provider returning
// only one of them would be exactly as wrong as returning neither.
Expressions ItemsOfFn
// Catalog is the server's own vocabulary for this buffer's endpoint —
// every entry an ADR-0147 §SD6 probe. Empty until M2.
Catalog Catalog
}
Providers is the host's wiring, per buffer (ADR-0147 §SD7). A nil field is a domain this host cannot resolve; the engine reports that rather than offering nothing without a reason.
type Request ¶
type Request struct {
// Site is the per-frame answer from the lex tier.
Site highlight.CaretSite
// Scope is the sentinel parse's answer, nil until it arrives.
Scope *Scope
// Statement is the buffer the site's ranges index.
Statement string
// Caret is the caret's byte offset into Statement.
Caret int
}
Request is one caret's question.
type Result ¶
type Result struct {
// Domain is the argument domain the engine resolved, zero when it
// resolved none.
Domain sqlvocab.Domain
// Items are the candidates, in the provider's own order.
Items []Item
// Partial is the byte range in Statement a completion replaces.
Partial highlight.Range
// Match is the state of what was typed against Items.
Match MatchE
// Exact is the index in Items of the candidate equal to the token's whole
// text, or -1.
Exact int
// Prefix are the indices of the candidates extending the typed text — all
// of them when nothing has been typed.
Prefix []int
// Silent says why there is nothing to offer, for the pane to show instead
// of an empty table. Empty when Items is non-empty.
//
// Every path that offers nothing sets it: ADR-0190 §SD1 commits to silence
// over guessing, and a silence with no reason is indistinguishable from a
// bug.
Silent string
// Callee is the enclosing call the domain came from, for the pane's
// heading. Empty when the domain came from the clause or a member access.
Callee string
// Ordinal is the argument position within Callee, or -1.
Ordinal int
}
Result is what the pane and the editor tint render.
func (Result) TabCompletion ¶
TabCompletion is what one captured Tab inserts (ADR-0190 §SD10): the suffix of the unique prefix match, or — when several match — the longest common prefix beyond what has been typed.
Shell-style, deliberately. A list with several candidates is not a menu here: the pane already shows them, so the key's job is to type the part they agree on and leave the choice visible. When they agree on nothing more, ok is false and the key inserts nothing, which is what a shell does too.
typed is what precedes the caret; the caller must have checked that the caret is at the token's end (a suffix insert is only valid there).
type Scope ¶
type Scope struct {
// Frame is the tree's own view of the caret's call. For a comma-separated
// call it must agree with the site's; for a keyword-syntax call
// (`CAST(x AS T)`) it is the only one there is.
Frame *highlight.CallFrame
// Aliases maps an alias to the source text of the expression it names, so
// the typer can recurse into it.
Aliases map[string]string
CTEs []string
Tables []TableRef
Windows []string
// Clause is the clause the sentinel landed in, spelled as
// [highlight.CaretSite.Clause] spells it so the two tiers do not disagree
// about the same word.
Clause string
}
Scope is what the statement's own tree adds to the site: the names the statement itself introduces (ADR-0190 §SD3).
It arrives one quiescence window behind the buffer, from a sentinel parse on a worker, because the parser costs 5–18 ms while its DFA warms (ADR-0084). Everything the site alone can answer is answered per frame without it, so a nil Scope narrows what the engine knows rather than stopping it.
func ParseScope ¶
ParseScope repairs the statement and parses it, returning what the tree adds to the site.
The first attempt that parses wins. When neither does — a JOIN position, for one, where the grammar wants ON or USING — the error says so and the site alone stays the model, which is what §SD3 accepts.
type Typer ¶
type Typer struct {
// Providers is where the registry answers come from — the component
// registry, the column probe.
Providers *Providers
// Scope is the statement's alias map, nil until the scope tier answers.
Scope *Scope
// contains filtered or unexported fields
}
Typer maps an expression to a ClickHouse type when it can (ADR-0190 §SD5).
It is a closed list of shapes on purpose. Outside it the answer is *unknown*, and unknown yields nothing — a wrong element list read off a guessed type is exactly the failure §SD1 exists to prevent. The rungs below the list are the server (`DESCRIBE (SELECT …)`, M4), not a heuristic.
It works on the lex tier, not on a parse: the expression texts it sees are argument slices of a buffer being typed, and the parser costs 5–18 ms while its DFA warms (ADR-0084), which is not a per-frame budget. The shapes it recognises — a literal, a call with a literal argument, a cast — are syntactically shallow enough that lexing is the honest tool for them.
Render-thread-only: the memo is unsynchronised, and each buffer's engine has its own.