Packages
Terminal emulation and driver infrastructure for Raxol. ANSI parsing, screen buffers, command processing, cursor management, input handling, session management, and termbox2 NIF integration.
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