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

Maps filetypes to tree-sitter grammar names and locates highlight queries.

Filetypes (atoms from `Minga.Language.Filetype`) resolve to tree-sitter grammar names from the registered `%Minga.Language{}` definitions. The fallback grammar name comes from the language record itself, not a static in-module table. Highlight queries are loaded from `priv/queries/{language}/highlights.scm` with an optional user override in `~/.config/minga/queries/{language}/highlights.scm`.

# `language`

```elixir
@type language() :: String.t()
```

A tree-sitter language name.

# `dynamic_grammar_path`

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

Returns the expected path for a dynamically-loaded grammar shared library.

Path: `~/.config/minga/grammars/{name}.so` (or `.dylib` on macOS).

# `init_registry`

```elixir
@spec init_registry() :: :ok
```

Initializes the dynamic language registry ETS table.

Called once at application startup. The table stores runtime-registered filetype-to-grammar mappings from extensions. Lookups check this table first, then fall back to the grammar name on the registered `%Minga.Language{}` definition.

# `injection_query_path`

```elixir
@spec injection_query_path(language()) :: String.t() | nil
```

Returns the path to the injection query file for a language.

Checks user config dir first (`~/.config/minga/queries/{lang}/injections.scm`),
then falls back to `priv/queries/{lang}/injections.scm`.

Returns `nil` if no injection query file exists.

# `language_for_filetype`

```elixir
@spec language_for_filetype(atom()) :: {:ok, language()} | :unsupported
```

Returns the tree-sitter language name for a filetype atom.

Checks the dynamic registry (populated by extensions) first, then falls back to the grammar name on the registered `%Minga.Language{}` definition.

## Examples

    iex> Minga.Language.Grammar.language_for_filetype(:elixir)
    {:ok, "elixir"}

    iex> Minga.Language.Grammar.language_for_filetype(:typescript_react)
    {:ok, "tsx"}

    iex> Minga.Language.Grammar.language_for_filetype(:text)
    :unsupported

# `query_path`

```elixir
@spec query_path(language()) :: String.t() | nil
```

Returns the path to the highlight query file for a language.

Checks user config dir first (`~/.config/minga/queries/{lang}/highlights.scm`),
then falls back to `priv/queries/{lang}/highlights.scm`.

Returns `nil` if no query file exists.

# `read_injection_query`

```elixir
@spec read_injection_query(language()) ::
  {:ok, String.t()} | {:error, :no_query | File.posix()}
```

Reads the injection query content for a language.

Returns `{:ok, query_text}` or `{:error, reason}`.

# `read_query`

```elixir
@spec read_query(language()) :: {:ok, String.t()} | {:error, :no_query | File.posix()}
```

Reads the highlight query content for a language.

Returns `{:ok, query_text}` or `{:error, reason}`.

# `register_language`

```elixir
@spec register_language(atom(), String.t()) :: :ok
```

Registers a dynamic filetype-to-grammar mapping.

Extensions call this to make their grammar available for syntax highlighting. The mapping is checked before the registered-language fallback, so extensions can override bundled grammars.

## Examples

    Minga.Language.Grammar.register_language(:org, "org")
    Minga.Language.Grammar.register_language(:astro, "astro")

# `supported_languages`

```elixir
@spec supported_languages() :: %{required(atom()) =&gt; language()}
```

Returns the full filetype-to-grammar mapping, including dynamic registrations.

---

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