Packages
Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.
Current section
Files
Jump to
Current section
Files
lib/raxol/terminal/config/utils.ex
defmodule Raxol.Terminal.Config.Utils do
@moduledoc """
Utility functions for handling terminal configuration maps.
"""
@doc """
Deeply merges two maps.
Keys in the right map take precedence. If both values for a key are maps,
they are merged recursively.
"""
@spec deep_merge(map(), map()) :: map()
def deep_merge(left, right) when is_map(left) and is_map(right) do
Map.merge(left, right, fn
_key, left_value, right_value
when is_map(left_value) and is_map(right_value) ->
deep_merge(left_value, right_value)
_key, _left_value, right_value ->
right_value
end)
end
def deep_merge(_, right) when is_map(right), do: right
def deep_merge(_, _), do: %{}
@doc """
Converts a keyword list or map of potentially nested options into a nested map.
Handles flat keys like `theme: "light"` and nested paths represented
by lists like `[behavior: [scrollback: 100]]` within the keyword list.
"""
@spec opts_to_nested_map(Keyword.t() | map()) :: map()
def opts_to_nested_map(opts) when is_list(opts) or is_map(opts) do
Enum.reduce(opts, %{}, fn {key, value}, acc ->
nested_map = create_nested_map(key, value)
deep_merge(acc, nested_map)
end)
end
# Creates a potentially nested map from a single key-value pair.
# Key can be an atom or a list of atoms representing the path.
defp create_nested_map(key, value) when is_atom(key) do
%{key => value}
end
defp create_nested_map(path, value) when is_list(path) do
path_to_nested_map(path, value)
end
# Helper to build the nested map structure from a path list
defp path_to_nested_map([key], value) when is_atom(key) do
%{key => value}
end
defp path_to_nested_map([head | tail], value)
when is_atom(head) and is_list(tail) do
%{head => path_to_nested_map(tail, value)}
end
@doc """
Merges configuration options into an existing configuration map.
The `opts` are first converted into a nested map structure and then
deeply merged into the `current_config`.
"""
@spec merge_opts(map(), Keyword.t() | map()) :: map()
def merge_opts(current_config, opts) when is_map(current_config) do
nested_opts_map = opts_to_nested_map(opts)
deep_merge(current_config, nested_opts_map)
end
end