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/input/control_sequence_handler.ex
defmodule Raxol.Terminal.Input.ControlSequenceHandler do
@moduledoc """
Handles various control sequences for the terminal emulator.
Includes CSI, OSC, DCS, PM, and APC sequence handling.
## APC Sequences
APC (Application Program Command) sequences are used by the Kitty graphics
protocol for transmitting images. The format is:
ESC _ G <control-data> ; <payload> ESC \\
Where `G` indicates Kitty graphics and control-data contains key=value pairs.
"""
require Raxol.Core.Runtime.Log
alias Raxol.Terminal.ANSI.KittyGraphics
alias Raxol.Terminal.Commands.{CSIHandler, OSCHandler}
@doc """
Handles a CSI (Control Sequence Introducer) sequence.
"""
def handle_csi_sequence(emulator, command, params) do
CSIHandler.handle_csi_sequence(emulator, command, params)
end
@doc """
Handles an OSC (Operating System Command) sequence.
"""
def handle_osc_sequence(emulator, command, data) do
OSCHandler.handle_osc_sequence(emulator, command, data)
end
@doc """
Handles a DCS (Device Control String) sequence.
"""
def handle_dcs_sequence(emulator, command, data) do
case command do
# Sixel graphics
"q" ->
handle_sixel_graphics(emulator, data)
# DECRQSS (Request Status String)
"r" ->
handle_status_string_request(emulator, data)
# Unknown DCS command
_ ->
Raxol.Core.Runtime.Log.debug(
"Unhandled DCS command: #{command} with data: #{inspect(data)}"
)
emulator
end
end
@doc """
Handles a PM (Privacy Message) sequence.
"""
def handle_pm_sequence(emulator, command, data) do
# PM sequences are typically ignored by terminals
Raxol.Core.Runtime.Log.debug("Ignoring PM sequence: #{command} with data: #{inspect(data)}")
emulator
end
@doc """
Handles an APC (Application Program Command) sequence.
APC sequences are used by the Kitty graphics protocol. The command
indicates the type of APC sequence:
* `G` - Kitty graphics protocol
* Other commands are logged and ignored
"""
def handle_apc_sequence(emulator, command, data) do
case command do
# Kitty graphics protocol
"G" ->
handle_kitty_graphics(emulator, data)
# Unknown APC command
_ ->
Raxol.Core.Runtime.Log.debug(
"Unhandled APC sequence: #{command} with data: #{inspect(truncate_data(data))}"
)
emulator
end
end
# Private helper functions for DCS handlers
defp handle_sixel_graphics(emulator, data) do
# Basic Sixel graphics handling - currently just logs and returns
# Full implementation will be added in a future update
Raxol.Core.Runtime.Log.info("Sixel graphics received: #{byte_size(data)} bytes")
emulator
end
defp handle_status_string_request(emulator, data) do
# Handle DECRQSS (Request Status String) command
case data do
# SGR (Select Graphic Rendition)
"m" ->
response = "\eP1$r#{emulator.style}\e\\"
%{emulator | output_buffer: emulator.output_buffer <> response}
# DECSTBM (Set Top and Bottom Margins)
"r" ->
{top, bottom} = emulator.scroll_region
response = "\eP1$r#{top};#{bottom}r\e\\"
%{emulator | output_buffer: emulator.output_buffer <> response}
_ ->
emulator
end
end
# Private helper functions for APC handlers
defp handle_kitty_graphics(emulator, data) do
# Get or initialize Kitty graphics state from emulator
kitty_state = Map.get(emulator, :kitty_graphics, KittyGraphics.new())
case KittyGraphics.process_sequence(kitty_state, data) do
{updated_kitty_state, :ok} ->
Raxol.Core.Runtime.Log.debug(
"[ControlSequenceHandler] Kitty graphics processed successfully"
)
Map.put(emulator, :kitty_graphics, updated_kitty_state)
{_kitty_state, {:error, reason}} ->
Raxol.Core.Runtime.Log.warning(
"[ControlSequenceHandler] Kitty graphics error: #{inspect(reason)}"
)
emulator
end
end
defp truncate_data(data) when is_binary(data) and byte_size(data) > 100 do
<<prefix::binary-size(100), _rest::binary>> = data
prefix <> "...(#{byte_size(data)} bytes total)"
end
defp truncate_data(data), do: data
end