# `Erabi.Match`
[🔗](https://github.com/hattoriai/erabi/blob/v0.1.0/lib/erabi/match.ex#L1)

How a picker matches and ranks options as a person types, in Elixir.

The browser filters the options it has with the same rules, and the
same numbers (`test/fixtures/match.json` holds the two to the same
results), so this module says what a picker shows: `Erabi.Test` uses
it, and a search of your own can rank with it on the server.

The rules are Jumon's, whose palette ranks its commands so:

  * case, accents and the width of characters do not count: "cafe"
    finds "Café", "ｈｏｍｅ" finds "Home";
  * each word of the query must be found in the option, its letters in
    order (a subsequence): "nwiss" finds "New issue";
  * a letter scores more at the start of the label or of a word, and
    after the letter before it; letters far apart score less;
  * a word is found in the label first, then in the keywords, the hint
    and the group, each scoring less, and there only as letters next to
    each other;
  * a word of four letters or more that is not found may have one typo
    (a letter missing, added, changed, or two letters swapped) against
    the start of a word of the label or of a keyword: "isue" finds
    "Issues";
  * the label equal to the query, then a label that starts with it,
    rank first; a shorter label ranks before a longer one;
  * the option's `:priority` is added to its score.

# `result`

```elixir
@type result() :: %{score: integer(), positions: [non_neg_integer()]}
```

The score of an option, and the positions in its label to highlight.

# `fold`

```elixir
@spec fold(String.t()) :: String.t()
```

Folds a text for matching: decomposed (NFKD), without combining marks,
in lower case, character by character.

## Examples

    iex> Erabi.Match.fold("Café ＡＢ")
    "cafe ab"

# `rank`

```elixir
@spec rank([map()], String.t()) :: [{map(), result()}]
```

Ranks options for a query: those that match, best first, each with its
score and positions. Options with the same score keep their order. With
an empty query, every option, by `:priority`.

# `score`

```elixir
@spec score(map(), String.t()) :: result() | nil
```

The score of an option for a query, or `nil` when it does not match.
The positions are the characters of the label, by index, that the query
matched. An option is an `Erabi.Option`, or a map with `:label` (and
`:keywords`, `:hint`, `:group`, `:priority`).

## Examples

    iex> Erabi.Match.score(%{label: "New issue"}, "nis").positions
    [0, 4, 5]
    iex> Erabi.Match.score(%{label: "New issue"}, "xyz")
    nil

---

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