From 31f3c16857e83097113e541a35c5f9a0e2d372c8 Mon Sep 17 00:00:00 2001 From: Karolina Gontarek Date: Tue, 11 May 2021 23:02:15 +0200 Subject: [PATCH] Resolve relative paths in command names for complete -p Fixes #6001 --- CHANGELOG.rst | 1 + src/complete.cpp | 10 +++++++--- src/path.h | 4 ++-- tests/checks/complete.fish | 27 +++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e177539ab..4e5ec6f7b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -69,6 +69,7 @@ Completions - ``firewall-cmd`` (:issue:`7900`) - Commands that wrap ``cd`` (using ``complete --wraps cd``) get the same completions as ``cd`` (:issue:`4693`). +- Completion defined with ``complete -p`` now also work when the commandline uses a relative path to the command (:issue:`6001`). Improved terminal support ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/complete.cpp b/src/complete.cpp index d04316eae..eeee57b4d 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -573,9 +573,13 @@ void complete_remove_all(const wcstring &cmd, bool cmd_is_path) { /// Find the full path and commandname from a command string 'str'. static void parse_cmd_string(const wcstring &str, wcstring *path, wcstring *cmd, const environment_t &vars) { - if (!path_get_path(str, path, vars)) { - /// Use the empty string as the 'path' for commands that can not be found. - path->clear(); + bool found = path_get_path(str, path, vars); + // If the command was not found, 'path' is the empty string. + // Resolve commands that use relative paths because we compare full paths with "complete -p". + if (found && !str.empty() && str.at(0) != L'/') { + if (auto full_path = wrealpath(*path)) { + path->assign(full_path.acquire()); + } } // Make sure the path is not included in the command. diff --git a/src/path.h b/src/path.h index 366c1dbbc..852714b15 100644 --- a/src/path.h +++ b/src/path.h @@ -41,11 +41,11 @@ int path_get_config_is_remote(); class env_stack_t; void path_emit_config_directory_messages(env_stack_t &vars); -/// Finds the full path of an executable. +/// Finds the path of an executable. /// /// Args: /// cmd - The name of the executable. -/// output_or_NULL - If non-NULL, store the full path. +/// output_or_NULL - If non-NULL, store the path. /// vars - The environment variables to use /// /// Returns: diff --git a/tests/checks/complete.fish b/tests/checks/complete.fish index 5ba7ce08d..ff3fd60d9 100644 --- a/tests/checks/complete.fish +++ b/tests/checks/complete.fish @@ -396,3 +396,30 @@ complete -C'fudge eat yummyin' cd - rm -r $dir + +set -l dir (mktemp -d) +cd $dir +cd - + +: >command-not-in-path +chmod +x command-not-in-path +complete -p $PWD/command-not-in-path -xa relative-path +complete -C './command-not-in-path ' +# CHECK: relative-path + +# Non-canonical command path +mkdir -p subdir +: >subdir/command-in-subdir +chmod +x subdir/command-in-subdir +complete -p "$PWD/subdir/command-in-subdir" -xa custom-completions +complete -C './subdir/../subdir/command-in-subdir ' +# CHECK: custom-completions + +# Relative $PATH +begin + set -lx PATH subdir $PATH + complete -C 'command-in-subdir ' + # CHECK: custom-completions +end + +rm -r $dir