-module(glint). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([pretty_help/2, name/2, as_module/1, command_help/2, unnamed_args/2, named_arg/2, default_pretty_help/0, each/1, constraint/2, flag_help/2, default/2, flag/3, command/1, group_flag/4, get_int/2, int/0, get_ints/2, get_bool/2, get_string/2, string/0, add/3, one_of/1, none_of/1, ints/0, bool/0, get_strings/2, strings/0, get_float/2, float/0, get_floats/2, floats/0, new/0, update_flags/2, execute/2, run_and_handle/3, run/2]). -export_type([config/0, pretty_help/0, glint/1, args_count/0, command/1, named_args/0, command_node/1, out/1, metadata/0, flag_help/0, command_help/0, value/0, flag/1, flag_internals/1, flag_entry/0, flags/0]). -type config() :: {config, gleam@option:option(pretty_help()), gleam@option:option(binary()), boolean()}. -type pretty_help() :: {pretty_help, gleam_community@colour:colour(), gleam_community@colour:colour(), gleam_community@colour:colour()}. -opaque glint(FVQ) :: {glint, config(), command_node(FVQ)}. -type args_count() :: {eq_args, integer()} | {min_args, integer()}. -opaque command(FVR) :: {command, fun((named_args(), list(binary()), flags()) -> FVR), flags(), binary(), gleam@option:option(args_count()), list(binary())}. -opaque named_args() :: {named_args, gleam@dict:dict(binary(), binary())}. -type command_node(FVS) :: {command_node, gleam@option:option(command(FVS)), gleam@dict:dict(binary(), command_node(FVS)), flags()}. -type out(FVT) :: {out, FVT} | {help, binary()}. -type metadata() :: {metadata, binary(), binary()}. -type flag_help() :: {flag_help, metadata(), binary()}. -type command_help() :: {command_help, metadata(), list(flag_help()), list(metadata()), gleam@option:option(args_count()), list(binary())}. -type value() :: {b, flag_internals(boolean())} | {i, flag_internals(integer())} | {li, flag_internals(list(integer()))} | {f, flag_internals(float())} | {lf, flag_internals(list(float()))} | {s, flag_internals(binary())} | {ls, flag_internals(list(binary()))}. -opaque flag(FVU) :: {flag, binary(), fun((binary()) -> {ok, FVU} | {error, snag:snag()}), fun((flag_internals(FVU)) -> value()), fun((flags(), binary()) -> {ok, FVU} | {error, snag:snag()}), gleam@option:option(FVU)}. -type flag_internals(FVV) :: {flag_internals, gleam@option:option(FVV), fun((binary()) -> {ok, FVV} | {error, snag:snag()})}. -type flag_entry() :: {flag_entry, value(), binary()}. -opaque flags() :: {flags, gleam@dict:dict(binary(), flag_entry())}. -spec config(glint(FWI), config()) -> glint(FWI). config(Glint, Config) -> erlang:setelement(2, Glint, Config). -spec pretty_help(glint(FWL), pretty_help()) -> glint(FWL). pretty_help(Glint, Pretty) -> config( Glint, erlang:setelement(2, erlang:element(2, Glint), {some, Pretty}) ). -spec name(glint(FWO), binary()) -> glint(FWO). name(Glint, Name) -> config(Glint, erlang:setelement(3, erlang:element(2, Glint), {some, Name})). -spec as_module(glint(FWR)) -> glint(FWR). as_module(Glint) -> config(Glint, erlang:setelement(4, erlang:element(2, Glint), true)). -spec command_help(binary(), fun(() -> command(FXN))) -> command(FXN). command_help(Desc, F) -> erlang:setelement(4, F(), Desc). -spec unnamed_args(args_count(), fun(() -> command(FXQ))) -> command(FXQ). unnamed_args(Args, F) -> erlang:setelement(5, F(), {some, Args}). -spec named_arg( binary(), fun((fun((named_args()) -> binary())) -> command(FXT)) ) -> command(FXT). named_arg(Name, F) -> Cmd = F( fun(Named_args) -> _assert_subject = gleam@dict:get( erlang:element(2, Named_args), Name ), {ok, Arg} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"glint"/utf8>>, function => <<"named_arg"/utf8>>, line => 243}) end, Arg end ), erlang:setelement(6, Cmd, [Name | erlang:element(6, Cmd)]). -spec default_pretty_help() -> pretty_help(). default_pretty_help() -> _assert_subject = gleam_community@colour:from_rgb255(182, 255, 234), {ok, Usage_colour} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"glint"/utf8>>, function => <<"default_pretty_help"/utf8>>, line => 489}) end, _assert_subject@1 = gleam_community@colour:from_rgb255(255, 175, 243), {ok, Flags_colour} = case _assert_subject@1 of {ok, _} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@1, module => <<"glint"/utf8>>, function => <<"default_pretty_help"/utf8>>, line => 490}) end, _assert_subject@2 = gleam_community@colour:from_rgb255(252, 226, 174), {ok, Subcommands_colour} = case _assert_subject@2 of {ok, _} -> _assert_subject@2; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@2, module => <<"glint"/utf8>>, function => <<"default_pretty_help"/utf8>>, line => 491}) end, {pretty_help, Usage_colour, Flags_colour, Subcommands_colour}. -spec is_not_empty(binary()) -> boolean(). is_not_empty(S) -> S /= <<""/utf8>>. -spec heading_style(binary(), gleam_community@colour:colour()) -> binary(). heading_style(Heading, Colour) -> _pipe = Heading, _pipe@1 = gleam_community@ansi:bold(_pipe), _pipe@2 = gleam_community@ansi:underline(_pipe@1), _pipe@3 = gleam_community@ansi:italic(_pipe@2), _pipe@4 = gleam_community@ansi:hex( _pipe@3, gleam_community@colour:to_rgb_hex(Colour) ), gleam_community@ansi:reset(_pipe@4). -spec flag_type_info(flag_entry()) -> binary(). flag_type_info(Flag) -> case erlang:element(2, Flag) of {i, _} -> <<"INT"/utf8>>; {b, _} -> <<"BOOL"/utf8>>; {f, _} -> <<"FLOAT"/utf8>>; {lf, _} -> <<"FLOAT_LIST"/utf8>>; {li, _} -> <<"INT_LIST"/utf8>>; {ls, _} -> <<"STRING_LIST"/utf8>>; {s, _} -> <<"STRING"/utf8>> end. -spec build_subcommands_help(gleam@dict:dict(binary(), command_node(any()))) -> list(metadata()). build_subcommands_help(Subcommands) -> gleam@dict:fold( Subcommands, [], fun(Acc, Name, Cmd) -> [{metadata, Name, begin _pipe = erlang:element(2, Cmd), _pipe@1 = gleam@option:map( _pipe, fun(Command) -> erlang:element(4, Command) end ), gleam@option:unwrap(_pipe@1, <<""/utf8>>) end} | Acc] end ). -spec subcommand_help_to_string(metadata()) -> binary(). subcommand_help_to_string(Help) -> case erlang:element(3, Help) of <<""/utf8>> -> erlang:element(2, Help); _ -> <<<<(erlang:element(2, Help))/binary, "\t\t"/utf8>>/binary, (erlang:element(3, Help))/binary>> end. -spec string_map(binary(), fun((binary()) -> binary())) -> binary(). string_map(S, F) -> case S of <<""/utf8>> -> <<""/utf8>>; _ -> F(S) end. -spec each(fun((GAH) -> {ok, GAH} | {error, snag:snag()})) -> fun((list(GAH)) -> {ok, list(GAH)} | {error, snag:snag()}). each(Constraint) -> fun(L) -> _pipe = L, _pipe@1 = gleam@list:try_map(_pipe, Constraint), gleam@result:replace(_pipe@1, L) end. -spec new_builder( fun((flag_internals(GAV)) -> value()), fun((flags(), binary()) -> {ok, GAV} | {error, snag:snag()}), fun((binary()) -> {ok, GAV} | {error, snag:snag()}) ) -> flag(GAV). new_builder(Valuer, Getter, P) -> {flag, <<""/utf8>>, P, Valuer, Getter, none}. -spec build_flag(flag(any())) -> flag_entry(). build_flag(Fb) -> {flag_entry, (erlang:element(4, Fb))( {flag_internals, erlang:element(6, Fb), erlang:element(3, Fb)} ), erlang:element(2, Fb)}. -spec attempt( {ok, GBN} | {error, GBO}, fun((GBN) -> {ok, any()} | {error, GBO}) ) -> {ok, GBN} | {error, GBO}. attempt(Val, F) -> gleam@result:'try'(Val, fun(A) -> gleam@result:replace(F(A), A) end). -spec wrap_with_constraint( fun((binary()) -> {ok, GBH} | {error, snag:snag()}), fun((GBH) -> {ok, GBH} | {error, snag:snag()}) ) -> fun((binary()) -> {ok, GBH} | {error, snag:snag()}). wrap_with_constraint(P, Constraint) -> fun(Input) -> attempt(P(Input), Constraint) end. -spec constraint(flag(GBD), fun((GBD) -> {ok, GBD} | {error, snag:snag()})) -> flag(GBD). constraint(Builder, Constraint) -> erlang:setelement( 3, Builder, wrap_with_constraint(erlang:element(3, Builder), Constraint) ). -spec flag_help(flag(GBW), binary()) -> flag(GBW). flag_help(Builder, Description) -> erlang:setelement(2, Builder, Description). -spec default(flag(GBZ), GBZ) -> flag(GBZ). default(Builder, Default) -> erlang:setelement(6, Builder, {some, Default}). -spec insert(flags(), binary(), flag_entry()) -> flags(). insert(Flags, Name, Flag) -> {flags, gleam@dict:insert(erlang:element(2, Flags), Name, Flag)}. -spec flag( binary(), flag(FXW), fun((fun((flags()) -> {ok, FXW} | {error, snag:snag()})) -> command(FXZ)) ) -> command(FXZ). flag(Name, Builder, F) -> Cmd = F(fun(_capture) -> (erlang:element(5, Builder))(_capture, Name) end), erlang:setelement( 3, Cmd, insert(erlang:element(3, Cmd), Name, build_flag(Builder)) ). -spec merge(flags(), flags()) -> flags(). merge(A, B) -> {flags, gleam@dict:merge(erlang:element(2, A), erlang:element(2, B))}. -spec fold(flags(), GCC, fun((GCC, binary(), flag_entry()) -> GCC)) -> GCC. fold(Flags, Acc, F) -> gleam@dict:fold(erlang:element(2, Flags), Acc, F). -spec build_flags_help(flags()) -> list(flag_help()). build_flags_help(Flags) -> fold( Flags, [], fun(Acc, Name, Flag) -> [{flag_help, {metadata, Name, erlang:element(3, Flag)}, flag_type_info(Flag)} | Acc] end ). -spec build_command_help_metadata(binary(), command_node(any())) -> command_help(). build_command_help_metadata(Name, Node) -> {Description, Flags, Unnamed_args, Named_args} = case erlang:element( 2, Node ) of none -> {<<""/utf8>>, [], none, []}; {some, Cmd} -> {erlang:element(4, Cmd), build_flags_help( merge(erlang:element(4, Node), erlang:element(3, Cmd)) ), erlang:element(5, Cmd), erlang:element(6, Cmd)} end, {command_help, {metadata, Name, Description}, Flags, build_subcommands_help(erlang:element(3, Node)), Unnamed_args, Named_args}. -spec new_flags() -> flags(). new_flags() -> {flags, gleam@dict:new()}. -spec empty_command() -> command_node(any()). empty_command() -> {command_node, none, gleam@dict:new(), new_flags()}. -spec do_add(command_node(FXB), list(binary()), command(FXB)) -> command_node(FXB). do_add(Root, Path, Contents) -> case Path of [] -> erlang:setelement(2, Root, {some, Contents}); [X | Xs] -> erlang:setelement( 3, Root, (gleam@dict:update( erlang:element(3, Root), X, fun(Node) -> _pipe = Node, _pipe@1 = gleam@option:lazy_unwrap( _pipe, fun empty_command/0 ), do_add(_pipe@1, Xs, Contents) end )) ) end. -spec command(fun((named_args(), list(binary()), flags()) -> FXK)) -> command(FXK). command(Runner) -> {command, Runner, new_flags(), <<""/utf8>>, none, []}. -spec do_group_flag(command_node(FYI), list(binary()), binary(), flag_entry()) -> command_node(FYI). do_group_flag(Node, Path, Name, Flag) -> case Path of [] -> erlang:setelement( 4, Node, insert(erlang:element(4, Node), Name, Flag) ); [Head | Tail] -> erlang:setelement( 3, Node, (gleam@dict:update( erlang:element(3, Node), Head, fun(Node@1) -> _pipe = Node@1, _pipe@1 = gleam@option:unwrap(_pipe, empty_command()), do_group_flag(_pipe@1, Tail, Name, Flag) end )) ) end. -spec group_flag(glint(FYC), list(binary()), binary(), flag(any())) -> glint(FYC). group_flag(Glint, Path, Name, Flag) -> erlang:setelement( 3, Glint, do_group_flag(erlang:element(3, Glint), Path, Name, build_flag(Flag)) ). -spec access_type_error(binary()) -> {ok, any()} | {error, snag:snag()}. access_type_error(Flag_type) -> snag:error(<<"cannot access flag as "/utf8, Flag_type/binary>>). -spec flag_not_provided_error() -> {ok, any()} | {error, snag:snag()}. flag_not_provided_error() -> snag:error(<<"no value provided"/utf8>>). -spec construct_value( binary(), flag_internals(GCJ), fun((flag_internals(GCJ)) -> value()) ) -> {ok, value()} | {error, snag:snag()}. construct_value(Input, Internal, Constructor) -> gleam@result:map( (erlang:element(3, Internal))(Input), fun(Val) -> Constructor(erlang:setelement(2, Internal, {some, Val})) end ). -spec compute_flag(binary(), value()) -> {ok, value()} | {error, snag:snag()}. compute_flag(Input, Current) -> _pipe = Input, _pipe@1 = case Current of {i, Internal} -> fun(_capture) -> construct_value( _capture, Internal, fun(Field@0) -> {i, Field@0} end ) end; {li, Internal@1} -> fun(_capture@1) -> construct_value( _capture@1, Internal@1, fun(Field@0) -> {li, Field@0} end ) end; {f, Internal@2} -> fun(_capture@2) -> construct_value( _capture@2, Internal@2, fun(Field@0) -> {f, Field@0} end ) end; {lf, Internal@3} -> fun(_capture@3) -> construct_value( _capture@3, Internal@3, fun(Field@0) -> {lf, Field@0} end ) end; {s, Internal@4} -> fun(_capture@4) -> construct_value( _capture@4, Internal@4, fun(Field@0) -> {s, Field@0} end ) end; {ls, Internal@5} -> fun(_capture@5) -> construct_value( _capture@5, Internal@5, fun(Field@0) -> {ls, Field@0} end ) end; {b, Internal@6} -> fun(_capture@6) -> construct_value( _capture@6, Internal@6, fun(Field@0) -> {b, Field@0} end ) end end(_pipe), snag:context(_pipe@1, <<"failed to compute value for flag"/utf8>>). -spec layer_invalid_flag(snag:snag(), binary()) -> snag:snag(). layer_invalid_flag(Err, Flag) -> snag:layer(Err, <<<<"invalid flag '"/utf8, Flag/binary>>/binary, "'"/utf8>>). -spec no_value_flag_err(binary()) -> snag:snag(). no_value_flag_err(Flag_input) -> _pipe = (<<<<"flag '"/utf8, Flag_input/binary>>/binary, "' has no assigned value"/utf8>>), _pipe@1 = snag:new(_pipe), layer_invalid_flag(_pipe@1, Flag_input). -spec undefined_flag_err(binary()) -> snag:snag(). undefined_flag_err(Key) -> _pipe = <<"flag provided but not defined"/utf8>>, _pipe@1 = snag:new(_pipe), layer_invalid_flag(_pipe@1, Key). -spec cannot_parse(binary(), binary()) -> snag:snag(). cannot_parse(Value, Kind) -> _pipe = (<<<<<<"cannot parse value '"/utf8, Value/binary>>/binary, "' as "/utf8>>/binary, Kind/binary>>), snag:new(_pipe). -spec get(flags(), binary()) -> {ok, flag_entry()} | {error, snag:snag()}. get(Flags, Name) -> _pipe = gleam@dict:get(erlang:element(2, Flags), Name), gleam@result:replace_error(_pipe, undefined_flag_err(Name)). -spec update_flag_value(flags(), {binary(), binary()}) -> {ok, flags()} | {error, snag:snag()}. update_flag_value(Flags, Data) -> {Key, Input} = Data, gleam@result:'try'( get(Flags, Key), fun(Contents) -> gleam@result:map( begin _pipe = compute_flag(Input, erlang:element(2, Contents)), gleam@result:map_error( _pipe, fun(_capture) -> layer_invalid_flag(_capture, Key) end ) end, fun(Value) -> insert(Flags, Key, erlang:setelement(2, Contents, Value)) end ) end ). -spec attempt_toggle_flag(flags(), binary()) -> {ok, flags()} | {error, snag:snag()}. attempt_toggle_flag(Flags, Key) -> gleam@result:'try'( get(Flags, Key), fun(Contents) -> case erlang:element(2, Contents) of {b, {flag_internals, none, _} = Internal} -> _pipe = erlang:setelement(2, Internal, {some, true}), _pipe@1 = {b, _pipe}, _pipe@2 = (fun(Val) -> erlang:setelement(2, Contents, Val) end)(_pipe@1), _pipe@3 = gleam@dict:insert( erlang:element(2, Flags), Key, _pipe@2 ), _pipe@4 = {flags, _pipe@3}, {ok, _pipe@4}; {b, {flag_internals, {some, Val@1}, _} = Internal@1} -> _pipe@5 = erlang:setelement( 2, Internal@1, {some, not Val@1} ), _pipe@6 = {b, _pipe@5}, _pipe@7 = (fun(Val@2) -> erlang:setelement(2, Contents, Val@2) end)(_pipe@6), _pipe@8 = gleam@dict:insert( erlang:element(2, Flags), Key, _pipe@7 ), _pipe@9 = {flags, _pipe@8}, {ok, _pipe@9}; _ -> {error, no_value_flag_err(Key)} end end ). -spec get_value( flags(), binary(), fun((flag_entry()) -> {ok, GCP} | {error, snag:snag()}) ) -> {ok, GCP} | {error, snag:snag()}. get_value(Flags, Key, Kind) -> _pipe = get(Flags, Key), _pipe@1 = gleam@result:'try'(_pipe, Kind), snag:context( _pipe@1, <<<<"failed to retrieve value for flag '"/utf8, Key/binary>>/binary, "'"/utf8>> ). -spec get_int_value(flag_entry()) -> {ok, integer()} | {error, snag:snag()}. get_int_value(Flag) -> case erlang:element(2, Flag) of {i, {flag_internals, {some, Val}, _}} -> {ok, Val}; {i, {flag_internals, none, _}} -> flag_not_provided_error(); _ -> access_type_error(<<"int"/utf8>>) end. -spec get_int(flags(), binary()) -> {ok, integer()} | {error, snag:snag()}. get_int(Flags, Name) -> get_value(Flags, Name, fun get_int_value/1). -spec int() -> flag(integer()). int() -> new_builder( fun(Field@0) -> {i, Field@0} end, fun get_int/2, fun(Input) -> _pipe = Input, _pipe@1 = gleam@int:parse(_pipe), gleam@result:replace_error( _pipe@1, cannot_parse(Input, <<"int"/utf8>>) ) end ). -spec args_compare(args_count(), integer()) -> {ok, nil} | {error, snag:snag()}. args_compare(Expected, Actual) -> _pipe = case Expected of {eq_args, Expected@1} when Actual =:= Expected@1 -> {ok, nil}; {min_args, Expected@2} when Actual >= Expected@2 -> {ok, nil}; {eq_args, Expected@3} -> {error, gleam@int:to_string(Expected@3)}; {min_args, Expected@4} -> {error, <<"at least "/utf8, (gleam@int:to_string(Expected@4))/binary>>} end, gleam@result:map_error( _pipe, fun(Err) -> snag:new( <<<<<<"expected: "/utf8, Err/binary>>/binary, " argument(s), provided: "/utf8>>/binary, (gleam@int:to_string(Actual))/binary>> ) end ). -spec args_count_to_usage_string(args_count()) -> binary(). args_count_to_usage_string(Count) -> case Count of {eq_args, 0} -> <<""/utf8>>; {eq_args, 1} -> <<"[ 1 argument ]"/utf8>>; {eq_args, N} -> <<<<"[ "/utf8, (gleam@int:to_string(N))/binary>>/binary, " arguments ]"/utf8>>; {min_args, N@1} -> <<<<"[ "/utf8, (gleam@int:to_string(N@1))/binary>>/binary, " or more arguments ]"/utf8>> end. -spec get_ints_value(flag_entry()) -> {ok, list(integer())} | {error, snag:snag()}. get_ints_value(Flag) -> case erlang:element(2, Flag) of {li, {flag_internals, {some, Val}, _}} -> {ok, Val}; {li, {flag_internals, none, _}} -> flag_not_provided_error(); _ -> access_type_error(<<"int list"/utf8>>) end. -spec get_ints(flags(), binary()) -> {ok, list(integer())} | {error, snag:snag()}. get_ints(Flags, Name) -> get_value(Flags, Name, fun get_ints_value/1). -spec get_bool_value(flag_entry()) -> {ok, boolean()} | {error, snag:snag()}. get_bool_value(Flag) -> case erlang:element(2, Flag) of {b, {flag_internals, {some, Val}, _}} -> {ok, Val}; {b, {flag_internals, none, _}} -> flag_not_provided_error(); _ -> access_type_error(<<"bool"/utf8>>) end. -spec get_bool(flags(), binary()) -> {ok, boolean()} | {error, snag:snag()}. get_bool(Flags, Name) -> get_value(Flags, Name, fun get_bool_value/1). -spec get_string_value(flag_entry()) -> {ok, binary()} | {error, snag:snag()}. get_string_value(Flag) -> case erlang:element(2, Flag) of {s, {flag_internals, {some, Val}, _}} -> {ok, Val}; {s, {flag_internals, none, _}} -> flag_not_provided_error(); _ -> access_type_error(<<"string"/utf8>>) end. -spec get_string(flags(), binary()) -> {ok, binary()} | {error, snag:snag()}. get_string(Flags, Name) -> get_value(Flags, Name, fun get_string_value/1). -spec string() -> flag(binary()). string() -> new_builder( fun(Field@0) -> {s, Field@0} end, fun get_string/2, fun(S) -> {ok, S} end ). -spec sanitize_path(list(binary())) -> list(binary()). sanitize_path(Path) -> _pipe = Path, _pipe@1 = gleam@list:map(_pipe, fun gleam@string:trim/1), gleam@list:filter(_pipe@1, fun is_not_empty/1). -spec add(glint(FWW), list(binary()), command(FWW)) -> glint(FWW). add(Glint, Path, Contents) -> erlang:setelement( 3, Glint, begin _pipe = Path, _pipe@1 = sanitize_path(_pipe), do_add(erlang:element(3, Glint), _pipe@1, Contents) end ). -spec one_of(list(GAB)) -> fun((GAB) -> {ok, GAB} | {error, snag:snag()}). one_of(Allowed) -> Allowed_set = gleam@set:from_list(Allowed), fun(Val) -> case gleam@set:contains(Allowed_set, Val) of true -> {ok, Val}; false -> snag:error( <<<<<<<<"invalid value '"/utf8, (gleam@string:inspect(Val))/binary>>/binary, "', must be one of: ["/utf8>>/binary, (begin _pipe = Allowed, _pipe@1 = gleam@list:map( _pipe, fun(A) -> <<<<"'"/utf8, (gleam@string:inspect(A))/binary>>/binary, "'"/utf8>> end ), gleam@string:join(_pipe@1, <<", "/utf8>>) end)/binary>>/binary, "]"/utf8>> ) end end. -spec none_of(list(GAE)) -> fun((GAE) -> {ok, GAE} | {error, snag:snag()}). none_of(Disallowed) -> Disallowed_set = gleam@set:from_list(Disallowed), fun(Val) -> case gleam@set:contains(Disallowed_set, Val) of false -> {ok, Val}; true -> snag:error( <<<<<<"invalid value '"/utf8, (gleam@string:inspect(Val))/binary>>/binary, "', must not be one of: ["/utf8>>/binary, (((<<(begin _pipe = Disallowed, _pipe@1 = gleam@list:map( _pipe, fun(A) -> <<<<"'"/utf8, (gleam@string:inspect(A))/binary>>/binary, "'"/utf8>> end ), gleam@string:join(_pipe@1, <<", "/utf8>>) end)/binary, "]"/utf8>>)))/binary>> ) end end. -spec ints() -> flag(list(integer())). ints() -> new_builder( fun(Field@0) -> {li, Field@0} end, fun get_ints/2, fun(Input) -> _pipe = Input, _pipe@1 = gleam@string:split(_pipe, <<","/utf8>>), _pipe@2 = gleam@list:try_map(_pipe@1, fun gleam@int:parse/1), gleam@result:replace_error( _pipe@2, cannot_parse(Input, <<"int list"/utf8>>) ) end ). -spec bool() -> flag(boolean()). bool() -> new_builder( fun(Field@0) -> {b, Field@0} end, fun get_bool/2, fun(Input) -> case gleam@string:lowercase(Input) of <<"true"/utf8>> -> {ok, true}; <<"t"/utf8>> -> {ok, true}; <<"false"/utf8>> -> {ok, false}; <<"f"/utf8>> -> {ok, false}; _ -> {error, cannot_parse(Input, <<"bool"/utf8>>)} end end ). -spec get_strings_value(flag_entry()) -> {ok, list(binary())} | {error, snag:snag()}. get_strings_value(Flag) -> case erlang:element(2, Flag) of {ls, {flag_internals, {some, Val}, _}} -> {ok, Val}; {ls, {flag_internals, none, _}} -> flag_not_provided_error(); _ -> access_type_error(<<"string list"/utf8>>) end. -spec get_strings(flags(), binary()) -> {ok, list(binary())} | {error, snag:snag()}. get_strings(Flags, Name) -> get_value(Flags, Name, fun get_strings_value/1). -spec strings() -> flag(list(binary())). strings() -> new_builder( fun(Field@0) -> {ls, Field@0} end, fun get_strings/2, fun(Input) -> _pipe = Input, _pipe@1 = gleam@string:split(_pipe, <<","/utf8>>), {ok, _pipe@1} end ). -spec get_float_value(flag_entry()) -> {ok, float()} | {error, snag:snag()}. get_float_value(Flag) -> case erlang:element(2, Flag) of {f, {flag_internals, {some, Val}, _}} -> {ok, Val}; {f, {flag_internals, none, _}} -> flag_not_provided_error(); _ -> access_type_error(<<"float"/utf8>>) end. -spec get_float(flags(), binary()) -> {ok, float()} | {error, snag:snag()}. get_float(Flags, Name) -> get_value(Flags, Name, fun get_float_value/1). -spec float() -> flag(float()). float() -> new_builder( fun(Field@0) -> {f, Field@0} end, fun get_float/2, fun(Input) -> _pipe = Input, _pipe@1 = gleam@float:parse(_pipe), gleam@result:replace_error( _pipe@1, cannot_parse(Input, <<"float"/utf8>>) ) end ). -spec get_floats_value(flag_entry()) -> {ok, list(float())} | {error, snag:snag()}. get_floats_value(Flag) -> case erlang:element(2, Flag) of {lf, {flag_internals, {some, Val}, _}} -> {ok, Val}; {lf, {flag_internals, none, _}} -> flag_not_provided_error(); _ -> access_type_error(<<"float list"/utf8>>) end. -spec get_floats(flags(), binary()) -> {ok, list(float())} | {error, snag:snag()}. get_floats(Flags, Name) -> get_value(Flags, Name, fun get_floats_value/1). -spec floats() -> flag(list(float())). floats() -> new_builder( fun(Field@0) -> {lf, Field@0} end, fun get_floats/2, fun(Input) -> _pipe = Input, _pipe@1 = gleam@string:split(_pipe, <<","/utf8>>), _pipe@2 = gleam@list:try_map(_pipe@1, fun gleam@float:parse/1), gleam@result:replace_error( _pipe@2, cannot_parse(Input, <<"float list"/utf8>>) ) end ). -spec new() -> glint(any()). new() -> {glint, {config, none, none, false}, empty_command()}. -spec subcommands_help_to_string(list(metadata()), config()) -> binary(). subcommands_help_to_string(Help, Config) -> gleam@bool:guard( Help =:= [], <<""/utf8>>, fun() -> <<(case erlang:element(2, Config) of none -> <<"SUBCOMMANDS:"/utf8>>; {some, Pretty} -> heading_style( <<"SUBCOMMANDS:"/utf8>>, erlang:element(4, Pretty) ) end)/binary, (begin _pipe = Help, _pipe@1 = gleam@list:map( _pipe, fun subcommand_help_to_string/1 ), _pipe@2 = gleam@list:sort( _pipe@1, fun gleam@string:compare/2 ), _pipe@3 = gleam@list:map( _pipe@2, fun(_capture) -> gleam@string:append(<<"\n\t"/utf8>>, _capture) end ), gleam@string:concat(_pipe@3) end)/binary>> end ). -spec help_flag() -> binary(). help_flag() -> <<"--"/utf8, "help"/utf8>>. -spec flag_help_to_string(flag_help()) -> binary(). flag_help_to_string(Help) -> <<<<<<<<"--"/utf8, (erlang:element(2, erlang:element(2, Help)))/binary>>/binary, "=<"/utf8>>/binary, (erlang:element(3, Help))/binary>>/binary, ">"/utf8>>. -spec flags_help_to_usage_strings(list(flag_help())) -> list(binary()). flags_help_to_usage_strings(Help) -> _pipe = Help, _pipe@1 = gleam@list:map(_pipe, fun flag_help_to_string/1), gleam@list:sort(_pipe@1, fun gleam@string:compare/2). -spec flags_help_to_usage_string(list(flag_help())) -> binary(). flags_help_to_usage_string(Help) -> gleam@bool:guard(Help =:= [], <<""/utf8>>, fun() -> _pipe = Help, _pipe@1 = flags_help_to_usage_strings(_pipe), _pipe@2 = gleam@list:intersperse(_pipe@1, <<" "/utf8>>), _pipe@3 = gleam@string_builder:from_strings(_pipe@2), _pipe@4 = gleam@string_builder:prepend(_pipe@3, <<"[ "/utf8>>), _pipe@5 = gleam@string_builder:append(_pipe@4, <<" ]"/utf8>>), gleam@string_builder:to_string(_pipe@5) end). -spec command_help_to_usage_string(command_help(), config()) -> binary(). command_help_to_usage_string(Help, Config) -> App_name = case erlang:element(3, Config) of {some, Name} when erlang:element(4, Config) -> <<"gleam run -m "/utf8, Name/binary>>; {some, Name@1} -> Name@1; none -> <<"gleam run"/utf8>> end, Flags = flags_help_to_usage_string(erlang:element(3, Help)), Subcommands = begin _pipe = gleam@list:map( erlang:element(4, Help), fun(Sc) -> erlang:element(2, Sc) end ), _pipe@1 = gleam@list:sort(_pipe, fun gleam@string:compare/2), _pipe@2 = gleam@string:join(_pipe@1, <<" | "/utf8>>), _pipe@3 = string_map( _pipe@2, fun(_capture) -> gleam@string:append(<<"( "/utf8>>, _capture) end ), string_map( _pipe@3, fun(_capture@1) -> gleam@string:append(_capture@1, <<" )"/utf8>>) end ) end, Named_args = begin _pipe@4 = erlang:element(6, Help), _pipe@5 = gleam@list:map( _pipe@4, fun(S) -> <<<<"<"/utf8, S/binary>>/binary, ">"/utf8>> end ), gleam@string:join(_pipe@5, <<" "/utf8>>) end, Unnamed_args = begin _pipe@6 = gleam@option:map( erlang:element(5, Help), fun args_count_to_usage_string/1 ), gleam@option:unwrap(_pipe@6, <<"[ ARGS ]"/utf8>>) end, <<<<<<<<<<<<<<(case erlang:element(2, Config) of none -> <<"USAGE:"/utf8>>; {some, Pretty} -> heading_style( <<"USAGE:"/utf8>>, erlang:element(2, Pretty) ) end)/binary, "\n\t"/utf8>>/binary, App_name/binary>>/binary, (string_map( erlang:element(2, erlang:element(2, Help)), fun(_capture@2) -> gleam@string:append(<<" "/utf8>>, _capture@2) end ))/binary>>/binary, (string_map( Subcommands, fun(_capture@3) -> gleam@string:append(<<" "/utf8>>, _capture@3) end ))/binary>>/binary, (string_map( Named_args, fun(_capture@4) -> gleam@string:append(<<" "/utf8>>, _capture@4) end ))/binary>>/binary, (string_map( Unnamed_args, fun(_capture@5) -> gleam@string:append(<<" "/utf8>>, _capture@5) end ))/binary>>/binary, (string_map( Flags, fun(_capture@6) -> gleam@string:append(<<" "/utf8>>, _capture@6) end ))/binary>>. -spec flag_help_to_string_with_description(flag_help()) -> binary(). flag_help_to_string_with_description(Help) -> <<<<(flag_help_to_string(Help))/binary, "\t\t"/utf8>>/binary, (erlang:element(3, erlang:element(2, Help)))/binary>>. -spec flags_help_to_string(list(flag_help()), config()) -> binary(). flags_help_to_string(Help, Config) -> gleam@bool:guard( Help =:= [], <<""/utf8>>, fun() -> <<(case erlang:element(2, Config) of none -> <<"FLAGS:"/utf8>>; {some, Pretty} -> heading_style( <<"FLAGS:"/utf8>>, erlang:element(3, Pretty) ) end)/binary, (begin _pipe = [<<"--help\t\t\tPrint help information"/utf8>> | gleam@list:map( Help, fun flag_help_to_string_with_description/1 )], _pipe@1 = gleam@list:sort(_pipe, fun gleam@string:compare/2), _pipe@2 = gleam@list:map( _pipe@1, fun(_capture) -> gleam@string:append(<<"\n\t"/utf8>>, _capture) end ), gleam@string:concat(_pipe@2) end)/binary>> end ). -spec command_help_to_string(command_help(), config()) -> binary(). command_help_to_string(Help, Config) -> Header_items = begin _pipe = [erlang:element(2, erlang:element(2, Help)), erlang:element(3, erlang:element(2, Help))], _pipe@1 = gleam@list:filter(_pipe, fun is_not_empty/1), gleam@string:join(_pipe@1, <<"\n"/utf8>>) end, _pipe@2 = [Header_items, command_help_to_usage_string(Help, Config), flags_help_to_string(erlang:element(3, Help), Config), subcommands_help_to_string(erlang:element(4, Help), Config)], _pipe@3 = gleam@list:filter(_pipe@2, fun is_not_empty/1), gleam@string:join(_pipe@3, <<"\n\n"/utf8>>). -spec cmd_help(list(binary()), command_node(any()), config()) -> binary(). cmd_help(Path, Cmd, Config) -> _pipe = Path, _pipe@1 = gleam@list:reverse(_pipe), _pipe@2 = gleam@string:join(_pipe@1, <<" "/utf8>>), _pipe@3 = build_command_help_metadata(_pipe@2, Cmd), command_help_to_string(_pipe@3, Config). -spec update_flags(flags(), binary()) -> {ok, flags()} | {error, snag:snag()}. update_flags(Flags, Flag_input) -> Flag_input@1 = gleam@string:drop_left( Flag_input, gleam@string:length(<<"--"/utf8>>) ), case gleam@string:split_once(Flag_input@1, <<"="/utf8>>) of {ok, Data} -> update_flag_value(Flags, Data); {error, _} -> attempt_toggle_flag(Flags, Flag_input@1) end. -spec execute_root( list(binary()), config(), command_node(FYY), list(binary()), list(binary()) ) -> {ok, out(FYY)} | {error, binary()}. execute_root(Path, Config, Cmd, Args, Flag_inputs) -> Res = begin _pipe@5 = (gleam@option:map( erlang:element(2, Cmd), fun(Contents) -> gleam@result:'try'( gleam@list:try_fold( Flag_inputs, merge( erlang:element(4, Cmd), erlang:element(3, Contents) ), fun update_flags/2 ), fun(New_flags) -> gleam@result:'try'( begin Named = gleam@list:zip( erlang:element(6, Contents), Args ), case gleam@list:length(Named) =:= gleam@list:length( erlang:element(6, Contents) ) of true -> {ok, maps:from_list(Named)}; false -> snag:error( <<"unmatched named arguments: "/utf8, (begin _pipe = erlang:element( 6, Contents ), _pipe@1 = gleam@list:drop( _pipe, gleam@list:length(Named) ), _pipe@2 = gleam@list:map( _pipe@1, fun(S) -> <<<<"'"/utf8, S/binary>>/binary, "'"/utf8>> end ), gleam@string:join( _pipe@2, <<", "/utf8>> ) end)/binary>> ) end end, fun(Named_args) -> Args@1 = gleam@list:drop( Args, maps:size(Named_args) ), gleam@result:map( case erlang:element(5, Contents) of {some, Count} -> _pipe@3 = Count, _pipe@4 = args_compare( _pipe@3, gleam@list:length(Args@1) ), snag:context( _pipe@4, <<"invalid number of arguments provided"/utf8>> ); none -> {ok, nil} end, fun(_) -> {out, (erlang:element(2, Contents))( {named_args, Named_args}, Args@1, New_flags )} end ) end ) end ) end )), _pipe@6 = gleam@option:unwrap( _pipe@5, snag:error(<<"command not found"/utf8>>) ), _pipe@7 = snag:context(_pipe@6, <<"failed to run command"/utf8>>), gleam@result:map_error( _pipe@7, fun(Err) -> {Err, cmd_help(Path, Cmd, Config)} end ) end, case Res of {ok, Out} -> {ok, Out}; {error, {Snag, Help}} -> {error, <<<<(snag:pretty_print(Snag))/binary, "\nSee the following help text, available via the '--help' flag.\n\n"/utf8>>/binary, Help/binary>>} end. -spec do_execute( command_node(FYQ), config(), list(binary()), list(binary()), boolean(), list(binary()) ) -> {ok, out(FYQ)} | {error, binary()}. do_execute(Cmd, Config, Args, Flags, Help, Command_path) -> case Args of [] when Help -> _pipe = Command_path, _pipe@1 = cmd_help(_pipe, Cmd, Config), _pipe@2 = {help, _pipe@1}, {ok, _pipe@2}; [] -> execute_root(Command_path, Config, Cmd, [], Flags); [Arg | Rest] -> case gleam@dict:get(erlang:element(3, Cmd), Arg) of {ok, Sub_command} -> Sub_command@1 = erlang:setelement( 4, Sub_command, merge( erlang:element(4, Cmd), erlang:element(4, Sub_command) ) ), do_execute( Sub_command@1, Config, Rest, Flags, Help, [Arg | Command_path] ); _ when Help -> _pipe@3 = Command_path, _pipe@4 = cmd_help(_pipe@3, Cmd, Config), _pipe@5 = {help, _pipe@4}, {ok, _pipe@5}; _ -> execute_root(Command_path, Config, Cmd, Args, Flags) end end. -spec execute(glint(FYM), list(binary())) -> {ok, out(FYM)} | {error, binary()}. execute(Glint, Args) -> Help_flag = help_flag(), {Help, Args@2} = case gleam@list:pop(Args, fun(S) -> S =:= Help_flag end) of {ok, {_, Args@1}} -> {true, Args@1}; _ -> {false, Args} end, {Flags, Args@3} = gleam@list:partition( Args@2, fun(_capture) -> gleam@string:starts_with(_capture, <<"--"/utf8>>) end ), do_execute( erlang:element(3, Glint), erlang:element(2, Glint), Args@3, Flags, Help, [] ). -spec run_and_handle(glint(FZG), list(binary()), fun((FZG) -> any())) -> nil. run_and_handle(Glint, Args, Handle) -> case execute(Glint, Args) of {error, S} -> gleam@io:println(S); {ok, {help, S}} -> gleam@io:println(S); {ok, {out, Out}} -> Handle(Out), nil end. -spec run(glint(any()), list(binary())) -> nil. run(Glint, Args) -> run_and_handle(Glint, Args, fun(_) -> nil end).