# `Minga.Config.Options`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/config/options.ex#L1)

Central registry for typed editor options.

Stores global option values and per-filetype overrides. Other modules
read options via `get/1` (global) or `get_for_filetype/2` (merged with
filetype overrides).

Backed by ETS with `read_concurrency: true` for lock-free reads on
every render frame and keystroke. The GenServer exists only to own
the ETS table lifecycle. Reads go directly to ETS; writes validate
and then insert directly (no GenServer round-trip needed since ETS
writes are atomic per-key).

## Supported options

| Option          | Type                                          | Default   |
|-----------------|-----------------------------------------------|-----------|
| `:tab_width`    | positive integer                               | `2`       |
| `:line_numbers` | `:hybrid`, `:absolute`, `:relative`, `:none`   | `:hybrid` |
| `:autopair`     | boolean                                        | `true`    |
| `:scroll_margin`| non-negative integer                           | `5`       |
| `:scroll_lines` | positive integer                               | `1`       |
| `:theme`        | theme name atom (see `Minga.Config.ThemeRegistry.available/0`) | `:doom_one`|
| `:indent_with`  | `:spaces` or `:tabs`                            | `:spaces`  |
| `:trim_trailing_whitespace` | boolean                             | `false`    |
| `:insert_final_newline`     | boolean                             | `false`    |
| `:format_on_save`           | boolean                             | `false`    |
| `:formatter`    | string or `nil`                                  | `nil`      |
| `:title_format` | string with `{placeholder}` tokens               | `"{filename} {dirty}({directory}) - Minga"` |
| `:recent_files_limit` | positive integer                            | `200`      |
| `:persist_recent_files` | boolean                                  | `true`     |
| `:wrap`                 | boolean                                    | `false`    |
| `:linebreak`            | boolean                                    | `true`     |
| `:breakindent`          | boolean                                    | `true`     |
| `:agent_tool_approval`  | `:destructive`, `:all`, or `:none`          | `:destructive` |
| `:agent_destructive_tools` | list of tool name strings                | `["write_file", "edit_file", "shell"]` |
| `:agent_panel_split`      | positive integer (30-80)                   | `65`       |
| `:startup_view`           | `:agent` or `:editor`                       | `:agent`   |
| `:agent_auto_context`     | boolean                                     | `true`     |
| `:font_family`            | string (font name)                          | `"Menlo"`   |
| `:font_size`              | positive integer (point size)               | `13`        |
| `:font_weight`            | `:thin` / `:light` / `:regular` / `:medium` / `:semibold` / `:bold` / `:heavy` / `:black` | `:regular` |
| `:font_ligatures`         | boolean                                     | `true`      |
| `:font_fallback`          | list of font family strings                 | `[]`        |
| `:prettify_symbols`       | boolean                                     | `false`     |
| `:whichkey_layout`        | `:bottom` or `:float`                       | `:bottom`   |
| `:cursorline`             | boolean                                        | `true`    |
| `:nav_flash`              | boolean                                        | `true`    |
| `:nav_flash_threshold`    | positive integer                               | `5`       |
| `:log_level`              | `:debug` / `:info` / `:warning` / `:error` / `:none` | `:info` |
| `:log_level_render`       | log level or `:default`                     | `:default`  |
| `:log_level_lsp`          | log level or `:default`                     | `:default`  |
| `:log_level_agent`        | log level or `:default`                     | `:default`  |
| `:log_level_editor`       | log level or `:default`                     | `:default`  |
| `:log_level_config`       | log level or `:default`                     | `:default`  |
| `:log_level_port`         | log level or `:default`                     | `:default`  |
| `:event_retention_days`   | positive integer (days to keep event log)    | `90`        |

Log level options control per-subsystem verbosity. Subsystem options
default to `:default` (inherit from `:log_level`). See `Minga.Log`
for the filtering API.

## Per-filetype overrides

Per-filetype settings override globals for buffers of that type:

    Minga.Config.Options.set_for_filetype(:go, :tab_width, 8)
    Minga.Config.Options.get_for_filetype(:tab_width, :go)
    #=> 8

## Example

    Minga.Config.Options.set(:tab_width, 4)
    Minga.Config.Options.get(:tab_width)
    #=> 4

# `line_number_style`

```elixir
@type line_number_style() :: :hybrid | :absolute | :relative | :none
```

Line number display style.

# `option_name`

