This originally stemmed from wrapping `Arg` in a `Box`, but we had to
smash it with a hammer as it didn't improve things enough.
- This dropped binary size by 3-7 KiB
- Parsing slowed by 20%.
- Incremental rebuilds slowed down by 1%
With the previous fixes for #4273 and #4280 in place, it's now easy to
add support for subcommand aliases, which this commit does. This
addresses #4265 for Bash.
This continues the work started with the fix for #4273. There was
another bug caused by using the subcommand names without considering
their position in the argument list. If the user enters `git diff log
<TAB>`, we build up a string that identifies the subcommand. We ended
up making the string `git__diff__log` in this case because we appended
`__log` without considering the current state. Since `git__diff__log`
does not correspond to an actual command, we wouldn't provide any
suggestions.
This commit restructures the code so we walk subcommands and
subsubcommands in `bash.rs`. While walking those, we build up a list
containing triples of the parent `$cmd` name (e.g. `git__diff`), the
current command's name (e.g. `log`), and the `$cmd` for the current
command. We then build the shell script's case arms based on that
information.
We could instead have fixed#4280 by using the second element in the
pair returned from `utils::all_subcommands()` (a stringified list of
the subcommand path) instead of the first one. However, that would not
have helped us solve #4265.
Closes#4280
Early in the Bash-completion script, we build up a string that
identifies the command or subcommand. When we see the top-level
command's name (e.g. `git`) we set the command so far to that
value. We do that regardless of where in the argument list it
appears. For example, if the argument list is `git diff git`, we set
the current command to `git` when run into it the second time. We
therefore suggest arguments to the top-level command afterwards, which
is not correct.
This patch fixes that by also considering the string that identifies
the command so far, so we only set the overall command to `git` if the
command so far is the empty string.
This is actually just a step on the way to getting completion to work
for aliases of subcommands.
Closes#4273
There seems to be little reason to return early with an empty list
when there are no subcommands, instead of going through the loop 0
times and then returning the empty list.
The derive-based example has a `///` comment on one argument, which
ends up as a description for the argument in the generated completion
scripts. Let's switch to `//` so the two scripts produce the same
output (except for the binary name), so they're easy to compare.