completions: fix double evaluation of tokenized commandline

Fix cases like

    eval my-cmd (commandline -o)
    complete -C "my-cmd $(commandline -o)"

In both cases, we spuriously evaluate tokens like "(inside-quoted-string)"
as command substitutions. Fix this by escaping the strings.  The momentarily
regresses the intended purpose of "eval" -- to expand variables -- but the
next commit will fix that.
This commit is contained in:
Johannes Altmanninger 2024-01-06 08:45:33 +01:00
parent 368017905e
commit 798527d79a
10 changed files with 14 additions and 16 deletions

View file

@ -8,7 +8,7 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml an
for token in $argv[2..-1] for token in $argv[2..-1]
switch $prev switch $prev
case -buildfile -file -f case -buildfile -file -f
set buildfile (eval echo $token) set buildfile echo $token
end end
set prev $token set prev $token
end end

View file

@ -9,8 +9,7 @@ function __blender_echo_input_file_name
set -l path (commandline -poc | set -l path (commandline -poc |
string match -r '.*\\.blend[0-9]*$' | string match -r '.*\\.blend[0-9]*$' |
tail --lines=1) tail --lines=1)
# Using eval to expand ~ and variables specified on the commandline. echo $path
eval echo $path
end end
function __blender_list_scenes function __blender_list_scenes

View file

@ -16,8 +16,7 @@ function __fish_git
end end
end end
# Using 'command git' to avoid interactions for aliases from git to (e.g.) hub # Using 'command git' to avoid interactions for aliases from git to (e.g.) hub
# Using eval to expand ~ and variables specified on the commandline. command git $global_args $saved_args 2>/dev/null
eval command git $global_args \$saved_args 2>/dev/null
end end
# Print an optspec for argparse to handle git's options that are independent of any subcommand. # Print an optspec for argparse to handle git's options that are independent of any subcommand.
@ -2462,11 +2461,11 @@ complete -c git -n __fish_git_needs_command -a '(__fish_git_custom_commands)' -d
function __fish_git_complete_custom_command -a subcommand function __fish_git_complete_custom_command -a subcommand
set -l cmd (commandline -opc) set -l cmd (commandline -opc)
set -e cmd[1] # Drop "git". set -e cmd[1] # Drop "git".
set -l subcommand_args set -lx subcommand_args
if argparse -s (__fish_git_global_optspecs) -- $cmd if argparse -s (__fish_git_global_optspecs) -- $cmd
set subcommand_args $argv[2..] # Drop the subcommand. set subcommand_args $argv[2..] # Drop the subcommand.
end end
complete -C "git-$subcommand $subcommand_args "(commandline -ct) complete -C "git-$subcommand \$subcommand_args "(commandline -ct)
end end
# source git-* commands' autocompletion file if exists # source git-* commands' autocompletion file if exists

View file

@ -2,8 +2,7 @@ function __fish_ninja
set -l saved_args $argv set -l saved_args $argv
set -l dir . set -l dir .
if argparse -i C/dir= -- (commandline -opc) if argparse -i C/dir= -- (commandline -opc)
# Using eval to expand ~ and variables specified on the commandline. command ninja -C$_flag_C $saved_args
eval command ninja -C$_flag_C \$saved_args
end end
end end

View file

@ -39,8 +39,7 @@ if unzip -v 2>/dev/null | string match -eq Debian
complete -c unzip -n "__fish_is_nth_token 1" -k -xa '(__fish_complete_suffix .zip .jar .aar)' complete -c unzip -n "__fish_is_nth_token 1" -k -xa '(__fish_complete_suffix .zip .jar .aar)'
# Files thereafter are either files to include or exclude from the operation # Files thereafter are either files to include or exclude from the operation
set -l zipfile complete -c unzip -n 'not __fish_is_nth_token 1' -xa '(unzip -l (__fish_first_token) 2>/dev/null | string replace -r --filter ".*:\S+\s+(.*)" "\$1")'
complete -c unzip -n 'not __fish_is_nth_token 1' -xa '(unzip -l (eval set zipfile (__fish_first_token); echo $zipfile) 2>/dev/null | string replace -r --filter ".*:\S+\s+(.*)" "\$1")'
else else

View file

