Packages
glint
0.7.2
1.3.0
1.2.1
1.2.0
1.1.1
1.1.0
1.0.1
1.0.0
1.0.0-rc5
1.0.0-rc4
1.0.0-rc3
1.0.0-rc2
1.0.0-rc1
0.18.1
0.18.0
0.17.1
0.17.0
0.16.0
0.16.0-rc1
0.15.0
0.15.0-rc2
0.15.0-rc1
0.14.0
0.13.0
0.12.0
0.12.0-rc6
0.12.0-rc5
0.12.0-rc4
0.12.0-rc3
0.12.0-rc2
0.12.0-rc1
0.11.4
0.11.3
0.11.2
0.11.0
0.10.0
0.9.0
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Gleam command-line argument parsing with flags and automated help text generation.
Current section
Files
Jump to
Current section
Files
src/glint.erl
-module(glint).
-compile(no_auto_import).
-export([new/0, add_command/6, execute/2, run/2]).
-export_type([command_input/0, description/0, contents/1, command/1, out/1]).
-type command_input() :: {command_input,
list(binary()),
gleam@map:map_(binary(), glint@flag:contents())}.
-type description() :: {description, binary(), binary()}.
-type contents(EKU) :: {contents,
fun((command_input()) -> EKU),
gleam@map:map_(binary(), glint@flag:contents()),
description()}.
-opaque command(EKV) :: {command,
gleam@option:option(contents(EKV)),
gleam@map:map_(binary(), command(EKV))}.
-type out(EKW) :: {out, EKW} | {help, binary()}.
-spec new() -> command(any()).
new() ->
{command, none, gleam@map:new()}.
-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_command(
command(ELQ),
list(binary()),
fun((command_input()) -> ELQ),
list({binary(), glint@flag:contents()}),
binary(),
binary()
) -> command(ELQ).
add_command(Root, Path, F, Flags, Description, Usage) ->
_pipe = Path,
_pipe@1 = sanitize_path(_pipe),
do_add_command(
Root,
_pipe@1,
{contents,
F,
glint@flag:build_map(Flags),
{description, Description, Usage}}
).
-spec do_add_command(command(ELW), list(binary()), contents(ELW)) -> command(ELW).
do_add_command(Root, Path, Contents) ->
case Path of
[] ->
erlang:setelement(2, Root, {some, Contents});
[X | Xs] ->
Update_subcommand = fun(Node) ->
_pipe = Node,
_pipe@1 = gleam@option:lazy_unwrap(_pipe, fun new/0),
do_add_command(_pipe@1, Xs, Contents)
end,
erlang:setelement(
3,
Root,
gleam@map:update(erlang:element(3, Root), X, Update_subcommand)
)
end.
-spec execute_root(command(EMB), list(binary()), list(binary())) -> {ok,
out(EMB)} |
{error, snag:snag()}.
execute_root(Cmd, Args, Flags) ->
case erlang:element(2, Cmd) of
{some, Contents} ->
case begin
_pipe = Flags,
_pipe@1 = gleam@list:try_fold(
_pipe,
erlang:element(3, Contents),
fun glint@flag:update_flags/2
),
snag:context(_pipe@1, <<"failed to run command"/utf8>>)
end of
{error, _try} -> {error, _try};
{ok, New_flags} ->
_pipe@2 = Args,
_pipe@3 = {command_input, _pipe@2, New_flags},
_pipe@4 = (erlang:element(2, Contents))(_pipe@3),
_pipe@5 = {out, _pipe@4},
{ok, _pipe@5}
end;
none ->
_pipe@6 = snag:error(<<"command not found"/utf8>>),
snag:context(_pipe@6, <<"failed to run command"/utf8>>)
end.
-spec execute(command(EMG), list(binary())) -> {ok, out(EMG)} |
{error, snag:snag()}.
execute(Cmd, Args) ->
Help_flag = glint@flag:help_flag(),
{Help, Args@2} = case gleam@list:pop(Args, fun(S) -> S =:= Help_flag end) of
{ok, {_@1, Args@1}} ->
{true, Args@1};
_@2 ->
{false, Args}
end,
{Flags, Args@3} = gleam@list:partition(
Args@2,
fun(_capture) -> gleam@string:starts_with(_capture, <<"--"/utf8>>) end
),
do_execute(Cmd, Args@3, Flags, Help, []).
-spec do_execute(
command(EMK),
list(binary()),
list(binary()),
boolean(),
list(binary())
) -> {ok, out(EMK)} | {error, snag:snag()}.
do_execute(Cmd, Args, Flags, Help, Command_path) ->
case Args of
[] when Help ->
_pipe = Command_path,
_pipe@1 = cmd_help(_pipe, Cmd),
_pipe@2 = {help, _pipe@1},
{ok, _pipe@2};
[] ->
execute_root(Cmd, [], Flags);
[Arg | Rest] ->
case gleam@map:get(erlang:element(3, Cmd), Arg) of
{ok, Cmd@1} ->
do_execute(Cmd@1, Rest, Flags, Help, [Arg | Command_path]);
_@1 when Help ->
_pipe@3 = Command_path,
_pipe@4 = cmd_help(_pipe@3, Cmd),
_pipe@5 = {help, _pipe@4},
{ok, _pipe@5};
_@2 ->
execute_root(Cmd, Args, Flags)
end
end.
-spec run(command(any()), list(binary())) -> nil.
run(Cmd, Args) ->
case execute(Cmd, Args) of
{error, Err} ->
_pipe = Err,
_pipe@1 = snag:pretty_print(_pipe),
gleam@io:println(_pipe@1);
{ok, {help, Help}} ->
gleam@io:println(Help);
_@1 ->
nil
end.
-spec is_not_empty(binary()) -> boolean().
is_not_empty(S) ->
S /= <<""/utf8>>.
-spec cmd_help(list(binary()), command(any())) -> binary().
cmd_help(Path, Command) ->
Name = begin
_pipe = Path,
_pipe@1 = gleam@list:reverse(_pipe),
gleam@string:join(_pipe@1, <<" "/utf8>>)
end,
{Flags@2, Description, Usage@1} = case erlang:element(2, Command) of
none ->
{<<""/utf8>>, <<""/utf8>>, <<""/utf8>>};
{some, {contents, _@1, Flags, Desc}} ->
Flags@1 = begin
_pipe@2 = Flags,
_pipe@3 = glint@flag:flags_help(_pipe@2),
_pipe@4 = append_if_msg_not_empty(<<"\n\t"/utf8>>, _pipe@3),
_pipe@5 = gleam@string:append(
<<"--help\t\t\tPrint help information"/utf8>>,
_pipe@4
),
gleam@string:append(<<"FLAGS:\n\t"/utf8>>, _pipe@5)
end,
Usage = append_if_msg_not_empty(
<<"USAGE:\n\t"/utf8>>,
erlang:element(3, Desc)
),
{Flags@1, erlang:element(2, Desc), Usage}
end,
Header_items = begin
_pipe@6 = [Name, Description],
_pipe@7 = gleam@list:filter(_pipe@6, fun is_not_empty/1),
gleam@string:join(_pipe@7, <<"\n"/utf8>>)
end,
Subcommands = begin
_pipe@8 = erlang:element(3, Command),
_pipe@9 = subcommands_help(_pipe@8),
append_if_msg_not_empty(<<"SUBCOMMANDS:\n\t"/utf8>>, _pipe@9)
end,
_pipe@10 = [Header_items, Usage@1, Flags@2, Subcommands],
_pipe@11 = gleam@list:filter(_pipe@10, fun is_not_empty/1),
gleam@string:join(_pipe@11, <<"\n\n"/utf8>>).
-spec append_if_msg_not_empty(binary(), binary()) -> binary().
append_if_msg_not_empty(Prefix, Message) ->
case Message of
<<""/utf8>> ->
<<""/utf8>>;
_@1 ->
gleam@string:append(Prefix, Message)
end.
-spec subcommands_help(gleam@map:map_(binary(), command(any()))) -> binary().
subcommands_help(Cmds) ->
_pipe = Cmds,
_pipe@1 = gleam@map:map_values(_pipe, fun subcommand_help/2),
_pipe@2 = gleam@map:values(_pipe@1),
_pipe@3 = gleam@list:sort(_pipe@2, fun gleam@string:compare/2),
gleam@string:join(_pipe@3, <<"\n\t"/utf8>>).
-spec subcommand_help(binary(), command(any())) -> binary().
subcommand_help(Name, Cmd) ->
case erlang:element(2, Cmd) of
none ->
Name;
{some, {contents, _@1, _@2, {description, Desc, _@3}}} ->
gleam@string:concat([Name, <<"\t\t"/utf8>>, Desc])
end.