fix: Only generate stubs if has subcommands

This commit is contained in:
Lzu Tao 2024-07-11 05:58:34 +07:00
parent 76b9c46241
commit 6243d65463
2 changed files with 40 additions and 26 deletions

View file

@ -1,6 +1,6 @@
use std::io::Write; use std::io::Write;
use clap::{builder, Arg, ArgAction, Command, ValueHint}; use clap::{builder, Arg, Command, ValueHint};
use crate::generator::{utils, Generator}; use crate::generator::{utils, Generator};
@ -20,25 +20,13 @@ impl Generator for Fish {
.get_bin_name() .get_bin_name()
.expect("crate::generate should have set the bin_name"); .expect("crate::generate should have set the bin_name");
// If there is any regular flags, we may have complicated cases, e.g. `git --git-dir somedir status`. Using normal
// `__fish_seen_subcommand_from` won't help us find out the real subcommand is `status`, and not `somedir`.
// However, we prefer to fallback to the old behavior when there are no regular flags. `-h` and `-v` is not
// a regular flag and it behaves like a command. E.g., `rustup --version toolchain` is not a valid command line.
let has_global_flags = cmd.get_arguments().any(|a| {
!a.is_positional()
&& !matches!(
a.get_action(),
ArgAction::Help
| ArgAction::HelpShort
| ArgAction::HelpLong
| ArgAction::Version
)
});
let name = escape_name(bin_name); let name = escape_name(bin_name);
let mut needs_fn_name = &format!("__fish_{name}_needs_command")[..]; let mut needs_fn_name = &format!("__fish_{name}_needs_command")[..];
let mut using_fn_name = &format!("__fish_{name}_using_subcommand")[..]; let mut using_fn_name = &format!("__fish_{name}_using_subcommand")[..];
if has_global_flags && cmd.has_subcommands() { // Given `git --git-dir somedir status`, using `__fish_seen_subcommand_from` won't help us
// find out `status` is the real subcommand, and not `somedir`. However, when there are no subcommands,
// there is no need to use our custom stubs.
if cmd.has_subcommands() {
gen_subcommand_helpers(&name, cmd, buf, needs_fn_name, using_fn_name); gen_subcommand_helpers(&name, cmd, buf, needs_fn_name, using_fn_name);
} else { } else {
needs_fn_name = "__fish_use_subcommand"; needs_fn_name = "__fish_use_subcommand";

View file

@ -1,9 +1,35 @@
complete -c my-app -n "__fish_use_subcommand" -s h -l help -d 'Print help' # Print an optspec for argparse to handle cmd's options that are independent of any subcommand.
complete -c my-app -n "__fish_use_subcommand" -a "foo" function __fish_my_app_global_optspecs
complete -c my-app -n "__fish_use_subcommand" -a "bar" string join \n h/help
complete -c my-app -n "__fish_use_subcommand" -a "help" -d 'Print this message or the help of the given subcommand(s)' end
complete -c my-app -n "__fish_seen_subcommand_from foo" -s h -l help -d 'Print help'
complete -c my-app -n "__fish_seen_subcommand_from bar" -s h -l help -d 'Print help' function __fish_my_app_needs_command
complete -c my-app -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from foo bar help" -f -a "foo" # Figure out if the current invocation already has a command.
complete -c my-app -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from foo bar help" -f -a "bar" set -l cmd (commandline -opc)
complete -c my-app -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from foo bar help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' set -e cmd[1]
argparse -s (__fish_my_app_global_optspecs) -- $cmd 2>/dev/null
or return
if set -q argv[1]
# Also print the command, so this can be used to figure out what it is.
echo $argv[1]
return 1
end
return 0
end
function __fish_my_app_using_subcommand
set -l cmd (__fish_my_app_needs_command)
test -z "$cmd"
and return 1
contains -- $cmd[1] $argv
end
complete -c my-app -n "__fish_my_app_needs_command" -s h -l help -d 'Print help'
complete -c my-app -n "__fish_my_app_needs_command" -a "foo"
complete -c my-app -n "__fish_my_app_needs_command" -a "bar"
complete -c my-app -n "__fish_my_app_needs_command" -a "help" -d 'Print this message or the help of the given subcommand(s)'
complete -c my-app -n "__fish_my_app_using_subcommand foo" -s h -l help -d 'Print help'
complete -c my-app -n "__fish_my_app_using_subcommand bar" -s h -l help -d 'Print help'
complete -c my-app -n "__fish_my_app_using_subcommand help; and not __fish_seen_subcommand_from foo bar help" -f -a "foo"
complete -c my-app -n "__fish_my_app_using_subcommand help; and not __fish_seen_subcommand_from foo bar help" -f -a "bar"
complete -c my-app -n "__fish_my_app_using_subcommand help; and not __fish_seen_subcommand_from foo bar help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'