Expand description
Completion for the cursor, keyed off the line up to it.
The surface is the canonical cursor context × candidate-kind matrix fixed
by ADR 0093 (design/decisions/0093-completion-surface-contract.md), spec’d
at design/bynk-lsp-spec.md §3.15. complete dispatches the six contexts
it can serve purely (no analysis cache):
consumes <prefix>/consumes U { … }/given …— consumable units and in-scope capabilities (v0.17);- type position (
: T,-> T, inside[ … ]type args) — built-in types, thebynk-surface transparent types, and projecttypedecls; - keyword position (a bare word at a declaration/statement start) — the reserved keywords (with registry docs) and declaration snippets;
- name-receiver
UpperIdent.— sum variants (project + built-inHttpResult/QueueResult), refined/opaqueof/unsafe, capability ops, and built-in type statics (Int.parse/List.empty/Effect.pure/…); - expression position (after
=/(/,/=>/an operator) — the value constructors (Ok/Some/true/…), in-scope type names, and in-scope free functions (the current unit’s ownfns +uses-imported stdlib/project combinators, gated on theusesset) (ADR 0093 D3).
Two further contexts need the analysis overlay and so live handler-side
(main.rs): value-receiver lower. members (kernel methods + record
fields) and in-scope locals/params. They depend on the analysis overlay
(the boundary is ADR 0093 D4), but since slice 4 (ADR 0094) it is
error-tolerant: best-effort partial types are recorded even on a broken
buffer, so they no longer go silent on an unrelated error. Items also carry a
one-line detail eagerly; the richer documentation is filled in lazily by
completionItem/resolve, handler-side (slice 5).
Context detection is lexical (it must work mid-edit, when the buffer rarely
parses); candidates are semantic. Unit/type/capability/member enumeration
parses the project’s .bynk files (and the embedded bynk surface) with
recovery, so it works even while the file the cursor sits in is mid-edit.
Built-ins, keywords, and constructors come from the static bynkc registries
(keywords/builtin_names/firstparty/ast), never the index — first-party
symbols aren’t indexed (the v0.28 finding); the project parse supplies only
project symbols.
Structs§
Enums§
- Completion
Kind - What a candidate refers to — maps to an LSP
CompletionItemKind.
Constants§
- BUILTIN_
STATICS - Built-in type statics — real language statics that are not user-declared, so
they come from this small table rather than the project parse. Covers the
numeric parse statics and the JSON codec (v0.22, ADRs 0048/0049), the
collection
emptyconstructors (v0.20b), andEffect.pure(v0.5). The full real set per ADR 0093 D2 — kept complete and drift-tested (builtin_statics_are_reachable). - CACHE_
ARGS - v0.140 (ADR 0163): the
@cachehandler-annotation arguments, offered at an argument-name position inside@cache( … ).maxAgeis required (the freshness window);scopeis optional (public/private, defaultprivate). The conditionalETag/304half is automatic and has no surface. - CORS_
FIELDS - v0.131: the CORS policy fields, offered at a field-name position inside a
cors { }block.Allow-Methodsis deliberately absent (derived from the routes), so the closed set is these four. - LIMITS_
FIELDS - v0.142 (ADR 0165): the request-limits policy fields, offered at a field-name
position inside a
limits { }block. The closed set is this one. - LIMIT_
ARGS - v0.142 (ADR 0165): the
@limithandler-annotation arguments, offered at an argument-name position inside@limit( … ). Its one arg ismaxBody, the request-body byte ceiling above which a413is synthesised before the body is read. - SECURITY_
FIELDS - v0.141 (ADR 0164): the security-headers policy fields, offered at a field-name
position inside a
security { }block. The closed set is these two. - SNIPPETS
- Declaration snippets (
CompletionItemKind::SNIPPET), as LSP snippet bodies.pubsotests/scaffolds_compile.rs(ADR 0157) can enumerate them.
Functions§
- complete
- Produce completions for the cursor, given the text of the line up to the cursor, the current document text, and the project source root (if any).
- contract_
clause_ kind - v0.124 (slice 3): the cursor sits in a contract-clause predicate —
requires <name>: <cursor>orensures <name>: <cursor>— where the enclosing function’s parameters (and, for anensures,result) are in scope. ReturnsSome(is_ensures); the parameters themselves are resolved handler-side from the enclosingfn(needs the cursor offset). - for_
each_ unit - Parse every project unit, plus the embedded first-party adapters (the
bynksurface and thebynk.cloudflareplatform adapter), and callffor each. Recovery parsing tolerates the in-progress edit at the cursor. - ident_
ending_ at - The identifier run ending at byte
endintext—(name, start)— the trim-back-to-a-non-identifier-boundary scan shared by every receiver/ identifier extraction in the LSP:value_receiver_rewriteabove,symbols::receiver_segment_at(a member’s receiver, dot-preceded), andsymbols::store_field_kind_at(a bare receiver’s own end offset, no dot). Each has different preconditions on what precedesend, but the boundary scan itself — walk back to the nearest non-identifier char, respecting UTF-8 boundaries — is one definition, so it can’t drift between them (a review flagged the previous three near-identical copies).Noneif nothing identifier-shaped precedesend. - in_
cache_ arg_ position - v0.140 (ADR 0163): the cursor is at an argument-name position inside a
@cache( … )— the innermost open paren is opened by thecacheannotation (@cache, not a barecache(call), and the current argument segment (since the last,) has no:yet (a name position, not a value one). - in_
cors_ field_ position - v0.131: the cursor is at a field-name position inside a
cors { … }block — the innermost open brace is opened bycors, and the current field segment (since the last,or newline) has no:yet (a value position). - in_
limit_ arg_ position - v0.142 (ADR 0165): the cursor is at an argument-name position inside a
@limit( … )— the innermost open paren is opened by thelimitannotation (@limit, not a barelimit(call), and the current argument segment has no:yet. Mirrorsin_cache_arg_position. - in_
limits_ field_ position - v0.142 (ADR 0165): the cursor is at a field-name position inside a
limits { … }block — the innermost open brace is opened bylimits, and the current field segment has no:yet. Mirrorsin_security_field_position. - in_
security_ field_ position - v0.141: the cursor is at a field-name position inside a
security { … }block — the innermost open brace is opened bysecurity, and the current field segment has no:yet. Mirrorsin_cors_field_position. - in_
service_ body_ item_ position - v0.131: the cursor is at a service-body item start — a bare word inside a
service … {block (not a nested block) — wherecorsmay begin, alongside theonhandler kinds. Gated onis_keyword_positionso it only fires at a fresh item start, and on the enclosing brace’s header line namingservice. - is_
expression_ position - The cursor sits where a value expression is expected — after
=/(/,, a=>lambda arrow, or a binary operator — so in-scope locals are offered (v0.31, ADR 0064). Conservative: covers the common positions, excludes the type arrow->. (The handler also offers locals at keyword position.) - is_
keyword_ position - A bare word at a declaration/statement start: the line up to the cursor is
only leading whitespace plus an optional partial identifier (no operators,
colons, or brackets). Fires on an empty line too. Disjoint from
is_type_position(an internal helper), whose triggers (:/->/[) make this false. - keyword_
doc - The one-line doc for a name in the
keywordsregistry, if present.pubso hover’s bare-keyword fallback (ADR 0156) can reuse it — completion and hover render the same doc, never a parallel copy. - nested_
variant_ completions - v0.145 (ADR 0169, nested-variant completion for #565): the variants offerable
inside
OuterVariant(‸within a match arm — the payload field type’s variants. Resolves the single-field payload type ofouter_varianton the scrutineety(the same shape asbynk-emit’spayload_field_ty):Result/Option/HttpResultgeneric args come straight off theTy, and a user-declared sum’s field type is walked from source.Ok/ErrinsideSome(‸)on anOption[Result[…]]is the headline case. - store_
field_ member_ candidates - #596: the entry ops (and, for a
Map, the.entries/.keys/.valuesquery accessors) of a barestorefield receiver — merged ontovalue_member_candidatesso a store field offers its whole vocabulary, not just theQueryhalfkernel_methods::methods_forcovers. A bare storeMapfield types (via the checker’s ADR 0120 “whole map as a value” reading) to plainTy::Query, indistinguishable from an ordinaryQuery-typed local — so this reads the receiver’s provenance instead, the same way hover’sdescribe_store_op_atdoes. Empty when the receiver isn’t a store field of an enclosing agent, or is shadowed by a local. - sum_
type_ variants - v0.124 (slice 3): the variants of a project (or embedded-surface) sum type
named
name, as pattern completions — theis/matchcandidate set once the scrutinee’s type is known (resolved handler-side fromexpr_types).pubso the completion handler can offer them at anisposition. - value_
member_ candidates - The members of a typed value receiver: the built-in kernel methods of its type (from the enumerable registry) plus, for a record, its fields.
- value_
receiver_ rewrite - If the cursor (byte
offsetintotext) sits just after a lowercasereceiver.(partial) — a value receiver — return the buffer rewritten so the receiver is a complete expression (the trailing.partialdropped, so the file parses) and the byte offset of the receiver to type. ReturnsNonefor an uppercase name receiver (slice 2), a decimal1., or a.-qualified segment. - variants_
for_ ty - v0.145 (ADR 0169, base gap for #565): the variants offerable for a scrutinee
Tyat a pattern position. A user-declared sum’s variants come from source (sum_type_variants); the built-inResult/Optionvariants do not (they are not declared types, sosum_type_variantscan’t see them) and are intrinsic here. This is why match-arm /iscompletion now fires for aResult/Optionscrutinee, not only a user sum.