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/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