Completion accept, filter, trigger, and dismiss logic.
Handles both LSP completions (async, debounced) and config file
completions (synchronous, from the Options registry). Extracted
from MingaEditor to keep the GenServer module focused on
orchestration. All functions are pure state transforms.
Summary
Types
Config contexts that produce completion items (excludes :none).
Config completion context detected from cursor position.
Functions
Accepts the currently selected completion item.
Applies a completion result that was processed off the Editor in a Task.
Detects the config DSL context from a line of text and cursor position.
Dismisses the active completion popup and resets trigger state.
Sends the actual completionItem/resolve request after debounce.
Handles a completionItem/resolve response.
Handles an LSP completion response off the Editor hot path.
Handles a textDocument/signatureHelp response.
Updates or dismisses completion after a key press.
Triggers a completionItem/resolve request for the selected item.
Types
Functions
@spec accept(MingaEditor.State.t(), Minga.Editing.Completion.t()) :: MingaEditor.State.t()
Accepts the currently selected completion item.
Routes to insert-text or text-edit depending on the completion type, then dismisses the completion popup.
@spec apply_processed( MingaEditor.State.t(), non_neg_integer(), :primary | :merge, Minga.Editing.Completion.t() | [Minga.Editing.Completion.item()] | :failed, {non_neg_integer(), non_neg_integer()} ) :: MingaEditor.State.t()
Applies a completion result that was processed off the Editor in a Task.
Discards the result unless a completion modal is still open and it carries
the current request generation (gen). This latest-wins guard drops a stale
Task result from a request batch that was superseded by newer typing, so an
out-of-order or slow Task can never overwrite a fresher menu.
For a :primary result the Task already produced a fully sorted+filtered
Completion, so the common single-server path is a cheap assignment. If a
secondary server's :merge result happened to land first, the primary result
is unioned into it (rather than replacing it) so no server's items are lost.
A :failed payload (the Task crashed or could not start) clears a still-pending
menu so it is not left stuck, while leaving an already-populated menu intact.
@spec detect_config_context(String.t(), non_neg_integer()) :: config_context()
Detects the config DSL context from a line of text and cursor position.
Returns :option_name, {:option_value, atom()}, :filetype, or :none.
Used internally by config_completion_context/1 after determining the
buffer is a config file. Exposed for testing.
@spec dismiss(MingaEditor.State.t()) :: MingaEditor.State.t()
Dismisses the active completion popup and resets trigger state.
No-op when the active modal is something other than :completion — the
caller may invoke this on every non-insert keypress, so we mustn't
displace the picker / prompt / etc.
@spec flush_resolve(MingaEditor.State.t(), non_neg_integer()) :: MingaEditor.State.t()
Sends the actual completionItem/resolve request after debounce.
Called from MingaEditor.handle_info({:completion_resolve, index}).
@spec handle_resolve_response(MingaEditor.State.t(), {:ok, term()} | {:error, term()}) :: MingaEditor.State.t()
Handles a completionItem/resolve response.
Updates the selected completion item's documentation with the resolved content.
@spec handle_response(MingaEditor.State.t(), reference(), term()) :: MingaEditor.State.t()
Handles an LSP completion response off the Editor hot path.
Only the cheap bookkeeping runs on the Editor: CompletionTrigger.classify_response/4
matches the response ref against the pending request and decides whether it
is the primary response, a secondary one to merge, or stale. The expensive
work (parsing every item, sorting, and prefix-filtering) is then handed to a
Task under Minga.Eval.TaskSupervisor, which sends the processed result back
as {:completion_processed, gen, mode, payload, trigger_pos}. The Editor
applies that via apply_processed/5 with a cheap state assignment.
This keeps the Editor mailbox responsive even when a server returns 1000+ completion items.
@spec handle_signature_help_response( MingaEditor.State.t(), {:ok, term()} | {:error, term()} ) :: MingaEditor.State.t()
Handles a textDocument/signatureHelp response.
Creates a SignatureHelp struct from the response and stores it
in editor state. Returns state unchanged on error or empty response.
@spec maybe_handle( MingaEditor.State.t(), boolean(), non_neg_integer(), non_neg_integer() ) :: MingaEditor.State.t()
Updates or dismisses completion after a key press.
Called after every key in insert mode. If the mode changed away from insert, dismisses completion. Otherwise updates the filter prefix and possibly triggers new completion.
@spec maybe_resolve_selected(MingaEditor.State.t()) :: MingaEditor.State.t()
Triggers a completionItem/resolve request for the selected item.
Called when C-n/C-p moves the selection. Debounces to avoid flooding the server when navigating rapidly. Only triggers if the selected item doesn't already have documentation and the server supports resolve.