Packages

A library to easily create rich and interactive prompts in the terminal

Current section

Files

Jump to
survey src survey.erl
Raw

src/survey.erl

-module(survey).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new_question/5, new_confirmation/4, ask/2, ask_fn/3, ask_many_fn/3, ask_many/2]).
-export_type([survey/0, answer/0, ask_error/0]).
-type survey() :: {question,
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(fun((binary()) -> boolean())),
gleam@option:option(fun((binary()) -> binary()))} |
{confirmation,
binary(),
gleam@option:option(binary()),
gleam@option:option(boolean()),
gleam@option:option(fun((boolean()) -> boolean()))}.
-type answer() :: {string_answer, binary()} |
{bool_answer, boolean()} |
{answer_error, ask_error()} |
no_answer.
-type ask_error() :: input | invalid_type | validation.
-spec new_question(
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(fun((binary()) -> boolean())),
gleam@option:option(fun((binary()) -> binary()))
) -> survey().
new_question(Prompt, Help, Default, Validate, Transform) ->
{question, Prompt, Help, Default, Validate, Transform}.
-spec new_confirmation(
binary(),
gleam@option:option(binary()),
gleam@option:option(boolean()),
gleam@option:option(fun((boolean()) -> boolean()))
) -> survey().
new_confirmation(Prompt, Help, Default, Transform) ->
{confirmation, Prompt, Help, Default, Transform}.
-spec default_get_line(binary()) -> {ok, binary()} | {error, ask_error()}.
default_get_line(Prompt) ->
case gleam_erlang_ffi:get_line(Prompt) of
{ok, S} ->
{ok, S};
{error, _} ->
{error, input}
end.
-spec handle_transform(answer(), survey()) -> answer().
handle_transform(A, Q) ->
case Q of
{question, _, _, _, _, Transform} ->
case Transform of
none ->
A;
{some, Tr} ->
case A of
{string_answer, S} ->
{string_answer, Tr(S)};
_ ->
{answer_error, invalid_type}
end
end;
{confirmation, _, _, _, Transform@1} ->
case Transform@1 of
none ->
A;
{some, Tr@1} ->
case A of
{bool_answer, S@1} ->
{bool_answer, Tr@1(S@1)};
_ ->
{answer_error, invalid_type}
end
end
end.
-spec confirm_prompt(gleam@option:option(boolean())) -> binary().
confirm_prompt(Default) ->
case Default of
{some, Default_true} when Default_true ->
<<" [Y/n] "/utf8>>;
{some, _} ->
<<" [y/N] "/utf8>>;
none ->
<<" [y/n] "/utf8>>
end.
-spec handle_input(binary(), survey()) -> answer().
handle_input(Input, Q) ->
_pipe = case Q of
{question, _, _, _, Validate, _} ->
Validate_fn = case Validate of
{some, Val_fn} ->
Val_fn;
none ->
fun(_) -> true end
end,
case Input of
<<""/utf8>> ->
handle_default(Q);
_ ->
case Validate_fn(Input) of
true ->
{string_answer, Input};
false ->
ask(Q, true)
end
end;
{confirmation, _, _, _, _} ->
case Input of
<<"Y"/utf8>> ->
{bool_answer, true};
<<"y"/utf8>> ->
{bool_answer, true};
<<"N"/utf8>> ->
{bool_answer, false};
<<"n"/utf8>> ->
{bool_answer, false};
<<""/utf8>> ->
handle_default(Q);
_ ->
ask(Q, true)
end
end,
handle_transform(_pipe, Q).
-spec ask(survey(), boolean()) -> answer().
ask(Q, Help) ->
ask_fn(Q, fun default_get_line/1, Help).
-spec ask_fn(
survey(),
fun((binary()) -> {ok, binary()} | {error, ask_error()}),
boolean()
) -> answer().
ask_fn(Q, Get_line, Help) ->
Input = begin
_pipe = (<<(case erlang:element(3, Q) of
{some, Help_msg} when Help ->
<<Help_msg/binary, "\n"/utf8>>;
none ->
<<""/utf8>>;
{some, _} ->
<<""/utf8>>
end)/binary, (case Q of
{question, _, _, _, _, _} ->
<<(erlang:element(2, Q))/binary, " "/utf8>>;
{confirmation, _, _, Default, _} ->
<<(erlang:element(2, Q))/binary,
(confirm_prompt(Default))/binary>>
end)/binary>>),
Get_line(_pipe)
end,
case Input of
{ok, Result} ->
_pipe@1 = Result,
_pipe@2 = gleam@string:trim(_pipe@1),
handle_input(_pipe@2, Q);
{error, _} ->
{answer_error, input}
end.
-spec ask_many_loop(
list({binary(), survey()}),
list(fun((binary()) -> {ok, binary()} | {error, ask_error()})),
boolean()
) -> list({binary(), answer()}).
ask_many_loop(Qs, Get_lines, Help) ->
F = fun(Qs@1, Get_line, Get_lines@1) -> case Qs@1 of
[] ->
[];
[{Key, Q}] ->
[{Key, ask_fn(Q, Get_line, Help)}];
[{Key@1, Q@1} | Tail] ->
[{Key@1, ask_fn(Q@1, Get_line, Help)} |
ask_many_loop(Tail, Get_lines@1, Help)]
end end,
case Get_lines of
[] ->
F(Qs, fun default_get_line/1, []);
[Get_line@1 | Get_lines_tail] ->
F(Qs, Get_line@1, Get_lines_tail)
end.
-spec ask_many_fn(
list({binary(), survey()}),
list(fun((binary()) -> {ok, binary()} | {error, ask_error()})),
boolean()
) -> list({binary(), answer()}).
ask_many_fn(Qs, Get_lines, Help) ->
ask_many_loop(Qs, Get_lines, Help).
-spec ask_many(list({binary(), survey()}), boolean()) -> list({binary(),
answer()}).
ask_many(Qs, Help) ->
ask_many_fn(Qs, [], Help).
-spec handle_default(survey()) -> answer().
handle_default(Q) ->
case Q of
{question, _, _, Default, _, _} ->
case Default of
{some, Def} ->
{string_answer, Def};
none ->
ask(Q, true)
end;
{confirmation, _, _, Default@1, _} ->
case Default@1 of
{some, Def@1} ->
{bool_answer, Def@1};
none ->
ask(Q, true)
end
end.