Skip to content

Commit

Permalink
Add aliases for command arguments
Browse files Browse the repository at this point in the history
Fix #59
  • Loading branch information
carlobaldassi committed Jan 23, 2020
1 parent 26b1a74 commit 128e51d
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 49 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ See also the examples in the [examples directory](examples).
* Drop support for Julia versions v0.6/v0.7
* Parsing does not exit julia by default when in interactive mode now
* Added mutually-exclusive and/or required argument groups
* Added command aliases
* Renamed function `import_settings``import_settings!`

## Changes in release 0.6.2
Expand Down
24 changes: 18 additions & 6 deletions docs/src/arg_table.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ using ArgParse
Commands are a special kind of arguments which introduce sub-parsing sessions as soon as they are encountered by `parse_args`
(and are therefore mutually exclusive).
The `ArgParse` module allows commands to look both as positional arguments or as options, with minor differences between the two.
Unlike actual positional arguments, commands that *look* like positional arguments can have extra names (aliases).

Commands are introduced by the `action = :command` setting in the argument table. Suppose we save the following script in
a file called `cmd_example.jl`:
Expand All @@ -285,10 +286,10 @@ function parse_commandline()
s = ArgParseSettings()

@add_arg_table s begin
"cmd1"
"cmd1", "C"
help = "first command"
action = :command
"cmd2"
"cmd2", "K"
help = "second command"
action = :command
end
Expand All @@ -307,8 +308,8 @@ $ julia cmd_example.jl --help
usage: cmd_example.jl [-h] {cmd1|cmd2}
commands:
cmd1 first command
cmd2 second command
cmd1 first command (aliases: C)
cmd2 second command (aliases: K)
optional arguments:
-h, --help show this help message and exit
Expand All @@ -325,6 +326,14 @@ Dict("%COMMAND%"=>"cmd1", "cmd1"=>Dict())
This is unless `parse_args` is invoked with `as_symbols=true`, in which case the special key becomes `:_COMMAND_`. (In that case,
no other argument is allowed to use `_COMMAND_` as its `dest_name`, or an error will be raised.)

Aliases are recognized when parsing, but the returned `Dict` will always use the command's name (the first entry in the
table):

```text
$ julia cmd_example.jl C
Dict("%COMMAND%"=>"cmd1", "cmd1"=>Dict())
```

Since commands introduce sub-parsing sessions, an additional key will be added for the called command (`"cmd1"` in this case) whose
associated value is another `Dict{String, Any}` containing the result of the sub-parsing (in the above case it's empty). In fact,
with the default settings, commands have their own help screens:
Expand Down Expand Up @@ -352,8 +361,8 @@ By default, if commands exist, they are required; this can be avoided by setting
The only meaningful settings for commands in an argument entry besides `action` are `help`, `force_override`, `group` and
(for flags only) `dest_name`.

The only differences between positional-arguments-like and option-like commands are in the way they are parsed, the fact that options
accept a `dest_name` setting, and that options can have multiple names (e.g. a long and short form).
The only differences between positional-arguments-like and option-like commands are in the way they are parsed, and the fact
that options accept a `dest_name` setting.

Note that short-form option-like commands will be still be recognized in the middle of a short options group and trigger a sub-parsing
session: for example, if an option `-c` is associated to a command, then `-xch` will parse option `-x` according to the parent
Expand Down Expand Up @@ -381,6 +390,9 @@ parse_args(["--help"], settings)
```

It is possible to partition the arguments differently by defining and using customized argument groups.
Groups of options can also be declared to be mutually exclusive, meaning that no more than one of the
options in the group can be provided. A group can also be declared to be required, meaning that at least
one argument in the group needs to be provided.

```@docs
add_arg_group
Expand Down
10 changes: 6 additions & 4 deletions docs/src/conflicts.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Conflicts between arguments, be them options, positional arguments or commands,
`:append_arg`)
* Two positional arguments have the same metavar (and are therefore indistinguishable in the usage and help screens
and in error messages)
* An argument and a command, or two commands, have the same destination key.
* An argument's destination key is the same as a command name
* Two commands with the same name are given, but one has a long-option form (e.g. `test` and `--test`)
* A command alias is equal to another command's name or alias

When the general setting `error_on_conflict` is `true`, or any time the specific `force_override` table entry
setting is `false`, any of the above conditions leads to an error.
Expand All @@ -21,6 +23,6 @@ the resolution of most of the conflicts in favor of the newest added entry. The
* In case of duplicate destination key and incompatible types or actions, the older argument is deleted
* In case of duplicate positional arguments metavars, the older argument is deleted
* A command can override an argument with the same destination key
* However, an argument can never override a command if they have the same destination key; neither can
a command override another command when added with `@add_arg_table` (compatible commands are merged
by [`import_settings`](@ref) though)
* However, an argument can never override a command; neither can a command override another command when added
with `@add_arg_table` (compatible commands are merged by [`import_settings`](@ref) though)
* Conflicting command aliases are removed
2 changes: 1 addition & 1 deletion examples/argparse_example6.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function main(args)
"run"
action = :command # adds a command which will be read from an argument
help = "start running mode"
"jump"
"jump", "ju", "J" # another one, this one has two aliases
action = :command
help = "start jumping mode"
end
Expand Down
26 changes: 24 additions & 2 deletions src/parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ function gen_help_text(arg::ArgParseField, settings::ArgParseSettings)
type_str = ""
default_str = ""
const_str = ""
alias_str = ""
if !is_command_action(arg.action)
if arg.arg_type Any && !(arg.arg_type <: AbstractString)
type_str = pre * "(type: " * string_compact(arg.arg_type)
Expand All @@ -271,9 +272,14 @@ function gen_help_text(arg::ArgParseField, settings::ArgParseSettings)
mid = isempty(type_str) && isempty(default_str) ? " (" : ", "
const_str = mid * "without arg: " * string_compact(arg.constant)
end
else
is_arg(arg) || found_a_bug()
if !isempty(arg.cmd_aliases)
alias_str = pre * "(aliases: " * join(arg.cmd_aliases, ", ")
end
end
post = all(isempty, (type_str, default_str, const_str)) ? "" : ")"
return arg.help * type_str * default_str * const_str * post
post = all(isempty, (type_str, default_str, const_str, alias_str)) ? "" : ")"
return arg.help * type_str * default_str * const_str * alias_str * post
end

function print_group(io::IO, lst::Vector, desc::AbstractString, lc_usable_len::Int, lc_len::Int,
Expand Down Expand Up @@ -782,6 +788,22 @@ function parse1_optarg(state::ParserState, settings::ArgParseSettings, f::ArgPar
elseif f.action == :append_arg
push!(out_dict[f.dest_name], opt_arg)
elseif f.action == :command_arg
if !haskey(settings, opt_arg)
found = false
for f1 in settings.args_table.fields
(is_cmd(f1) && is_arg(f1)) || continue
for al in f1.cmd_aliases
if opt_arg == al
found = true
opt_arg = f1.constant
break
end
end
found && break
end
!found && argparse_error("unknown command: $opt_arg")
haskey(settings, opt_arg) || found_a_bug()
end
out_dict[f.dest_name] = opt_arg
command = opt_arg
else
Expand Down
Loading

0 comments on commit 128e51d

Please sign in to comment.