# `Minga.Language.Registry`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/language/registry.ex#L1)

Provides O(1) language catalog lookups for `%Minga.Language{}` definitions registered by config and extension-owned language packs.

Backed by ETS with `read_concurrency: true` for lock-free reads on every keystroke, render frame, and comment toggle. The GenServer exists only to own the ETS table lifecycle. All reads go directly to ETS.

## Lookup functions

- `get/1` — lookup by language name atom (e.g., `:elixir`)
- `for_extension/1` — lookup by file extension string (e.g., `"ex"`)
- `for_filename/1` — lookup by exact filename (e.g., `"Makefile"`)
- `for_shebang/1` — lookup by shebang interpreter (e.g., `"python3"`)

## Runtime registration

Extensions register languages via `register/2` with `{:extension, name}` as the source. Reload and unload paths remove the whole `%Minga.Language{}` record, so its names, extensions, filenames, shebangs, devicons, grammar metadata, formatter, and LSP defaults disappear together.

# `contribution_source`

```elixir
@type contribution_source() :: :builtin | :config | {:extension, atom()}
```

Source that contributed registry entries.

# `register_error`

```elixir
@type register_error() ::
  {:duplicate_key, term(), contribution_source(), contribution_source()}
```

# `all`

```elixir
@spec all() :: [Minga.Language.t()]
```

Returns all registered language definitions.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `for_extension`

```elixir
@spec for_extension(String.t()) :: Minga.Language.t() | nil
```

Returns the language definition for a file extension, or `nil`.

The extension should not include the leading dot and is matched
case-insensitively.

## Examples

    iex> lang = Minga.Language.Registry.for_extension("ex")
    iex> lang.name
    :elixir

# `for_filename`

```elixir
@spec for_filename(String.t()) :: Minga.Language.t() | nil
```

Returns the language definition for an exact filename, or `nil`.

## Examples

    iex> lang = Minga.Language.Registry.for_filename("Makefile")
    iex> lang.name
    :make

# `for_shebang`

```elixir
@spec for_shebang(String.t()) :: Minga.Language.t() | nil
```

Returns the language definition for a shebang interpreter, or `nil`.

## Examples

    iex> lang = Minga.Language.Registry.for_shebang("python3")
    iex> lang.name
    :python

# `get`

```elixir
@spec get(atom()) :: Minga.Language.t() | nil
```

Returns the language definition for a name atom, or `nil` if unknown.

## Examples

    iex> lang = Minga.Language.Registry.get(:elixir)
    iex> lang.label
    "Elixir"

    iex> Minga.Language.Registry.get(:unknown_language)
    nil

# `register`

```elixir
@spec register(Minga.Language.t()) :: :ok | {:error, register_error()}
```

Registers a config-owned language at runtime.

Rebuilds the extension, filename, and shebang index entries and records source ownership so reloads and extension unloads can remove contributed data as a group.

# `register`

```elixir
@spec register(Minga.Language.t(), contribution_source()) ::
  :ok | {:error, register_error()}
```

Registers a language with an explicit source.

# `source_for`

```elixir
@spec source_for(term()) :: contribution_source() | nil
```

Returns the contribution source for a registry key, or `nil` if the key is unknown.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Starts the language registry.

# `supported_names`

```elixir
@spec supported_names() :: [atom()]
```

Returns all language names that have definitions.

# `unregister_source`

```elixir
@spec unregister_source(contribution_source()) :: :ok
```

Removes every language and lookup index contributed by a source.

---

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