```elixir
@type option_name() ::
  :editing_model
  | :space_leader
  | :tab_width
  | :line_numbers
  | :show_gutter_separator
  | :autopair
  | :scroll_margin
  | :scroll_lines
  | :theme
  | :indent_with
  | :indent_guides
  | :trim_trailing_whitespace
  | :insert_final_newline
  | :format_on_save
  | :formatter
  | :title_format
  | :recent_files_limit
  | :persist_recent_files
  | :clipboard
  | :wrap
  | :linebreak
  | :breakindent
  | :agent_provider
  | :agent_model
  | :agent_tool_approval
  | :agent_destructive_tools
  | :agent_tool_permissions
  | :agent_session_retention_days
  | :agent_panel_split
  | :startup_view
  | :agent_auto_context
  | :agent_max_tokens
  | :agent_max_retries
  | :agent_models
  | :agent_prompt_cache
  | :agent_notifications
  | :agent_notify_on
  | :agent_system_prompt
  | :agent_append_system_prompt
  | :agent_diff_size_threshold
  | :agent_max_turns
  | :agent_max_cost
  | :agent_api_base_url
  | :agent_api_endpoints
  | :agent_compaction_threshold
  | :agent_compaction_keep_recent
  | :agent_approval_timeout
  | :agent_subagent_timeout
  | :agent_mention_max_file_size
  | :agent_notify_debounce
  | :agent_diagnostic_feedback
  | :agent_flush_before_shell
  | :confirm_quit
  | :line_spacing
  | :font_family
  | :font_size
  | :font_weight
  | :font_ligatures
  | :font_fallback
  | :prettify_symbols
  | :whichkey_layout
  | :log_level
  | :log_level_render
  | :log_level_lsp
  | :log_level_agent
  | :log_level_editor
  | :cursorline
  | :nav_flash
  | :nav_flash_threshold
  | :log_level_config
  | :log_level_port
  | :parser_tree_ttl
  | :event_retention_days
  | :default_shell
```

Valid option names.

# `option_spec`

```elixir
@type option_spec() :: {option_name(), type_descriptor(), term()}
```

Option spec: `{name, type_descriptor, default_value}`.

# `table`

```elixir
@type table() :: :ets.table()
```

ETS table reference used for reads and writes.

# `type_descriptor`

```elixir
@type type_descriptor() ::
  :pos_integer
  | :non_neg_integer
  | :integer
  | :boolean
  | :atom
  | {:enum, [atom()]}
  | :theme_atom
  | :string
  | :string_or_nil
  | :string_list
  | :map_or_nil
  | :float_or_nil
  | :any
```

# `all`

```elixir
@spec all() :: %{required(option_name()) =&gt; term()}
```

Returns all current global option values as a map.

# `all`

```elixir
@spec all(GenServer.server()) :: %{required(option_name()) =&gt; term()}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `default`

```elixir
@spec default(option_name()) :: term()
```

Returns the default value for an option.

# `extension_option_description`

```elixir
@spec extension_option_description(atom(), atom()) :: String.t() | nil
```

Returns the description string for an extension option, or `nil` if
not found.

Used by `SPC h v` (describe option) and other introspection features.

# `extension_option_description`

```elixir
@spec extension_option_description(GenServer.server(), atom(), atom()) ::
  String.t() | nil
```

# `extension_schema`

```elixir
@spec extension_schema(atom()) :: [Minga.Extension.option_spec()] | nil
```

Returns the registered option schema for an extension, or `nil` if
the extension has no schema.

# `extension_schema`

```elixir
@spec extension_schema(GenServer.server(), atom()) ::
  [Minga.Extension.option_spec()] | nil
