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 mode_ops.ex
Raw

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

defmodule Raxol.Terminal.Commands.CommandServer.ModeOps do
@moduledoc false
alias Raxol.Terminal.ScreenBuffer
def handle_set_mode(
emulator,
%{params: params, private_markers: private},
_context
) do
case private do
"?" -> handle_dec_private_mode(emulator, params, :set)
_ -> handle_ansi_mode(emulator, params, :set)
end
end
def handle_reset_mode(
emulator,
%{params: params, private_markers: private},
_context
) do
case private do
"?" -> handle_dec_private_mode(emulator, params, :reset)
_ -> handle_ansi_mode(emulator, params, :reset)
end
end
defp handle_ansi_mode(emulator, params, action) do
updated_emulator =
Enum.reduce(params, emulator, fn mode, acc ->
apply_ansi_mode(acc, mode, action)
end)
{:ok, updated_emulator}
end
defp handle_dec_private_mode(emulator, params, action) do
updated_emulator =
Enum.reduce(params, emulator, fn mode, acc ->
apply_dec_private_mode(acc, mode, action)
end)
{:ok, updated_emulator}
end
defp apply_ansi_mode(emulator, mode, action) do
case {mode, action} do
{4, :set} -> %{emulator | insert_mode: true}
{4, :reset} -> %{emulator | insert_mode: false}
{20, :set} -> %{emulator | automatic_newline: true}
{20, :reset} -> %{emulator | automatic_newline: false}
_ -> emulator
end
end
defp apply_dec_private_mode(emulator, mode, action) do
case {mode, action} do
{1, :set} ->
%{emulator | cursor_keys_mode: :application}
{1, :reset} ->
%{emulator | cursor_keys_mode: :normal}
{25, :set} ->
%{emulator | cursor_visible: true}
{25, :reset} ->
%{emulator | cursor_visible: false}
{47, :set} ->
switch_to_alternate_screen(emulator)
{47, :reset} ->
switch_to_main_screen(emulator)
{1049, :set} ->
emulator
|> save_cursor_position()
|> switch_to_alternate_screen_with_clear()
{1049, :reset} ->
emulator
|> switch_to_main_screen()
|> restore_cursor_position()
_ ->
emulator
end
end
defp switch_to_alternate_screen(emulator) do
%{emulator | screen_mode: :alternate, active_buffer_type: :alternate}
end
defp switch_to_alternate_screen_with_clear(emulator) do
emulator
|> switch_to_alternate_screen()
|> clear_alternate_buffer()
end
defp switch_to_main_screen(emulator) do
%{emulator | screen_mode: :main, active_buffer_type: :main}
end
defp save_cursor_position(emulator) do
cursor = emulator.cursor
updated_cursor = %{
cursor
| saved_row: cursor.row,
saved_col: cursor.col,
saved_position: {cursor.row, cursor.col}
}
%{emulator | cursor: updated_cursor}
end
defp restore_cursor_position(emulator) do
cursor = emulator.cursor
{new_row, new_col} =
case {cursor.saved_row, cursor.saved_col} do
{nil, nil} -> {0, 0}
{row, col} -> {row, col}
end
updated_cursor = %{
cursor
| row: new_row,
col: new_col,
position: {new_row, new_col}
}
%{emulator | cursor: updated_cursor}
end
defp clear_alternate_buffer(emulator) do
blank_buffer = ScreenBuffer.new(emulator.width, emulator.height)
%{emulator | alternate_screen_buffer: blank_buffer}
end
end