defmodule Raxol.Terminal.Parser.States.OSCStringState do @moduledoc """ Handles the OSC String state in the terminal parser. This state is entered when an OSC sequence is initiated. """ alias Raxol.Terminal.Emulator alias Raxol.Terminal.Parser.ParserState, as: State alias Raxol.Terminal.Commands.Executor require Raxol.Core.Runtime.Log @doc """ Processes input when the parser is in the :osc_string state. Collects the OSC string until ST (ESC \) or BEL. """ @spec handle(Emulator.t(), State.t(), binary()) :: {:continue, Emulator.t(), State.t(), binary()} | {:finished, Emulator.t(), State.t()} | {:incomplete, Emulator.t(), State.t()} def handle( emulator, %State{state: :osc_string} = parser_state, input ) do case input do <<>> -> # Incomplete OSC string - return current state Raxol.Core.Runtime.Log.debug( "[Parser] Incomplete OSC string, input ended." ) {:incomplete, emulator, parser_state} # String Terminator (ST - ESC \) -- Use escape_char check first <<27, rest_after_esc::binary>> -> {:continue, emulator, %{parser_state | state: :osc_string_maybe_st}, rest_after_esc} # BEL (7) is another valid terminator for OSC <<7, rest_after_bel::binary>> -> # Call the dispatcher function (now imported) new_emulator = Executor.execute_osc_command( emulator, parser_state.payload_buffer ) next_parser_state = %{parser_state | state: :ground} {:continue, new_emulator, next_parser_state, rest_after_bel} # CAN/SUB abort OSC string <> when abort_byte == 0x18 or abort_byte == 0x1A -> Raxol.Core.Runtime.Log.debug("Aborting OSC String due to CAN/SUB") next_parser_state = %{parser_state | state: :ground} {:continue, emulator, next_parser_state, rest_after_abort} # Standard printable ASCII <> when char >= 32 and char <= 126 -> # Append to payload buffer next_parser_state = %{ parser_state | payload_buffer: parser_state.payload_buffer <> <> } {:continue, emulator, next_parser_state, rest} # Unhandled byte <> -> Raxol.Core.Runtime.Log.warning_with_context( "Unhandled byte in OSC String state: #{inspect(unhandled_byte)}", %{} ) # Go to ground state next_parser_state = %{parser_state | state: :ground} {:continue, emulator, next_parser_state, rest_after_unhandled} end end end