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 emulator input_processing.ex
Raw

lib/raxol/terminal/emulator/input_processing.ex

defmodule Raxol.Terminal.Emulator.InputProcessing do
@moduledoc false
alias Raxol.Core.Runtime.Log
alias Raxol.Terminal.Emulator.ModeOperations
def process_input(emulator, input) do
emulator = preprocess_scroll_region(emulator, input)
result =
Raxol.Terminal.Input.CoreHandler.process_terminal_input(emulator, input)
{updated_emulator, output} =
case result do
{emu, out} -> {emu, IO.iodata_to_binary(out)}
end
updated_emulator = maybe_track_history(updated_emulator, input)
{updated_emulator, output}
end
def handle_esc_equals(emulator) do
Log.debug("Emulator.handle_esc_equals called - setting decckm mode")
Log.debug("Initial cursor_keys_mode: #{inspect(emulator.mode_manager.cursor_keys_mode)}")
case ModeOperations.set_mode(emulator, :decckm) do
{:ok, new_emulator} ->
Log.debug("ModeOperations.set_mode succeeded")
Log.debug(
"Final cursor_keys_mode: #{inspect(new_emulator.mode_manager.cursor_keys_mode)}"
)
new_emulator
{:error, reason} ->
Log.debug("ModeOperations.set_mode failed: #{inspect(reason)}")
emulator
end
end
def handle_esc_greater(emulator) do
Log.debug("Emulator.handle_esc_greater called - resetting decckm mode")
Log.debug("Initial cursor_keys_mode: #{inspect(emulator.mode_manager.cursor_keys_mode)}")
case ModeOperations.reset_mode(emulator, :decckm) do
{:ok, new_emulator} ->
Log.debug("ModeOperations.reset_mode succeeded")
Log.debug(
"Final cursor_keys_mode: #{inspect(new_emulator.mode_manager.cursor_keys_mode)}"
)
new_emulator
{:error, reason} ->
Log.debug("ModeOperations.reset_mode failed: #{inspect(reason)}")
emulator
end
end
defp preprocess_scroll_region(emulator, input) do
case input do
<<"\e[", rest::binary>> when byte_size(rest) > 0 ->
case Regex.run(~r/^(\d+);(\d+)r/, rest) do
[_, top, bottom] ->
top_i = String.to_integer(top) - 1
bottom_i = String.to_integer(bottom) - 1
%{emulator | scroll_region: {top_i, bottom_i}}
_ ->
case rest do
"r" <> _ -> %{emulator | scroll_region: nil}
_ -> emulator
end
end
_ ->
emulator
end
end
defp maybe_track_history(emulator, input) do
case emulator.history_buffer do
nil -> emulator
_buffer -> track_command_history(emulator, input)
end
end
defp track_command_history(emulator, input) do
current_buffer = emulator.current_command_buffer || ""
{new_buffer, should_add_to_history} =
String.graphemes(input)
|> Enum.reduce({current_buffer, false}, fn char, {buffer, add_history} ->
case char do
"\n" -> {buffer, true}
"\r" -> {buffer, true}
<<c>> when c < 32 and c != ?\t -> {buffer, add_history}
printable -> {buffer <> printable, add_history}
end
end)
case should_add_to_history do
true when byte_size(new_buffer) > 0 ->
emulator_with_history =
Raxol.Terminal.HistoryManager.add_command(emulator, new_buffer)
%{emulator_with_history | current_command_buffer: ""}
_ ->
%{emulator | current_command_buffer: new_buffer}
end
end
end