# `Minga.Editing.Completion.Item`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/editing/completion/item.ex#L1)

One completion candidate with stable provider and semantic edit identity.

The identifier is the full identity tuple, not a display label or truncated hash. Documentation is intentionally excluded because `completionItem/resolve` may add it without changing the candidate's identity. Detail remains part of the identity because providers commonly use it to distinguish overloads.

# `id`

```elixir
@type id() ::
  {provider_id(),
   {String.t(), String.t(), map() | nil, term(), term(), term(), String.t()}}
```

Stable identity of one provider-owned completion candidate.

# `kind`

```elixir
@type kind() ::
  :text
  | :method
  | :function
  | :constructor
  | :field
  | :variable
  | :class
  | :interface
  | :module
  | :property
  | :unit
  | :value
  | :enum
  | :keyword
  | :snippet
  | :color
  | :file
  | :reference
  | :folder
  | :enum_member
  | :constant
  | :struct
  | :event
  | :operator
  | :type_parameter
```

LSP CompletionItemKind as an atom.

# `match_range`

```elixir
@type match_range() :: {start :: non_neg_integer(), length :: pos_integer()}
```

A half-open match range expressed in Unicode codepoint offsets.

# `provider_id`

```elixir
@type provider_id() :: term()
```

Identity of the provider within one completion session.

# `t`

```elixir
@type t() :: %Minga.Editing.Completion.Item{
  detail: String.t(),
  documentation: String.t(),
  filter_text: String.t(),
  id: id(),
  insert_text: String.t(),
  kind: kind(),
  label: String.t(),
  match_ranges: [match_range()],
  preselect: boolean(),
  provider_id: provider_id(),
  raw: map() | nil,
  search: Minga.Editing.Completion.Item.Search.t(),
  sort_text: String.t(),
  source: String.t(),
  text_edit: text_edit() | nil
}
```

# `text_edit`

```elixir
@type text_edit() :: %{
  range: %{
    start_line: non_neg_integer(),
    start_col: non_neg_integer(),
    end_line: non_neg_integer(),
    end_col: non_neg_integer()
  },
  new_text: String.t()
}
```

A text edit to apply when accepting a completion.

# `compact_match_positions`

```elixir
@spec compact_match_positions([non_neg_integer()]) :: [match_range()]
```

Compacts sorted match positions into half-open ranges.

# `from_fields`

```elixir
@spec from_fields(provider_id(), map()) :: t()
```

Builds a non-LSP completion item from the same stable field contract.

# `from_lsp`

```elixir
@spec from_lsp(provider_id(), map()) :: t()
```

Parses one LSP CompletionItem and assigns its provider-qualified stable identity.

# `resolve`

```elixir
@spec resolve(t(), String.t()) :: t()
```

Returns this candidate with resolved documentation while preserving its identity.

# `semantic_key`

```elixir
@spec semantic_key(t()) :: id()
```

Returns the provider-aware semantic key used to collapse true duplicates.

# `wire_id`

```elixir
@spec wire_id(t() | id()) :: String.t()
```

Returns a compact stable identifier suitable for native protocol payloads.

# `with_match_ranges`

```elixir
@spec with_match_ranges(t(), [match_range()]) :: t()
```

Returns this candidate with at most 255 display-label match ranges for the wire snapshot.

# `with_normalized_match_ranges`

```elixir
@spec with_normalized_match_ranges(t(), [match_range()]) :: t()
```

Maps normalized filter-text ranges onto the displayed label, omitting non-mappable ranges.

---

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