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