# `MingaEditor.CompletionHandling`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/completion_handling.ex#L1)

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.

# `active_config_context`

```elixir
@type active_config_context() :: :option_name | {:option_value, atom()} | :filetype
```

Config contexts that produce completion items (excludes :none).

# `config_context`

```elixir
@type config_context() :: :option_name | {:option_value, atom()} | :filetype | :none
```

Config completion context detected from cursor position.

# `accept`

```elixir
@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.

# `apply_processed`

```elixir
@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.

# `detect_config_context`

```elixir
@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.

# `dismiss`

```elixir
@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.

# `flush_resolve`

```elixir
@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}).

# `handle_resolve_response`

```elixir
@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.

# `handle_response`

```elixir
@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.

# `handle_signature_help_response`

```elixir
@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.

# `maybe_handle`

```elixir
@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.

# `maybe_resolve_selected`

```elixir
@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.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
