-module(etui@keymap).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etui/keymap.gleam").
-export([keymap_new/0, bind/4, unbind/2, merge/2, lookup/2, help_lines/1, all_bindings/1, render_help/4, filter/2]).
-export_type([binding/1, keymap/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type binding(EXR) :: {binding, binary(), EXR, binary()}.
-type keymap(EXS) :: {keymap, list(binding(EXS))}.
-file("src/etui/keymap.gleam", 52).
?DOC(" Empty keymap.\n").
-spec keymap_new() -> keymap(any()).
keymap_new() ->
{keymap, []}.
-file("src/etui/keymap.gleam", 58).
?DOC(
" Add a binding to the end of the keymap.\n"
" The first matching binding wins on `lookup`.\n"
).
-spec bind(keymap(EXV), binary(), EXV, binary()) -> keymap(EXV).
bind(Km, Key, Action, Description) ->
{keymap,
lists:append(
erlang:element(2, Km),
[{binding, Key, Action, Description}]
)}.
-file("src/etui/keymap.gleam", 70).
?DOC(" Remove all bindings for a given key.\n").
-spec unbind(keymap(EXY), binary()) -> keymap(EXY).
unbind(Km, Key) ->
{keymap,
gleam@list:filter(
erlang:element(2, Km),
fun(B) -> erlang:element(2, B) /= Key end
)}.
-file("src/etui/keymap.gleam", 75).
?DOC(" Merge `other` into `km`. Bindings from `other` are appended.\n").
-spec merge(keymap(EYB), keymap(EYB)) -> keymap(EYB).
merge(Km, Other) ->
{keymap, lists:append(erlang:element(2, Km), erlang:element(2, Other))}.
-file("src/etui/keymap.gleam", 83).
?DOC(" Find the action bound to `key`. Returns `Error(Nil)` if not found.\n").
-spec lookup(keymap(EYF), binary()) -> {ok, EYF} | {error, nil}.
lookup(Km, Key) ->
case gleam@list:find(
erlang:element(2, Km),
fun(B) -> erlang:element(2, B) =:= Key end
) of
{ok, B@1} ->
{ok, erlang:element(3, B@1)};
{error, _} ->
{error, nil}
end.
-file("src/etui/keymap.gleam", 91).
?DOC(" All bindings as `#(key, description)` pairs, in registration order.\n").
-spec help_lines(keymap(any())) -> list({binary(), binary()}).
help_lines(Km) ->
gleam@list:map(
erlang:element(2, Km),
fun(B) -> {erlang:element(2, B), erlang:element(4, B)} end
).
-file("src/etui/keymap.gleam", 96).
?DOC(" All bindings as `#(key, action)` pairs.\n").
-spec all_bindings(keymap(EYM)) -> list({binary(), EYM}).
all_bindings(Km) ->
gleam@list:map(
erlang:element(2, Km),
fun(B) -> {erlang:element(2, B), erlang:element(3, B)} end
).
-file("src/etui/keymap.gleam", 129).
-spec render_help_rows(
etui@buffer:buffer(),
etui@geometry:rect(),
list({binary(), binary()}),
integer(),
etui@style:style(),
integer()
) -> etui@buffer:buffer().
render_help_rows(Buf, Area, Lines, Key_w, St, Row) ->
case (Row >= erlang:element(3, erlang:element(3, Area))) orelse gleam@list:is_empty(
Lines
) of
true ->
Buf;
false ->
case Lines of
[] ->
Buf;
[{Key, Desc} | Rest] ->
Padded_key = etui@text:pad_right(Key, Key_w),
Row_text = <<<<Padded_key/binary, " "/utf8>>/binary,
(etui@text:truncate(
Desc,
(erlang:element(2, erlang:element(3, Area)) - Key_w)
- 2,
<<""/utf8>>
))/binary>>,
Trimmed = etui@text:truncate(
Row_text,
erlang:element(2, erlang:element(3, Area)),
<<""/utf8>>
),
Padded = etui@text:pad_right(
Trimmed,
erlang:element(2, erlang:element(3, Area))
),
Buf2 = etui@buffer:set_string(
Buf,
{position,
erlang:element(2, erlang:element(2, Area)),
erlang:element(3, erlang:element(2, Area)) + Row},
Padded,
erlang:element(2, St),
erlang:element(3, St),
erlang:element(4, St)
),
render_help_rows(Buf2, Area, Rest, Key_w, St, Row + 1)
end
end.
-file("src/etui/keymap.gleam", 107).
?DOC(
" Render a help table into `area`.\n"
" Each row shows ` key_col description`. `key_col_width` is the\n"
" minimum column width for keys (auto-computed if 0).\n"
" Returns the buffer with the help overlay drawn.\n"
).
-spec render_help(
etui@buffer:buffer(),
etui@geometry:rect(),
keymap(any()),
etui@style:style()
) -> etui@buffer:buffer().
render_help(Buf, Area, Km, St) ->
Lines = help_lines(Km),
Key_w = case gleam@list:fold(
Lines,
0,
fun(Acc, Pair) ->
{K, _} = Pair,
case etui@text:cell_width(K) > Acc of
true ->
etui@text:cell_width(K);
false ->
Acc
end
end
) of
0 ->
6;
N ->
N
end,
render_help_rows(Buf, Area, Lines, Key_w, St, 0).
-file("src/etui/keymap.gleam", 170).
?DOC(
" Keep only bindings whose description contains `query` (case-insensitive).\n"
" Useful for a live-filter command palette.\n"
).
-spec filter(keymap(EYS), binary()) -> keymap(EYS).
filter(Km, Query) ->
case Query of
<<""/utf8>> ->
Km;
Q ->
Lower_q = string:lowercase(Q),
{keymap,
gleam@list:filter(
erlang:element(2, Km),
fun(B) ->
gleam_stdlib:contains_string(
string:lowercase(erlang:element(4, B)),
Lower_q
)
orelse gleam_stdlib:contains_string(
string:lowercase(erlang:element(2, B)),
Lower_q
)
end
)}
end.