From 798527d79a278012fa7ae3d1d398e20ca1aabfac Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 6 Jan 2024 08:45:33 +0100 Subject: [PATCH] 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. --- share/completions/ant.fish | 2 +- share/completions/blender.fish | 3 +-- share/completions/git.fish | 7 +++---- share/completions/ninja.fish | 3 +-- share/completions/unzip.fish | 3 +-- share/completions/watchexec.fish | 2 +- share/completions/which.fish | 2 +- share/completions/xterm.fish | 2 +- share/functions/__fish_complete_subcommand.fish | 2 +- share/functions/__fish_preview_current_file.fish | 4 +++- 10 files changed, 14 insertions(+), 16 deletions(-) diff --git a/share/completions/ant.fish b/share/completions/ant.fish index bd315498e..5cb5eab98 100644 --- a/share/completions/ant.fish +++ b/share/completions/ant.fish @@ -8,7 +8,7 @@ function __fish_complete_ant_targets -d "Print list of targets from build.xml an for token in $argv[2..-1] switch $prev case -buildfile -file -f - set buildfile (eval echo $token) + set buildfile echo $token end set prev $token end diff --git a/share/completions/blender.fish b/share/completions/blender.fish index 295c1a690..5ebf31fed 100644 --- a/share/completions/blender.fish +++ b/share/completions/blender.fish @@ -9,8 +9,7 @@ function __blender_echo_input_file_name set -l path (commandline -poc | string match -r '.*\\.blend[0-9]*$' | tail --lines=1) - # Using eval to expand ~ and variables specified on the commandline. - eval echo $path + echo $path end function __blender_list_scenes diff --git a/share/completions/git.fish b/share/completions/git.fish index 91452c3bf..b781a7c26 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -16,8 +16,7 @@ function __fish_git end end # Using 'command git' to avoid interactions for aliases from git to (e.g.) hub - # Using eval to expand ~ and variables specified on the commandline. - eval command git $global_args \$saved_args 2>/dev/null + command git $global_args $saved_args 2>/dev/null end # 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 set -l cmd (commandline -opc) set -e cmd[1] # Drop "git". - set -l subcommand_args + set -lx subcommand_args if argparse -s (__fish_git_global_optspecs) -- $cmd set subcommand_args $argv[2..] # Drop the subcommand. end - complete -C "git-$subcommand $subcommand_args "(commandline -ct) + complete -C "git-$subcommand \$subcommand_args "(commandline -ct) end # source git-* commands' autocompletion file if exists diff --git a/share/completions/ninja.fish b/share/completions/ninja.fish index c46c00ae5..dab77f750 100644 --- a/share/completions/ninja.fish +++ b/share/completions/ninja.fish @@ -2,8 +2,7 @@ function __fish_ninja set -l saved_args $argv set -l dir . if argparse -i C/dir= -- (commandline -opc) - # Using eval to expand ~ and variables specified on the commandline. - eval command ninja -C$_flag_C \$saved_args + command ninja -C$_flag_C $saved_args end end diff --git a/share/completions/unzip.fish b/share/completions/unzip.fish index 68864d1a1..633c134f7 100644 --- a/share/completions/unzip.fish +++ b/share/completions/unzip.fish @@ -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)' # 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 (eval set zipfile (__fish_first_token); echo $zipfile) 2>/dev/null | string replace -r --filter ".*:\S+\s+(.*)" "\$1")' + 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")' else diff --git a/share/completions/watchexec.fish b/share/completions/watchexec.fish index 075b9d68e..7fe9aeb05 100644 --- a/share/completions/watchexec.fish +++ b/share/completions/watchexec.fish @@ -1,7 +1,7 @@ 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 argv (commandline -opc) (commandline -ct) + set argv (commandline -opc | string escape) (commandline -ct) set -e argv[1] argparse -s $spec -- $argv 2>/dev/null diff --git a/share/completions/which.fish b/share/completions/which.fish index d4fb5ff8f..45209ac33 100644 --- a/share/completions/which.fish +++ b/share/completions/which.fish @@ -16,4 +16,4 @@ else # OSX complete -c which -s s -d "Print no output, only return 0 if found" end -complete -c which -a "(complete -C (printf %s\n (commandline -ot)))" -x +complete -c which -a "(__fish_complete_subcommand)" -x diff --git a/share/completions/xterm.fish b/share/completions/xterm.fish index fe9d5041e..738d32aa3 100644 --- a/share/completions/xterm.fish +++ b/share/completions/xterm.fish @@ -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 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 bcn -d 'Blinking cursor will be on for that many milliseconds' diff --git a/share/functions/__fish_complete_subcommand.fish b/share/functions/__fish_complete_subcommand.fish index 5fad75fa2..2bcc1a720 100644 --- a/share/functions/__fish_complete_subcommand.fish +++ b/share/functions/__fish_complete_subcommand.fish @@ -18,7 +18,7 @@ function __fish_complete_subcommand -d "Complete subcommand" --no-scope-shadowin set -l options_with_param $argv 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] set -l token $cmd[1] set -e cmd[1] diff --git a/share/functions/__fish_preview_current_file.fish b/share/functions/__fish_preview_current_file.fish index ae8db1091..f2fc53c1e 100644 --- a/share/functions/__fish_preview_current_file.fish +++ b/share/functions/__fish_preview_current_file.fish @@ -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 # could comprise multiple lines, so join them into a single string. set -l file (commandline -t | string collect) + set -l prefix eval set if test -z $file # $backslash will parsed as regex which may need additional escaping. set -l backslash '\\\\' not status test-feature regex-easyesc && set backslash $backslash$backslash set file (string replace -ra -- '([ ;#^<>&|()"\'])' "$backslash\$1" (commandline -oc)[-1]) + set prefix set end 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 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] $pager $files