DSL module for Minga user configuration.
Used in ~/.config/minga/config.exs (or $XDG_CONFIG_HOME/minga/config.exs)
to declare editor options, custom keybindings, and commands. The config
file is real Elixir code evaluated at startup.
Example config file
use Minga.Config
# Options
set :tab_width, 4
set :line_numbers, :relative
set :scroll_margin, 8
# Custom keybindings
bind :normal, "SPC g s", :git_status, "Git status"
# Custom commands
command :git_status, "Show git status" do
{output, _} = System.cmd("git", ["status", "--short"])
Minga.API.message(output)
end
# Command advice (skip formatting if buffer has errors)
advise :around, :format_buffer, fn execute, state ->
if error_free?(state), do: execute.(state), else: state
endAvailable options
See Minga.Config.Options for the full list of supported options.
Summary
Functions
Injects the config DSL into the calling module or script.
Wraps an existing command with advice.
Binds a key sequence to a command in the given mode.
Binds a key sequence to a command with options.
Defines a custom command and registers it in the command registry.
Returns the path to the user's config file (~/.config/minga/config.exs).
Declares an extension to load.
Returns the registered option schema for an extension, or nil.
Completion items for filetype names.
Sets per-filetype option overrides.
Reads a config option value.
Reads an extension option value.
Reads an extension option, merging per-filetype overrides when present.
Reads a config option, merging per-filetype overrides when present.
Declares filetype-scoped keybindings.
Returns the error from the last config load, or nil if it loaded cleanly.
Registers a lifecycle hook for an editor event.
Completion items for :set option names.
Completion items for values of a specific option.
Declares a popup rule for a buffer name pattern.
Registers a custom command (called by the command/3 macro).
Registers an extension's option schema and applies user config.
Re-evaluates the user's config file. Returns :ok or {:error, reason}.
Sets an editor option.
Sets an extension option at runtime.
Sets an extension option, returning {:ok, value} or {:error, message}.
Sets an extension option override for a specific filetype.
Sets an option, returning {:ok, value} or {:error, message}.
Returns the set of all recognized option names.
Validates an option name/value pair without storing it.
Wraps a command function with any registered before/after/around/override advice.
Types
@type option_name() :: Minga.Config.Options.option_name()
@type type_descriptor() :: Minga.Config.Options.type_descriptor()
Functions
Injects the config DSL into the calling module or script.
Imports Minga.Config so that set/2, bind/4, and command/3 are
available without qualification.
@spec advise(Minga.Config.Advice.phase(), atom(), function()) :: :ok
Wraps an existing command with advice.
Four phases are supported, matching Emacs's advice system:
:before—fn state -> state end— transforms state before the command:after—fn state -> state end— transforms state after the command:around—fn execute, state -> state end— receives the original command function; full control over whether and how it runs:override—fn state -> state end— completely replaces the command
Multiple advice functions for the same phase and command run in
registration order. For :around, they nest outward (first registered
is outermost). Crashes in advice are logged but don't affect the editor.
Examples
# Run before save
advise :before, :save, fn state ->
state
end
# Conditionally skip formatting
advise :around, :format_buffer, fn execute, state ->
if state.diagnostics_count == 0 do
execute.(state)
else
# In production, this state is the Editor's internal state.
# The advice callback can modify it to show a status message.
%{state | status_msg: "Skipping format: has errors"}
end
end
# Replace a command entirely
advise :override, :save, fn state ->
my_custom_save(state)
end
Binds a key sequence to a command in the given mode.
Supports all vim modes: :normal, :insert, :visual,
:operator_pending, :command. For scope-specific bindings, pass a
{scope, vim_state} tuple (e.g., {:agent, :normal}).
For normal mode, leader sequences (starting with SPC) are added to
the leader trie. Single-key bindings override defaults.
Invalid key sequences log a warning but don't crash.
Examples
bind :normal, "SPC g s", :git_status, "Git status"
bind :insert, "C-j", :next_line, "Next line"
bind :visual, "SPC x", :custom_delete, "Custom delete"
bind {:agent, :normal}, "y", :my_agent_copy, "Custom copy"
Binds a key sequence to a command with options.
Supports the filetype: option for filetype-scoped bindings under
the SPC m leader prefix.
Examples
bind :normal, "SPC m t", :mix_test, "Run tests", filetype: :elixir
bind :normal, "SPC m p", :markdown_preview, "Preview", filetype: :markdown
Defines a custom command and registers it in the command registry.
The block runs inside a supervised Task, so crashes don't take down the editor. Errors are shown in the status bar.
Examples
command :count_lines, "Count buffer lines" do
count = Minga.API.line_count()
Minga.API.message("Lines: #{count}")
end
@spec config_path() :: String.t()
Returns the path to the user's config file (~/.config/minga/config.exs).
Declares an extension to load.
Exactly one source must be provided: path:, git:, or hex:.
Extra keyword options (beyond the source and its options) are passed
to the extension's init/1 callback as config.
Path source (local development)
extension :my_tool, path: "~/code/minga_my_tool"
extension :greeter, path: "~/code/greeter", greeting: "howdy"Git source (bleeding-edge or private)
extension :snippets, git: "https://github.com/user/minga_snippets"
extension :snippets, git: "https://github.com/user/minga_snippets", branch: "main"
extension :snippets, git: "git@github.com:user/minga_snippets.git", ref: "v1.0.0"Hex source (stable, published)
extension :snippets, hex: "minga_snippets", version: "~> 0.3"
extension :snippets, hex: "minga_snippets"
@spec extension_schema(atom()) :: [Minga.Extension.option_spec()] | nil
Returns the registered option schema for an extension, or nil.
@spec filetype_completions() :: [map()]
Completion items for filetype names.
Sets per-filetype option overrides.
When a buffer of the given filetype is active, these values override the global defaults.
Examples
for_filetype :go, tab_width: 8
for_filetype :python, tab_width: 4
for_filetype :elixir, tab_width: 2, autopair: true
@spec get(Minga.Config.Options.option_name()) :: term()
Reads a config option value.
Examples
Config.get(:tab_width) #=> 2
Config.get(:theme) #=> :doom_one
Reads an extension option value.
Examples
Config.get_extension_option(:minga_org, :conceal) #=> true
Reads an extension option, merging per-filetype overrides when present.
@spec get_for_filetype(Minga.Config.Options.option_name(), atom() | nil) :: term()
Reads a config option, merging per-filetype overrides when present.
Returns the filetype-specific value if one was set via for_filetype/2,
otherwise falls back to the global value.
Declares filetype-scoped keybindings.
Bindings declared inside the block are scoped to the given filetype
and appear under the SPC m leader prefix. This is the primary way
to define language-specific key bindings.
Examples
keymap :elixir do
bind :normal, "SPC m t", :mix_test, "Run tests"
bind :normal, "SPC m f", :mix_format, "Format with mix"
end
keymap :markdown do
bind :normal, "SPC m p", :markdown_preview, "Preview"
end
@spec load_error() :: term() | nil
Returns the error from the last config load, or nil if it loaded cleanly.
@spec on(Minga.Config.Hooks.event(), function()) :: :ok
Registers a lifecycle hook for an editor event.
Hooks run asynchronously under a TaskSupervisor, so they won't block editing. Crashes are logged but don't affect the editor.
Supported events
:after_save— receives(buffer_pid, file_path):after_open— receives(buffer_pid, file_path):on_mode_change— receives(old_mode, new_mode)
Examples
on :after_save, fn _buf, path ->
System.cmd("mix", ["format", path])
end
@spec option_name_completions() :: [map()]
Completion items for :set option names.
@spec option_value_completions(Minga.Config.Options.option_name()) :: [map()]
Completion items for values of a specific option.
Declares a popup rule for a buffer name pattern.
When a buffer whose name matches pattern is opened, it will be
displayed according to the rule instead of replacing the current buffer.
Later registrations with the same pattern override earlier ones, so user
config overrides built-in defaults.
Split mode (default)
popup "*Warnings*", side: :bottom, size: {:percent, 30}, focus: false
popup "*compilation*", side: :bottom, size: {:percent, 25}, focus: false
popup ~r/\*grep/, side: :right, size: {:percent, 40}, focus: trueFloat mode
popup ~r/\*Help/, display: :float, width: {:percent, 60},
height: {:percent, 70}, border: :rounded, focus: true, auto_close: trueOptions
See Minga.Popup.Rule for the full list of supported options.
Registers a custom command (called by the command/3 macro).
Wraps the function in a Task under Minga.Eval.TaskSupervisor so that
crashes are isolated from the editor process.
@spec register_extension_schema(atom(), [Minga.Extension.option_spec()], keyword()) :: :ok | {:error, [String.t()]}
Registers an extension's option schema and applies user config.
Called by the extension supervisor when loading an extension.
@spec reload() :: :ok | {:error, term()}
Re-evaluates the user's config file. Returns :ok or {:error, reason}.
@spec set(Minga.Config.Options.option_name(), term()) :: :ok
Sets an editor option.
Validates the option name and value type, then stores the value in
Minga.Config.Options. Raises ArgumentError if the option name is
unknown or the value has the wrong type.
Examples
set :tab_width, 4
set :line_numbers, :relative
Sets an extension option at runtime.
Use this from commands, keybindings, or extension code to change an
extension option after load. Not usable in config.exs (the schema
isn't registered yet at config eval time; use the extension declaration
syntax instead).
Examples
set_extension_option :minga_org, :conceal, false
set_extension_option :minga_org, :heading_bullets, ["•", "◦"]
Sets an extension option, returning {:ok, value} or {:error, message}.
@spec set_extension_option_for_filetype(atom(), atom(), atom(), term()) :: {:ok, term()} | {:error, String.t()}
Sets an extension option override for a specific filetype.
@spec set_option(Minga.Config.Options.option_name(), term()) :: {:ok, term()} | {:error, String.t()}
Sets an option, returning {:ok, value} or {:error, message}.
Unlike set/2 (used in config.exs DSL which raises on error), this
returns the result tuple for callers that handle errors themselves.
@spec valid_option_names() :: [Minga.Config.Options.option_name()]
Returns the set of all recognized option names.
@spec validate_option(Minga.Config.Options.option_name(), term()) :: :ok | {:error, String.t()}
Validates an option name/value pair without storing it.
Wraps a command function with any registered before/after/around/override advice.
Returns a (state -> state) function that applies the full advice chain.