@ -1,7 +1,7 @@
function __fish_watchexec_print_remaining_args function __fish_watchexec_print_remaining_args
set -l spec w/watch= c/clear='?' o/on-busy-update= r/restart s/signal= stop-signal= stop-timeout= d/debounce= stdin-quit no-vcs-ignore no-project-ignore no-global-ignore no-default-ignore no-discover-ignore p/postpone delay-run= poll= shell= n no-environment emit-events-to= E/env= no-process-group N/notify project-origin= workdir= e/exts= f/filter= filter-file= i/ignore= ignore-file= fs-events= no-meta print-events v/verbose log-file= manual h/help V/version set -l spec w/watch= c/clear='?' o/on-busy-update= r/restart s/signal= stop-signal= stop-timeout= d/debounce= stdin-quit no-vcs-ignore no-project-ignore no-global-ignore no-default-ignore no-discover-ignore p/postpone delay-run= poll= shell= n no-environment emit-events-to= E/env= no-process-group N/notify project-origin= workdir= e/exts= f/filter= filter-file= i/ignore= ignore-file= fs-events= no-meta print-events v/verbose log-file= manual h/help V/version
set argv (commandline -opc) (commandline -ct) set argv (commandline -opc | string escape) (commandline -ct)
set -e argv[1] set -e argv[1]
argparse -s $spec -- $argv 2>/dev/null argparse -s $spec -- $argv 2>/dev/null

View file

@ -16,4 +16,4 @@ else # OSX
complete -c which -s s -d "Print no output, only return 0 if found" complete -c which -s s -d "Print no output, only return 0 if found"
end end
complete -c which -a "(complete -C (printf %s\n (commandline -ot)))" -x complete -c which -a "(__fish_complete_subcommand)" -x

View file

@ -98,7 +98,7 @@ complete -c xterm -o wc -d 'Use wide characters'
complete -c xterm -o wf -d 'Wait the first time for the window to be mapped' complete -c xterm -o wf -d 'Wait the first time for the window to be mapped'
complete -c xterm -o Sccn -d 'Use as input/output channel for an existing program' complete -c xterm -o Sccn -d 'Use as input/output channel for an existing program'
complete -c xterm -s e -a "(complete -C (printf %s\n (commandline -ot)))" -x -d 'Run program in xterm' complete -c xterm -s e -a "(__fish_complete_subcommand)" -x -d 'Run program in xterm'
complete -r -c xterm -o bcf -d 'Blinking cursor will be off for that many milliseconds' complete -r -c xterm -o bcf -d 'Blinking cursor will be off for that many milliseconds'
complete -r -c xterm -o bcn -d 'Blinking cursor will be on for that many milliseconds' complete -r -c xterm -o bcn -d 'Blinking cursor will be on for that many milliseconds'

View file

@ -18,7 +18,7 @@ function __fish_complete_subcommand -d "Complete subcommand" --no-scope-shadowin
set -l options_with_param $argv set -l options_with_param $argv
if not string length -q -- $subcommand if not string length -q -- $subcommand
set -l cmd (commandline -cop) (commandline -ct) set -l cmd (commandline -cop | string escape) (commandline -ct)
while set -q cmd[1] while set -q cmd[1]
set -l token $cmd[1] set -l token $cmd[1]
set -e cmd[1] set -e cmd[1]

View file

@ -5,12 +5,14 @@ function __fish_preview_current_file --description "Open the file at the cursor
# commandline -t will never return an empty list. However, the token # commandline -t will never return an empty list. However, the token
# could comprise multiple lines, so join them into a single string. # could comprise multiple lines, so join them into a single string.
set -l file (commandline -t | string collect) set -l file (commandline -t | string collect)
set -l prefix eval set
if test -z $file if test -z $file
# $backslash will parsed as regex which may need additional escaping. # $backslash will parsed as regex which may need additional escaping.
set -l backslash '\\\\' set -l backslash '\\\\'
not status test-feature regex-easyesc && set backslash $backslash$backslash not status test-feature regex-easyesc && set backslash $backslash$backslash
set file (string replace -ra -- '([ ;#^<>&|()"\'])' "$backslash\$1" (commandline -oc)[-1]) set file (string replace -ra -- '([ ;#^<>&|()"\'])' "$backslash\$1" (commandline -oc)[-1])
set prefix set
end end
set -q file[1] || return set -q file[1] || return
@ -18,7 +20,7 @@ function __fish_preview_current_file --description "Open the file at the cursor
# strip -option= from token if present # strip -option= from token if present
set file (string replace -r -- '^-[^\s=]*=' '' $file | string collect) set file (string replace -r -- '^-[^\s=]*=' '' $file | string collect)
eval set -l files $file || return # Bail if $file does not tokenize. $prefix -l files $file || return # Bail if $file does not tokenize.
if set -q files[1] && test -f $files[1] if set -q files[1] && test -f $files[1]
$pager $files $pager $files