Skip to main content

Module completion

Module completion 

Source
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, the bynk-surface transparent types, and project type decls;
  • 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-in HttpResult/QueueResult), refined/opaque of/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 own fns + uses-imported stdlib/project combinators, gated on the uses set) (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§

Completion

Enums§

CompletionKind
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 empty constructors (v0.20b), and Effect.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 @cache handler-annotation arguments, offered at an argument-name position inside @cache( … ). maxAge is required (the freshness window); scope is optional (public/private, default private). The conditional ETag/304 half 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-Methods is 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 @limit handler-annotation arguments, offered at an argument-name position inside @limit( … ). Its one arg is maxBody, the request-body byte ceiling above which a 413 is 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. pub so tests/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> or ensures <name>: <cursor> — where the enclosing function’s parameters (and, for an ensures, result) are in scope. Returns Some(is_ensures); the parameters themselves are resolved handler-side from the enclosing fn (needs the cursor offset).
for_each_unit
Parse every project unit, plus the embedded first-party adapters (the bynk surface and the bynk.cloudflare platform adapter), and call f for each. Recovery parsing tolerates the in-progress edit at the cursor.
ident_ending_at
The identifier run ending at byte end in text(name, start) — the trim-back-to-a-non-identifier-boundary scan shared by every receiver/ identifier extraction in the LSP: value_receiver_rewrite above, symbols::receiver_segment_at (a member’s receiver, dot-preceded), and symbols::store_field_kind_at (a bare receiver’s own end offset, no dot). Each has different preconditions on what precedes end, 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). None if nothing identifier-shaped precedes end.
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 the cache annotation (@cache, not a bare cache( 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 by cors, 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 the limit annotation (@limit, not a bare limit( call), and the current argument segment has no : yet. Mirrors in_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 by limits, and the current field segment has no : yet. Mirrors in_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 by security, and the current field segment has no : yet. Mirrors in_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) — where cors may begin, alongside the on handler kinds. Gated on is_keyword_position so it only fires at a fresh item start, and on the enclosing brace’s header line naming service.
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 keywords registry, if present. pub so 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 of outer_variant on the scrutinee ty (the same shape as bynk-emit’s payload_field_ty): Result/Option/HttpResult generic args come straight off the Ty, and a user-declared sum’s field type is walked from source. Ok/Err inside Some(‸) on an Option[Result[…]] is the headline case.
store_field_member_candidates
#596: the entry ops (and, for a Map, the .entries/.keys/.values query accessors) of a bare store field receiver — merged onto value_member_candidates so a store field offers its whole vocabulary, not just the Query half kernel_methods::methods_for covers. A bare store Map field types (via the checker’s ADR 0120 “whole map as a value” reading) to plain Ty::Query, indistinguishable from an ordinary Query-typed local — so this reads the receiver’s provenance instead, the same way hover’s describe_store_op_at does. 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 — the is/match candidate set once the scrutinee’s type is known (resolved handler-side from expr_types). pub so the completion handler can offer them at an is position.
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 offset into text) sits just after a lowercase receiver.(partial) — a value receiver — return the buffer rewritten so the receiver is a complete expression (the trailing .partial dropped, so the file parses) and the byte offset of the receiver to type. Returns None for an uppercase name receiver (slice 2), a decimal 1., or a .-qualified segment.
variants_for_ty
v0.145 (ADR 0169, base gap for #565): the variants offerable for a scrutinee Ty at a pattern position. A user-declared sum’s variants come from source (sum_type_variants); the built-in Result/Option variants do not (they are not declared types, so sum_type_variants can’t see them) and are intrinsic here. This is why match-arm / is completion now fires for a Result/Option scrutinee, not only a user sum.