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
raxol_terminal lib raxol terminal config application.ex
Raw

lib/raxol/terminal/config/application.ex

defmodule Raxol.Terminal.Config.Application do
@moduledoc """
Terminal configuration application.
This module handles applying configuration settings to the terminal,
ensuring all changes are properly propagated throughout the system.
"""
alias Raxol.Terminal.Config.{Capabilities, Validation}
@doc """
Applies a configuration to the terminal.
This function takes a configuration and applies it to the current terminal
instance, updating the terminal state and behavior.
## Parameters
* `config` - The configuration to apply
* `terminal_pid` - The PID of the terminal process (optional)
## Returns
`{:ok, applied_config}` or `{:error, reason}`
"""
def apply_config(config, terminal_pid \\ nil) do
# Validate the configuration
case Validation.validate_config(config) do
{:ok, validated_config} ->
# Apply the configuration using private functions for each section
with :ok <- apply_display_config(validated_config, terminal_pid),
:ok <- apply_input_config(validated_config, terminal_pid),
:ok <- apply_rendering_config(validated_config, terminal_pid),
:ok <- apply_ansi_config(validated_config, terminal_pid),
:ok <- apply_behavior_config(validated_config, terminal_pid) do
{:ok, validated_config}
else
{:error, reason} -> {:error, reason}
end
error ->
error
end
end
@doc """
Applies a partial configuration update to the terminal.
This allows updating only specific parts of the configuration without
changing other settings.
## Parameters
* `partial_config` - The partial configuration to apply
* `terminal_pid` - The PID of the terminal process (optional)
## Returns
`{:ok, updated_config}` or `{:error, reason}`
"""
def apply_partial_config(partial_config, terminal_pid \\ nil) do
# Get the current configuration
current_config = get_current_config(terminal_pid)
# Merge the partial config with the current config
updated_config = deep_merge(current_config, partial_config)
# Apply the updated configuration
apply_config(updated_config, terminal_pid)
end
@doc """
Gets the current terminal configuration.
## Parameters
* `terminal_pid` - The PID of the terminal process (optional)
## Returns
The current terminal configuration.
"""
def get_current_config(terminal_pid \\ nil) do
# If terminal_pid is provided, get config from that process
# Otherwise, use the default terminal process
pid = terminal_pid || default_terminal_pid()
case pid do
# No terminal active
nil ->
%{}
pid when is_pid(pid) ->
# Try to get configuration from the terminal process
case get_config_from_terminal(pid) do
{:ok, config_map} ->
# Extract only the necessary parts
config_map
|> Map.take([:font_size, :font_family, :theme])
end
end
end
@doc """
Resets terminal configuration to default values.
## Parameters
* `terminal_pid` - The PID of the terminal process (optional)
* `optimize` - Whether to optimize for detected capabilities (default: true)
## Returns
`{:ok, default_config}` or `{:error, reason}`
"""
def reset_config(terminal_pid \\ nil, optimize \\ true) do
# Get default configuration
default_config = get_default_config(optimize)
# Apply the default configuration
apply_config(default_config, terminal_pid)
end
# Private functions
defp get_default_config(true) do
# Use capability-aware optimized default config
Capabilities.optimized_config()
end
defp get_default_config(false) do
# Use basic default config
Raxol.Terminal.Config.Defaults.generate_default_config()
end
# Apply display configuration
defp apply_display_config(%{display: display}, terminal_pid)
when is_map(display) or is_tuple(display) do
pid = terminal_pid || default_terminal_pid()
apply_display_config_to_pid(pid, display)
end
# No display config to apply
defp apply_display_config(_, _), do: :ok
defp apply_display_config_to_pid(nil, _display) do
# No terminal active
:ok
end
defp apply_display_config_to_pid(pid, display) do
# Extract relevant display settings
settings = %{
width: extract_width(display),
height: extract_height(display),
title: Map.get(display, :title),
colors: Map.get(display, :colors),
truecolor: Map.get(display, :truecolor),
unicode: Map.get(display, :unicode)
}
# Send configuration to terminal process
send_config_to_terminal(pid, {:display_config, settings})
end
defp extract_width(display) when is_map(display), do: Map.get(display, :width)
defp extract_width(display) when is_tuple(display), do: elem(display, 0)
defp extract_height(display) when is_map(display),
do: Map.get(display, :height)
defp extract_height(display) when is_tuple(display), do: elem(display, 1)
# Apply input configuration
defp apply_input_config(%{input: input}, terminal_pid) when is_map(input) do
pid = terminal_pid || default_terminal_pid()
apply_input_config_to_pid(pid, input)
end
# No input config to apply
defp apply_input_config(_, _), do: :ok
defp apply_input_config_to_pid(nil, _input) do
# No terminal active
:ok
end
defp apply_input_config_to_pid(pid, input) do
# Extract relevant input settings
settings = %{
mouse: Map.get(input, :mouse),
keyboard: Map.get(input, :keyboard),
escape_timeout: Map.get(input, :escape_timeout),
clipboard: Map.get(input, :clipboard)
}
# Send configuration to terminal process
send_config_to_terminal(pid, {:input_config, settings})
end
# Apply rendering configuration
defp apply_rendering_config(%{rendering: rendering}, terminal_pid)
when is_map(rendering) do
pid = terminal_pid || default_terminal_pid()
apply_rendering_config_to_pid(pid, rendering)
end
# No rendering config to apply
defp apply_rendering_config(_, _), do: :ok
defp apply_rendering_config_to_pid(nil, _rendering) do
# No terminal active
:ok
end
defp apply_rendering_config_to_pid(pid, rendering) do
# Extract relevant rendering settings
settings = %{
fps: Map.get(rendering, :fps),
double_buffer: Map.get(rendering, :double_buffer),
redraw_mode: Map.get(rendering, :redraw_mode)
}
# Send configuration to terminal process
send_config_to_terminal(pid, {:rendering_config, settings})
end
# Apply ANSI configuration
defp apply_ansi_config(%{ansi: ansi}, terminal_pid) when is_map(ansi) do
pid = terminal_pid || default_terminal_pid()
apply_ansi_config_to_pid(pid, ansi)
end
# No ANSI config to apply
defp apply_ansi_config(_, _), do: :ok
defp apply_ansi_config_to_pid(nil, _ansi) do
# No terminal active
:ok
end
defp apply_ansi_config_to_pid(pid, ansi) do
# Extract relevant ANSI settings
settings = %{
enabled: Map.get(ansi, :enabled),
color_mode: Map.get(ansi, :color_mode),
colors: Map.get(ansi, :colors, %{})
}
# Send configuration to terminal process
send_config_to_terminal(pid, {:ansi_config, settings})
end
# Apply behavior configuration
defp apply_behavior_config(%{behavior: behavior}, terminal_pid)
when is_map(behavior) do
pid = terminal_pid || default_terminal_pid()
apply_behavior_config_to_pid(pid, behavior)
end
# No behavior config to apply
defp apply_behavior_config(_, _), do: :ok
defp apply_behavior_config_to_pid(nil, _behavior) do
# No terminal active
:ok
end
defp apply_behavior_config_to_pid(pid, behavior) do
# Extract relevant behavior settings
settings = %{
scrollback_lines: Map.get(behavior, :scrollback_lines),
auto_wrap: Map.get(behavior, :auto_wrap),
bell_style: Map.get(behavior, :bell_style)
}
# Send configuration to terminal process
send_config_to_terminal(pid, {:behavior_config, settings})
end
# Get the default terminal process PID
defp default_terminal_pid do
# This would actually look up the terminal process
# For now, we'll just return nil as a placeholder
nil
end
# Send configuration to terminal process
defp send_config_to_terminal(pid, message) do
# Send message to terminal process
# This is a placeholder implementation
# In a real implementation, this would use the appropriate
# message passing mechanism and handle responses
_ = Process.send(pid, message, [:noconnect])
:ok
end
# Get configuration from terminal process
defp get_config_from_terminal(_pid) do
# Placeholder implementation
{:ok, %{}}
end
# Deep merge two maps
defp deep_merge(left, right) when is_map(left) and is_map(right) do
Map.merge(left, right)
end
end