Skip to main content

src/etch@erlang@input.erl

-module(etch@erlang@input).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etch/erlang/input.gleam").
-export([poll/1, read/0, input_loop/1, get_keyboard_enhancement_flags/0, get_cursor_position/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

-file("src/etch/erlang/input.gleam", 14).
?DOC(
    " Checks if there is an [`Event`](https://hexdocs.pm/etch/etch/event.html#Event) available.\n"
    " Returns None if no events were received within the timeout.\n"
    " See also [`read`](input.html#read).\n"
).
-spec poll(integer()) -> gleam@option:option({ok, etch@event:event()} |
    {error, etch@event:event_error()}).
poll(Timeout) ->
    input_ffi:poll(Timeout).

-file("src/etch/erlang/input.gleam", 20).
?DOC(
    " Checks if there is an [`Event`](https://hexdocs.pm/etch/etch/event.html#Event) available.\n"
    " Waits forever for an available event.\n"
    " See also [`poll`](input.html#poll).\n"
).
-spec read() -> gleam@option:option({ok, etch@event:event()} |
    {error, etch@event:event_error()}).
read() ->
    input_ffi:read().

-file("src/etch/erlang/input.gleam", 43).
-spec push_events(
    list({ok, etch@event:event()} | {error, etch@event:event_error()})
) -> nil.
push_events(Events) ->
    case Events of
        [] ->
            nil;

        [E | Rest] ->
            input_ffi:push(E),
            push_events(Rest)
    end.

-file("src/etch/erlang/input.gleam", 32).
?DOC(false).
-spec input_loop(boolean()) -> any().
input_loop(Is_raw_mode) ->
    Str = case Is_raw_mode of
        true ->
            io:get_chars(<<""/utf8>>, 128);

        false ->
            io:get_line(<<""/utf8>>)
    end,
    Str@1 = gleam@string:to_graphemes(Str),
    Events = etch@event:parse_events(Str@1, <<""/utf8>>, [], false),
    push_events(Events),
    input_loop(Is_raw_mode).

-file("src/etch/erlang/input.gleam", 57).
?DOC(
    " Get keyboard enhancement flags. See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement>\n"
    " This function shouldn't be called in a tight loop. It's fine to call it when\n"
    " responding to specific user input (e.g., after a key press), but avoid calling\n"
    " it on every loop iteration.\n"
).
-spec get_keyboard_enhancement_flags() -> {ok,
        list(etch@event:keyboard_enhancement_flag())} |
    {error, etch@event:event_error()}.
get_keyboard_enhancement_flags() ->
    gleam_stdlib:print(<<"\x{001b}["/utf8, "?u"/utf8>>),
    Flags = io:get_chars(<<""/utf8>>, 32),
    case Flags of
        <<"\x{001b}[?"/utf8, S/binary>> ->
            case gleam@string:last(S) of
                {ok, <<"u"/utf8>>} ->
                    {ok, etch@event:parse_keyboard_enhancement_flags(S)};

                _ ->
                    {error,
                        {failed_to_parse_event,
                            <<"Could not get enhancment flags"/utf8>>}}
            end;

        _ ->
            {error,
                {failed_to_parse_event,
                    <<"Could not get cursor position"/utf8>>}}
    end.

-file("src/etch/erlang/input.gleam", 78).
?DOC(
    " Returns cursor position.\n"
    " This function shouldn't be called in a tight loop. It's fine to call it when\n"
    " responding to specific user input (e.g., after a key press), but avoid calling\n"
    " it on every loop iteration.\n"
).
-spec get_cursor_position() -> {ok, {integer(), integer()}} |
    {error, etch@event:event_error()}.
get_cursor_position() ->
    gleam_stdlib:print(<<"\x{001b}["/utf8, "6n"/utf8>>),
    Pos = io:get_chars(<<""/utf8>>, 32),
    case Pos of
        <<"\x{001b}["/utf8, S/binary>> ->
            case gleam@string:last(S) of
                {ok, <<"R"/utf8>>} ->
                    etch@event:parse_cursor_position(S);

                _ ->
                    {error,
                        {failed_to_parse_event,
                            <<"Could not get cursor position"/utf8>>}}
            end;

        _ ->
            {error,
                {failed_to_parse_event,
                    <<"Could not get cursor position"/utf8>>}}
    end.