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 commands command_server sgr_ops.ex
Raw

lib/raxol/terminal/commands/command_server/sgr_ops.ex

defmodule Raxol.Terminal.Commands.CommandServer.SGROps do
@moduledoc false
@compile {:no_warn_undefined, Raxol.Terminal.Commands.CommandServer.Helpers}
alias Raxol.Terminal.ANSI.TextFormatting
alias Raxol.Terminal.Commands.CommandServer.Helpers
@sgr_mappings %{
0 => {:reset, :all},
1 => {:set_attribute, :bold},
2 => {:set_attribute, :faint},
3 => {:set_attribute, :italic},
4 => {:set_attribute, :underline},
5 => {:set_attribute, :blink},
7 => {:set_attribute, :reverse},
8 => {:set_attribute, :conceal},
9 => {:set_attribute, :strikethrough},
22 => {:reset_attribute, :bold_faint},
23 => {:reset_attribute, :italic},
24 => {:reset_attribute, :underline},
25 => {:reset_attribute, :blink},
27 => {:reset_attribute, :reverse},
28 => {:reset_attribute, :conceal},
29 => {:reset_attribute, :strikethrough},
39 => {:color, :foreground, :reset},
49 => {:color, :background, :reset}
}
def handle_sgr(emulator, %{params: params}, _context) do
apply_text_formatting(emulator, params)
end
defp apply_text_formatting(emulator, params) do
updated_emulator =
Enum.reduce(params, emulator, fn param, acc ->
apply_sgr_parameter(acc, param)
end)
{:ok, updated_emulator}
end
defp apply_sgr_parameter(emulator, param) do
current_style = Helpers.get_current_text_style(emulator)
new_style = apply_sgr_formatting(current_style, param)
Helpers.set_current_text_style(emulator, new_style)
end
defp apply_sgr_formatting(style, param) do
case categorize_sgr_parameter(param) do
{:reset, _} -> TextFormatting.reset_attributes(style)
{:set_attribute, attribute} -> apply_text_attribute(style, attribute)
{:reset_attribute, attribute} -> reset_text_attribute(style, attribute)
{:color, type, value} -> apply_color(style, type, value)
:unknown -> style
end
end
defp categorize_sgr_parameter(param) do
@sgr_mappings[param] || categorize_sgr_range(param)
end
defp categorize_sgr_range(param) do
cond do
param >= 30 and param <= 37 -> {:color, :foreground, param - 30}
param >= 40 and param <= 47 -> {:color, :background, param - 40}
true -> :unknown
end
end
defp apply_text_attribute(style, attribute) do
case attribute do
:bold -> TextFormatting.set_bold(style)
:faint -> TextFormatting.set_faint(style)
:italic -> TextFormatting.set_italic(style)
:underline -> TextFormatting.set_underline(style)
:blink -> TextFormatting.set_blink(style)
:reverse -> TextFormatting.set_reverse(style)
:conceal -> TextFormatting.set_conceal(style)
:strikethrough -> TextFormatting.set_strikethrough(style)
end
end
defp reset_text_attribute(style, attribute) do
case attribute do
:bold_faint ->
TextFormatting.reset_bold(style) |> TextFormatting.reset_faint()
:italic ->
TextFormatting.reset_italic(style)
:underline ->
TextFormatting.reset_underline(style)
:blink ->
TextFormatting.reset_blink(style)
:reverse ->
TextFormatting.reset_reverse(style)
:conceal ->
TextFormatting.reset_conceal(style)
:strikethrough ->
TextFormatting.reset_strikethrough(style)
end
end
defp apply_color(style, type, value) do
case {type, value} do
{:foreground, :reset} ->
TextFormatting.reset_foreground(style)
{:background, :reset} ->
TextFormatting.reset_background(style)
{:foreground, color_value} ->
TextFormatting.set_foreground(style, color_value)
{:background, color_value} ->
TextFormatting.set_background(style, color_value)
end
end
end