-module(etui@backend@erlang).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etui/backend/erlang.gleam").
-export([new/0, new_with_mouse/0]).
-export_type([erlang_terminal_state/0]).
-type erlang_terminal_state() :: {erlang_terminal_state,
boolean(),
integer(),
integer(),
boolean()}.
-file("src/etui/backend/erlang.gleam", 171).
-spec terminal_cleanup() -> nil.
terminal_cleanup() ->
etui_terminal_ffi:uninstall_sigint_cleanup(),
etui_terminal_ffi:write_cleanup(),
etui_terminal_ffi:exit_raw(),
etui_tty_state:set_raw(false),
nil.
-file("src/etui/backend/erlang.gleam", 179).
-spec cleanup_terminal(erlang_terminal_state()) -> nil.
cleanup_terminal(_) ->
terminal_cleanup().
-file("src/etui/backend/erlang.gleam", 159).
-spec get_terminal_size(erlang_terminal_state()) -> {ok,
{etui@backend:terminal_size(), erlang_terminal_state()}} |
{error, etui@backend:error()}.
get_terminal_size(State) ->
case etui_terminal_ffi:window_size() of
{ok, {W, H}} ->
{ok, {{terminal_size, W - 1, H}, State}};
{error, _} ->
{ok, {{terminal_size, 79, 24}, State}}
end.
-file("src/etui/backend/erlang.gleam", 233).
-spec normalise_key(binary()) -> binary().
normalise_key(Raw) ->
case Raw of
<<"\x{001B}[A"/utf8>> ->
<<"up"/utf8>>;
<<"\x{001B}OA"/utf8>> ->
<<"up"/utf8>>;
<<"\x{001B}[B"/utf8>> ->
<<"down"/utf8>>;
<<"\x{001B}OB"/utf8>> ->
<<"down"/utf8>>;
<<"\x{001B}[C"/utf8>> ->
<<"right"/utf8>>;
<<"\x{001B}OC"/utf8>> ->
<<"right"/utf8>>;
<<"\x{001B}[D"/utf8>> ->
<<"left"/utf8>>;
<<"\x{001B}OD"/utf8>> ->
<<"left"/utf8>>;
<<"\r"/utf8>> ->
<<"enter"/utf8>>;
<<"\n"/utf8>> ->
<<"enter"/utf8>>;
<<"\x{007F}"/utf8>> ->
<<"backspace"/utf8>>;
<<"\x{0008}"/utf8>> ->
<<"backspace"/utf8>>;
<<"\x{001B}[3~"/utf8>> ->
<<"delete"/utf8>>;
<<"\t"/utf8>> ->
<<"tab"/utf8>>;
<<"\x{001B}[Z"/utf8>> ->
<<"backtab"/utf8>>;
<<"\x{001B}"/utf8>> ->
<<"esc"/utf8>>;
<<"\x{001B}[2~"/utf8>> ->
<<"insert"/utf8>>;
<<"\x{001B}[5~"/utf8>> ->
<<"pageup"/utf8>>;
<<"\x{001B}[6~"/utf8>> ->
<<"pagedown"/utf8>>;
<<"\x{001B}[H"/utf8>> ->
<<"home"/utf8>>;
<<"\x{001B}OH"/utf8>> ->
<<"home"/utf8>>;
<<"\x{001B}[1~"/utf8>> ->
<<"home"/utf8>>;
<<"\x{001B}[F"/utf8>> ->
<<"end"/utf8>>;
<<"\x{001B}OF"/utf8>> ->
<<"end"/utf8>>;
<<"\x{001B}[4~"/utf8>> ->
<<"end"/utf8>>;
<<"\x{001B}[11~"/utf8>> ->
<<"f1"/utf8>>;
<<"\x{001B}OP"/utf8>> ->
<<"f1"/utf8>>;
<<"\x{001B}[12~"/utf8>> ->
<<"f2"/utf8>>;
<<"\x{001B}OQ"/utf8>> ->
<<"f2"/utf8>>;
<<"\x{001B}[13~"/utf8>> ->
<<"f3"/utf8>>;
<<"\x{001B}OR"/utf8>> ->
<<"f3"/utf8>>;
<<"\x{001B}[14~"/utf8>> ->
<<"f4"/utf8>>;
<<"\x{001B}OS"/utf8>> ->
<<"f4"/utf8>>;
<<"\x{001B}[15~"/utf8>> ->
<<"f5"/utf8>>;
<<"\x{001B}[17~"/utf8>> ->
<<"f6"/utf8>>;
<<"\x{001B}[18~"/utf8>> ->
<<"f7"/utf8>>;
<<"\x{001B}[19~"/utf8>> ->
<<"f8"/utf8>>;
<<"\x{001B}[20~"/utf8>> ->
<<"f9"/utf8>>;
<<"\x{001B}[21~"/utf8>> ->
<<"f10"/utf8>>;
<<"\x{001B}[23~"/utf8>> ->
<<"f11"/utf8>>;
<<"\x{001B}[24~"/utf8>> ->
<<"f12"/utf8>>;
<<"\x{0001}"/utf8>> ->
<<"ctrl+a"/utf8>>;
<<"\x{0002}"/utf8>> ->
<<"ctrl+b"/utf8>>;
<<"\x{0003}"/utf8>> ->
<<"ctrl+c"/utf8>>;
<<"\x{0004}"/utf8>> ->
<<"ctrl+d"/utf8>>;
<<"\x{0005}"/utf8>> ->
<<"ctrl+e"/utf8>>;
<<"\x{0006}"/utf8>> ->
<<"ctrl+f"/utf8>>;
<<"\x{0007}"/utf8>> ->
<<"ctrl+g"/utf8>>;
<<"\x{000B}"/utf8>> ->
<<"ctrl+k"/utf8>>;
<<"\x{000C}"/utf8>> ->
<<"ctrl+l"/utf8>>;
<<"\x{000E}"/utf8>> ->
<<"ctrl+n"/utf8>>;
<<"\x{000F}"/utf8>> ->
<<"ctrl+o"/utf8>>;
<<"\x{0010}"/utf8>> ->
<<"ctrl+p"/utf8>>;
<<"\x{0011}"/utf8>> ->
<<"ctrl+q"/utf8>>;
<<"\x{0012}"/utf8>> ->
<<"ctrl+r"/utf8>>;
<<"\x{0013}"/utf8>> ->
<<"ctrl+s"/utf8>>;
<<"\x{0014}"/utf8>> ->
<<"ctrl+t"/utf8>>;
<<"\x{0015}"/utf8>> ->
<<"ctrl+u"/utf8>>;
<<"\x{0016}"/utf8>> ->
<<"ctrl+v"/utf8>>;
<<"\x{0017}"/utf8>> ->
<<"ctrl+w"/utf8>>;
<<"\x{0018}"/utf8>> ->
<<"ctrl+x"/utf8>>;
<<"\x{0019}"/utf8>> ->
<<"ctrl+y"/utf8>>;
<<"\x{001A}"/utf8>> ->
<<"ctrl+z"/utf8>>;
S ->
case gleam_stdlib:string_starts_with(S, <<"\x{001B}"/utf8>>) andalso (string:length(
S
)
=:= 2) of
true ->
<<"alt+"/utf8, (gleam@string:drop_start(S, 1))/binary>>;
false ->
S
end
end.
-file("src/etui/backend/erlang.gleam", 302).
-spec parse_sgr_mouse(binary()) -> etui@backend:input_event().
parse_sgr_mouse(Payload) ->
Is_press = gleam_stdlib:string_ends_with(Payload, <<"M"/utf8>>),
Trimmed = case Is_press of
true ->
gleam@string:drop_end(Payload, 1);
false ->
gleam@string:drop_end(Payload, 1)
end,
case gleam@string:split(Trimmed, <<";"/utf8>>) of
[Cb_str, Cx_str, Cy_str] ->
case {gleam_stdlib:parse_int(Cb_str),
gleam_stdlib:parse_int(Cx_str),
gleam_stdlib:parse_int(Cy_str)} of
{{ok, Cb}, {ok, Cx}, {ok, Cy}} ->
X = Cx - 1,
Y = Cy - 1,
case Cb of
64 ->
{mouse_scroll, X, Y, true};
65 ->
{mouse_scroll, X, Y, false};
_ ->
Btn = case Cb rem 4 of
0 ->
mouse_left;
1 ->
mouse_middle;
2 ->
mouse_right;
_ ->
mouse_left
end,
case Is_press of
true ->
{mouse_press, X, Y, Btn};
false ->
{mouse_release, X, Y, Btn}
end
end;
{_, _, _} ->
{key_press, <<"\x{001B}[<"/utf8, Payload/binary>>}
end;
_ ->
{key_press, <<"\x{001B}[<"/utf8, Payload/binary>>}
end.
-file("src/etui/backend/erlang.gleam", 219).
-spec parse_input(binary()) -> etui@backend:input_event().
parse_input(Input) ->
case Input of
<<""/utf8>> ->
tick;
_ ->
case gleam_stdlib:string_starts_with(Input, <<"\x{001B}[<"/utf8>>) of
true ->
parse_sgr_mouse(gleam@string:drop_start(Input, 3));
false ->
{key_press, normalise_key(Input)}
end
end.
-file("src/etui/backend/erlang.gleam", 137).
-spec poll_input(erlang_terminal_state(), integer()) -> {ok,
{etui@backend:input_event(), erlang_terminal_state()}} |
{error, etui@backend:error()}.
poll_input(State, Timeout_ms) ->
Input_event = case etui_terminal_ffi:read_with_timeout(Timeout_ms) of
{ok, Input} ->
parse_input(Input);
{error, _} ->
tick
end,
case etui_terminal_ffi:window_size() of
{ok, {C, R}} ->
case ((C - 1) =:= erlang:element(3, State)) andalso (R =:= erlang:element(
4,
State
)) of
true ->
{ok, {Input_event, State}};
false ->
{ok,
{{resize, C - 1, R},
{erlang_terminal_state,
erlang:element(2, State),
C - 1,
R,
erlang:element(5, State)}}}
end;
{error, _} ->
{ok, {Input_event, State}}
end.
-file("src/etui/backend/erlang.gleam", 340).
-spec int_to_string(integer()) -> binary().
int_to_string(N) ->
case N of
0 ->
<<"0"/utf8>>;
1 ->
<<"1"/utf8>>;
2 ->
<<"2"/utf8>>;
3 ->
<<"3"/utf8>>;
4 ->
<<"4"/utf8>>;
5 ->
<<"5"/utf8>>;
6 ->
<<"6"/utf8>>;
7 ->
<<"7"/utf8>>;
8 ->
<<"8"/utf8>>;
9 ->
<<"9"/utf8>>;
_ ->
Digit = case N rem 10 of
0 ->
<<"0"/utf8>>;
1 ->
<<"1"/utf8>>;
2 ->
<<"2"/utf8>>;
3 ->
<<"3"/utf8>>;
4 ->
<<"4"/utf8>>;
5 ->
<<"5"/utf8>>;
6 ->
<<"6"/utf8>>;
7 ->
<<"7"/utf8>>;
8 ->
<<"8"/utf8>>;
9 ->
<<"9"/utf8>>;
_ ->
<<"?"/utf8>>
end,
<<(int_to_string(N div 10))/binary, Digit/binary>>
end.
-file("src/etui/backend/erlang.gleam", 200).
-spec render_op_to_string(etui@backend:render_op()) -> binary().
render_op_to_string(Op) ->
case Op of
{move_cursor, X, Y} ->
<<<<<<<<"\x{001B}["/utf8, (int_to_string(Y + 1))/binary>>/binary,
";"/utf8>>/binary,
(int_to_string(X + 1))/binary>>/binary,
"H"/utf8>>;
{write, S} ->
S;
clear_screen ->
<<"\x{001B}[2J\x{001B}[H"/utf8>>;
enter_alt_screen ->
<<"\x{001B}[?1049h"/utf8>>;
exit_alt_screen ->
<<"\x{001B}[?1049l"/utf8>>;
enable_mouse ->
<<"\x{001B}[?1000h\x{001B}[?1006h"/utf8>>;
disable_mouse ->
<<"\x{001B}[?1007l\x{001B}[?1015l\x{001B}[?1006l\x{001B}[?1005l\x{001B}[?1003l\x{001B}[?1002l\x{001B}[?1000l"/utf8>>
end.
-file("src/etui/backend/erlang.gleam", 186).
-spec write_ops_to_stdout(list(etui@backend:render_op())) -> {ok, nil} |
{error, binary()}.
write_ops_to_stdout(Ops) ->
Output = begin
_pipe = Ops,
gleam@list:fold(
_pipe,
<<""/utf8>>,
fun(Acc, Op) -> <<Acc/binary, (render_op_to_string(Op))/binary>> end
)
end,
case Output of
<<""/utf8>> ->
{ok, nil};
S ->
io:put_chars(S),
{ok, nil}
end.
-file("src/etui/backend/erlang.gleam", 127).
-spec render_ops(erlang_terminal_state(), list(etui@backend:render_op())) -> {ok,
erlang_terminal_state()} |
{error, etui@backend:error()}.
render_ops(State, Ops) ->
case write_ops_to_stdout(Ops) of
{ok, nil} ->
{ok, State};
{error, Reason} ->
{error, {i_o_error, Reason}}
end.
-file("src/etui/backend/erlang.gleam", 101).
-spec init_terminal(boolean()) -> {ok, erlang_terminal_state()} |
{error, etui@backend:error()}.
init_terminal(Mouse) ->
etui_tty_state:init(),
Init_ops = case Mouse of
true ->
[enter_alt_screen, clear_screen, enable_mouse];
false ->
[enter_alt_screen, clear_screen]
end,
case write_ops_to_stdout(Init_ops) of
{ok, nil} ->
etui_terminal_ffi:enter_raw(),
etui_tty_state:set_raw(true),
{Cols, Rows} = case etui_terminal_ffi:window_size() of
{ok, {C, R}} ->
{C - 1, R};
{error, _} ->
{79, 24}
end,
etui_terminal_ffi:install_sigint_cleanup(
fun() -> terminal_cleanup() end
),
{ok, {erlang_terminal_state, true, Cols, Rows, Mouse}};
{error, Reason} ->
{error, {i_o_error, Reason}}
end.
-file("src/etui/backend/erlang.gleam", 31).
-spec new_impl(boolean()) -> etui@backend:backend(erlang_terminal_state()).
new_impl(Mouse) ->
{backend,
fun() -> init_terminal(Mouse) end,
fun render_ops/2,
fun poll_input/2,
fun get_terminal_size/1,
fun cleanup_terminal/1}.
-file("src/etui/backend/erlang.gleam", 23).
-spec new() -> etui@backend:backend(erlang_terminal_state()).
new() ->
new_impl(false).
-file("src/etui/backend/erlang.gleam", 27).
-spec new_with_mouse() -> etui@backend:backend(erlang_terminal_state()).
new_with_mouse() ->
new_impl(true).