Packages
Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.
Current section
Files
Jump to
Current section
Files
lib/raxol/ui/components/input/multi_line_input/message_router.ex
defmodule Raxol.UI.Components.Input.MultiLineInput.MessageRouter do
@moduledoc """
Handles message routing for MultiLineInput component to reduce complexity.
"""
@message_handlers %{
{:update_props, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_update_props/2,
{:input, :_} => &Raxol.UI.Components.Input.MultiLineInput.handle_input/2,
{:backspace} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_backspace/1,
{:delete} => &Raxol.UI.Components.Input.MultiLineInput.handle_delete/1,
{:enter} => &Raxol.UI.Components.Input.MultiLineInput.handle_enter/1,
{:move_cursor, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor/2,
{:move_cursor_line_start} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_line_start/1,
{:move_cursor_line_end} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_line_end/1,
{:move_cursor_page, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_page/2,
{:move_cursor_doc_start} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_doc_start/1,
{:move_cursor_doc_end} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_doc_end/1,
{:move_cursor_to, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_to/2,
{:select_and_move, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_selection_move/2,
{:select_all} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_select_all/1,
{:copy} => &Raxol.UI.Components.Input.MultiLineInput.handle_copy/1,
{:cut} => &Raxol.UI.Components.Input.MultiLineInput.handle_cut/1,
{:paste} => &Raxol.UI.Components.Input.MultiLineInput.handle_paste/1,
{:clipboard_content, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_clipboard_content/2,
:focus => &Raxol.UI.Components.Input.MultiLineInput.handle_focus/1,
:blur => &Raxol.UI.Components.Input.MultiLineInput.handle_blur/1,
{:set_shift_held, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_set_shift_held/2,
{:delete_selection, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_delete_selection/2,
{:copy_selection} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_copy_selection/1,
{:move_cursor_word_left} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_word_left/1,
{:move_cursor_word_right} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_move_cursor_word_right/1,
{:move_cursor_select, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_selection_move/2,
{:select_to, :_} =>
&Raxol.UI.Components.Input.MultiLineInput.handle_select_to/2
}
def route(msg, state) do
case find_handler(msg) do
{handler, args} -> {:ok, apply_handler(handler, args, state)}
nil -> :error
end
end
defp find_handler(msg) do
Enum.find_value(@message_handlers, fn {pattern, handler} ->
if matches_pattern?(msg, pattern) do
{handler, extract_args(msg, pattern)}
end
end)
end
defp matches_pattern?(msg, pattern) do
case {msg, pattern} do
{msg, pattern} when msg == pattern -> true
{{tag, _}, {tag, :_}} -> matches_tag_pattern?(tag, msg)
_ -> false
end
end
defp matches_tag_pattern?(:update_props, _msg), do: true
defp matches_tag_pattern?(:input, _msg), do: true
defp matches_tag_pattern?(:move_cursor, {:move_cursor, direction}),
do: direction in [:left, :right, :up, :down]
defp matches_tag_pattern?(:move_cursor_page, {:move_cursor_page, direction}),
do: direction in [:up, :down]
defp matches_tag_pattern?(:move_cursor_to, _msg), do: true
defp matches_tag_pattern?(:select_and_move, _msg), do: true
defp matches_tag_pattern?(:clipboard_content, {:clipboard_content, content}),
do: is_binary(content)
defp matches_tag_pattern?(:set_shift_held, _msg), do: true
defp matches_tag_pattern?(:delete_selection, {:delete_selection, direction}),
do: direction in [:backward, :forward]
defp matches_tag_pattern?(
:move_cursor_select,
{:move_cursor_select, direction}
),
do:
direction in [
:left,
:right,
:up,
:down,
:line_start,
:line_end,
:page_up,
:page_down,
:doc_start,
:doc_end
]
defp matches_tag_pattern?(:select_to, _msg), do: true
defp matches_tag_pattern?(_, _), do: false
defp extract_args(msg, pattern) do
case {msg, pattern} do
{{tag, arg}, {tag, :_}} -> extract_tag_args(tag, arg)
_ -> []
end
end
defp extract_tag_args(:update_props, new_props), do: [new_props]
defp extract_tag_args(:input, char_codepoint), do: [char_codepoint]
defp extract_tag_args(:move_cursor, direction), do: [direction]
defp extract_tag_args(:move_cursor_page, direction), do: [direction]
defp extract_tag_args(:move_cursor_to, pos), do: [pos]
defp extract_tag_args(:select_and_move, direction), do: [direction]
defp extract_tag_args(:clipboard_content, content), do: [content]
defp extract_tag_args(:set_shift_held, held), do: [held]
defp extract_tag_args(:delete_selection, direction), do: [direction]
defp extract_tag_args(:move_cursor_select, direction), do: [direction]
defp extract_tag_args(:select_to, pos), do: [pos]
defp extract_tag_args(_, _), do: []
defp apply_handler(handler, args, state) do
case length(args) do
0 -> handler.(state)
1 -> apply(handler, [Enum.at(args, 0), state])
2 -> apply(handler, args ++ [state])
end
end
end