From b2eea4b46f883b9a73b7d5a2cbd21b1d16e9736f Mon Sep 17 00:00:00 2001 From: Fabian Boehm Date: Thu, 11 Aug 2022 17:05:32 +0200 Subject: [PATCH] complete: Don't load completions if command isn't in $PATH This stops us from loading the completions for e.g. `./foo` if there is no `foo` in path. This is because the completion scripts will call an unqualified `foo`, and then error out. This of course means if the script would work because it never calls the command, we still don't load it. Pathed completions via `complete --path` should be unaffected because they aren't autoloaded anyway. Workaround for #3117 Fixes #9133 --- src/complete.cpp | 6 ++++-- tests/checks/complete.fish | 31 ++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/complete.cpp b/src/complete.cpp index 27a0217f0..299c50e64 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -821,9 +821,11 @@ bool completer_t::complete_param_for_command(const wcstring &cmd_orig, const wcs wcstring cmd, path; parse_cmd_string(cmd_orig, &path, &cmd, ctx.vars); - // Use cmd_orig here for paths, as it is potentially pathed. + // Don't use cmd_orig here for paths. It's potentially pathed, + // so that command might exist, but the completion script + // won't be using it. bool cmd_exists = builtin_exists(cmd) || function_exists_no_autoload(cmd) || - path_get_path(cmd_orig, ctx.vars).has_value(); + path_get_path(cmd, ctx.vars).has_value(); if (!cmd_exists) { // Do not load custom completions if the command does not exist // This prevents errors caused during the execution of completion providers for diff --git a/tests/checks/complete.fish b/tests/checks/complete.fish index 749519ea5..42f8845de 100644 --- a/tests/checks/complete.fish +++ b/tests/checks/complete.fish @@ -1,4 +1,4 @@ -# RUN: %fish %s +#RUN: %fish -C 'set -l fish %fish' %s function complete_test_alpha1 echo $argv end @@ -499,3 +499,32 @@ complete -C'oooops ' # CHECK: oops echo $oops # CHECK: 1 + + +# See that we load completions only if the command exists in $PATH, +# as a workaround for #3117. + +# We need a completion script that runs the command, +# and prints something simple, and isn't already used above. +# +# Currently, tr fits the bill (it does `tr --version` to check for GNUisms) +begin + $fish -c "complete -C'tr -'" | string match -- '-d*' + # CHECK: -d{{\t.*}} +end + +set -l tmpdir (mktemp -d) +cd $tmpdir +begin + touch tr + chmod +x tr + set -l PATH + complete -C'./tr -' | string match -- -d + or echo No match for relative + # CHECK: No match for relative + complete -c tr | string length -q + or echo Empty completions + # CHECK: Empty completions +end + +rm -r $tmpdir