diff --git a/share/completions/and.fish b/share/completions/and.fish index 9066e6101..50d2825b6 100644 --- a/share/completions/and.fish +++ b/share/completions/and.fish @@ -1,3 +1,3 @@ complete -c and -s h -l help -d 'Display help and exit' -complete -c and -xa '( __fish_complete_subcommand )' +complete -c and -xa '(__fish_complete_subcommand --allow-functions-and-builtins)' diff --git a/share/completions/begin.fish b/share/completions/begin.fish index e95aa4bbc..4d3c1256f 100644 --- a/share/completions/begin.fish +++ b/share/completions/begin.fish @@ -1,2 +1,2 @@ complete -c begin -s h -l help -d 'Display help and exit' -complete -c begin -xa '(__fish_complete_subcommand)' +complete -c begin -xa '(__fish_complete_subcommand --allow-functions-and-builtins)' diff --git a/share/completions/command.fish b/share/completions/command.fish index 7c3e6956b..85d4eca3a 100644 --- a/share/completions/command.fish +++ b/share/completions/command.fish @@ -3,5 +3,4 @@ complete -c command -n 'test (count (commandline -opc)) -eq 1' -s a -l all -d 'P complete -c command -n 'test (count (commandline -opc)) -eq 1' -s q -l quiet -d 'Do not print anything, only set exit status' complete -c command -n 'test (count (commandline -opc)) -eq 1' -s s -l search -d 'Print the file that would be executed' complete -c command -n 'test (count (commandline -opc)) -eq 1' -s s -l search -d 'Print the file that would be executed' -complete -c command -n 'test (count (commandline -opc)) -eq 1' -xa "(__fish_complete_external_command)" -complete -c command -n 'test (count (commandline -opc)) -ge 2' -xa "(__fish_complete_subcommand)" +complete -c command -xa "(__fish_complete_subcommand)" diff --git a/share/completions/doas.fish b/share/completions/doas.fish index e56071ec4..e90cf7730 100644 --- a/share/completions/doas.fish +++ b/share/completions/doas.fish @@ -24,7 +24,7 @@ end function __fish_complete_doas_subcommand set -l args (__fish_doas_print_remaining_args) set -lx -a PATH /usr/local/sbin /sbin /usr/sbin - complete -C "$args" + __fish_complete_subcommand --commandline $args end complete -c doas -n "not __fish_doas_print_remaining_args" -s a -d "Choose auth method on systems using /etc/login.conf" diff --git a/share/completions/env.fish b/share/completions/env.fish index 1de054afd..370cd3fed 100644 --- a/share/completions/env.fish +++ b/share/completions/env.fish @@ -17,7 +17,7 @@ function __fish_complete_env_subcommand # Then complete the rest as if it was given as a command. if test -n "$argv" - complete -C "$argv" + __fish_complete_subcomand --commandline $argv return 0 end return 1 diff --git a/share/completions/exec.fish b/share/completions/exec.fish index 1123f1e3e..73b535ee0 100644 --- a/share/completions/exec.fish +++ b/share/completions/exec.fish @@ -1,3 +1,2 @@ complete -c exec -n 'test (count (commandline -opc)) -eq 1' -s h -l help -d 'Display help and exit' -complete -c exec -n 'test (count (commandline -opc)) -eq 1' -xa "(__fish_complete_external_command)" -complete -c exec -n 'test (count (commandline -opc)) -ge 2' -xa "(__fish_complete_subcommand)" +complete -c exec -xa "(__fish_complete_subcommand)" diff --git a/share/completions/if.fish b/share/completions/if.fish index 978b1868d..5a2c2bdd4 100644 --- a/share/completions/if.fish +++ b/share/completions/if.fish @@ -1,2 +1,2 @@ complete -c if -s h -l help -d 'Display help and exit' -complete -c if -xa '(__fish_complete_subcommand)' +complete -c if -xa '(__fish_complete_subcommand --allow-functions-and-builtins)' diff --git a/share/completions/mosh.fish b/share/completions/mosh.fish index 36a00b36f..2185d24da 100644 --- a/share/completions/mosh.fish +++ b/share/completions/mosh.fish @@ -4,7 +4,7 @@ complete -x -c mosh -d Hostname -a "(__fish_complete_user_at_hosts)" complete -x -c mosh -d User -a " (__fish_print_users)@ " -complete -c mosh -d "Command to run" -x -a '(__fish_complete_subcommand --fcs-skip=2)' +complete -c mosh -n 'test (__fish_number_of_cmd_args_wo_opts) -ge 2' -d "Command to run" -x -a '(__fish_complete_subcommand --fcs-skip=2)' complete -c mosh -l client -d 'Path to client helper on local machine (default: "mosh-client")' complete -c mosh -l server -d 'Command to run server helper on remote machine (default: "mosh-server")' diff --git a/share/completions/not.fish b/share/completions/not.fish index 90fa69045..f77344e86 100644 --- a/share/completions/not.fish +++ b/share/completions/not.fish @@ -1,2 +1,2 @@ complete -c not -s h -l help -d 'Display help and exit' -complete -c not -xa '(__fish_complete_subcommand)' +complete -c not -xa '(__fish_complete_subcommand --allow-functions-and-builtins)' diff --git a/share/completions/or.fish b/share/completions/or.fish index d95e0957d..2c081c22d 100644 --- a/share/completions/or.fish +++ b/share/completions/or.fish @@ -1,3 +1,3 @@ complete -c or -s h -l help -d 'Display help and exit' -complete -c or -xa '(__fish_complete_subcommand)' +complete -c or -xa '(__fish_complete_subcommand --allow-functions-and-builtins)' diff --git a/share/completions/ssh.fish b/share/completions/ssh.fish index f2becec78..6bbc57118 100644 --- a/share/completions/ssh.fish +++ b/share/completions/ssh.fish @@ -13,7 +13,7 @@ complete -x -c ssh -d "Remote" -a "(__fish_complete_user_at_hosts)" # (__fish_print_users | string match -r -v '^_')@ # " -complete -c ssh -d "Command to run" -x -a '(__fish_complete_subcommand --fcs-skip=2)' +complete -c ssh -n 'test (__fish_number_of_cmd_args_wo_opts) -ge 2' -d "Command to run" -x -a '(__fish_complete_subcommand --fcs-skip=2)' complete -c ssh -s a -d "Disables forwarding of the authentication agent" complete -c ssh -s A -d "Enables forwarding of the authentication agent" diff --git a/share/completions/sudo.fish b/share/completions/sudo.fish index f432b5334..24abb0cce 100644 --- a/share/completions/sudo.fish +++ b/share/completions/sudo.fish @@ -34,7 +34,7 @@ end function __fish_complete_sudo_subcommand set -l args (__fish_sudo_print_remaining_args) set -lx -a PATH /usr/local/sbin /sbin /usr/sbin - complete -C "$args" + __fish_complete_subcommand --commandline $args end # All these options should be valid for GNU and OSX sudo diff --git a/share/completions/while.fish b/share/completions/while.fish index d85e72092..d799cf9ec 100644 --- a/share/completions/while.fish +++ b/share/completions/while.fish @@ -1,2 +1,2 @@ complete -c while -s h -l help -d 'Display help and exit' -complete -c while -xa '(__fish_complete_subcommand)' +complete -c while -xa '(__fish_complete_subcommand --allow-functions-and-builtins)' diff --git a/share/functions/__fish_complete_subcommand.fish b/share/functions/__fish_complete_subcommand.fish index 79496d6d2..d67c009a5 100644 --- a/share/functions/__fish_complete_subcommand.fish +++ b/share/functions/__fish_complete_subcommand.fish @@ -1,45 +1,58 @@ function __fish_complete_subcommand -d "Complete subcommand" --no-scope-shadowing + # Pass --commandline to complete the remainder of the arguments instead of the commandline. + # Pass --allow-functions-and-builtins to enable the completion of the first token as function or builtin. + # Other args are considered flags to the supercommand that require an option. + + # How many non-option tokens we skip in the input commandline before completing the subcommand + # Usually 1; for ssh 2. set -l skip_next 1 - set -l test - switch "$argv[1]" - case '--fcs-skip=*' - set -l rest - string replace -a = ' ' -- $argv[1] | read test skip_next - set -e argv[1] - end - - set -l res "" - set -l had_cmd 0 - set -l cmd (commandline -cop) (commandline -ct) - - for i in $cmd - - if test $skip_next -gt 0 - set skip_next (math $skip_next - 1) - continue + set -l allow_functions_and_builtins false + set -l subcommand + while string match -rq -- '^--[a-z]' $argv[1] + set -l arg $argv[1] + set -e argv[1] + switch $arg + case '--fcs-skip=*' + set skip_next (string split = -- $arg)[2] + case '--allow-functions-and-builtins' + set allow_functions_and_builtins true + case '--commandline' + set subcommand $argv + set -e argv + break end + end + set -l options_with_param $argv - if test "$had_cmd" = 1 - set res "$res $i" - else - - if contains -- $i $argv + if not string length -q $subcommand + set cmd (commandline -cop) (commandline -ct) + while set -q cmd[1] + set -l token $cmd[1] + set -e cmd[1] + if contains -- $token $options_with_param set skip_next (math $skip_next + 1) continue end - - switch $i - case '-*' - case '*=*' + switch $token + case '-*' '*=*' + continue case '*' - - set had_cmd 1 - set res $i + if test $skip_next -gt 0 + set skip_next (math $skip_next - 1) + continue + end + # found the start of our command + set subcommand $token $cmd + break end end end - printf "%s\n" (complete -C "$res") + if test $allow_functions_and_builtins = false && test (count $subcommand) -eq 1 + __fish_complete_external_command + else + printf "%s\n" (complete -C "$subcommand") + end end