-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 -> <>; 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.