```

# `get`

```elixir
@spec get(option_name()) :: term()
```

Gets the current global value of an option, falling back to its default.

# `get`

```elixir
@spec get(GenServer.server(), option_name()) :: term()
```

# `get_extension_option`

```elixir
@spec get_extension_option(atom(), atom()) :: term()
```

Gets an extension option value, falling back to its registered default.

## Examples

    Config.Options.get_extension_option(:minga_org, :conceal)
    # => true

# `get_extension_option`

```elixir
@spec get_extension_option(GenServer.server(), atom(), atom()) :: term()
```

# `get_extension_option_for_filetype`

```elixir
@spec get_extension_option_for_filetype(atom(), atom(), atom() | nil) :: term()
```

Gets an extension option with filetype override applied.

Checks filetype-specific override first, then falls back to the
global extension option value.

# `get_extension_option_for_filetype`

```elixir
@spec get_extension_option_for_filetype(
  GenServer.server(),
  atom(),
  atom(),
  atom() | nil
) :: term()
```

# `get_for_filetype`

```elixir
@spec get_for_filetype(option_name(), atom() | nil) :: term()
```

Gets an option value with filetype override applied.

Checks filetype-specific settings first, then falls back to the global
value. If `filetype` is `nil`, returns the global value.

# `get_for_filetype`

```elixir
@spec get_for_filetype(GenServer.server(), option_name(), atom() | nil) :: term()
```

# `option_specs`

```elixir
@spec option_specs() :: [option_spec()]
```

Returns the full option spec list: `[{name, type, default}]`.

Used by `Config.Completion` to generate completion items with
type and default information in the detail text.

# `register_extension_schema`

```elixir
@spec register_extension_schema(atom(), [Minga.Extension.option_spec()], keyword()) ::
  :ok | {:error, String.t()}
```

Registers a typed option for use by an extension.

Registers a full option schema for an extension and validates user
config against it. Called by `Extension.Supervisor` at load time,
not by extensions directly.

Each spec in the schema is stored under `{:extension, ext_name, opt_name}`
in ETS, with type metadata under `{:extension_schema, ext_name}`.

User config values that match a schema entry are validated and stored.
Unknown keys produce a warning log. Type mismatches return an error.

# `register_extension_schema`

```elixir
@spec register_extension_schema(
  GenServer.server(),
  atom(),
  [Minga.Extension.option_spec()],
  keyword()
) :: :ok | {:error, String.t()}
```

# `reset`

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

Resets all options (global and per-filetype) to defaults.

# `reset`

```elixir
@spec reset(GenServer.server()) :: :ok
```

# `set`

```elixir
@spec set(option_name(), term()) :: {:ok, term()} | {:error, String.t()}
```

Sets a global option value after type validation.

Returns `{:ok, value}` on success or `{:error, reason}` if the option
name is unknown or the value has the wrong type.

# `set`

```elixir
@spec set(GenServer.server(), option_name(), term()) ::
  {:ok, term()} | {:error, String.t()}
```

# `set_extension_option`

```elixir
@spec set_extension_option(atom(), atom(), term()) ::
  {:ok, term()} | {:error, String.t()}
```

Sets an extension option value after type validation.

## Examples

    Config.Options.set_extension_option(:minga_org, :conceal, false)
    # => {:ok, false}

# `set_extension_option`

```elixir
@spec set_extension_option(GenServer.server(), atom(), atom(), term()) ::
  {:ok, term()} | {:error, String.t()}
```

# `set_extension_option_for_filetype`

```elixir
@spec set_extension_option_for_filetype(atom(), atom(), atom(), term()) ::
  {:ok, term()} | {:error, String.t()}
```

Sets an extension option override for a specific filetype.

The value is validated against the extension's registered schema.

## Examples

    Config.Options.set_extension_option_for_filetype(:minga_org, :org, :conceal, false)

# `set_extension_option_for_filetype`

```elixir
@spec set_extension_option_for_filetype(
  GenServer.server(),
  atom(),
  atom(),
  atom(),
  term()
) ::
  {:ok, term()} | {:error, String.t()}
```

# `set_for_filetype`

```elixir
@spec set_for_filetype(atom(), option_name(), term()) ::
  {:ok, term()} | {:error, String.t()}
```

Sets an option override for a specific filetype.

The value is validated the same way as global options.

# `set_for_filetype`

```elixir
@spec set_for_filetype(GenServer.server(), atom(), option_name(), term()) ::
  {:ok, term()} | {:error, String.t()}
```

# `start_link`

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

Starts the options registry and creates the backing ETS table.

# `type_for`

```elixir
@spec type_for(option_name()) :: type_descriptor() | nil
```

Returns the type descriptor for an option, or `nil` if unknown.

Used by `Config.Completion` to determine what value completions
to offer (enum variants, booleans, etc.).

# `valid_names`

```elixir
@spec valid_names() :: [option_name()]
```

Returns the list of valid option names.

# `validate_option`

```elixir
@spec validate_option(atom(), term()) :: :ok | {:error, String.t()}
```

Validates an option name and value against the type registry.

Returns `:ok` if valid, or `{:error, reason}` if the name is unknown
or the value has the wrong type. Used by `Buffer.Server.set_option/3`
to validate buffer-local option overrides.

---

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