Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(scp): keep tilde in local paths by using _filedir instead of _expand #765

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 56 additions & 10 deletions completions/ssh
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,48 @@ _comp_xfunc_ssh_scp_remote_files()

_comp_deprecate_func _scp_remote_files _comp_xfunc_ssh_scp_remote_files

# Like `_filedir' but accepts a prefix similar to `compgen -P'
# and intended for usage with `compopt -o nospace' and` mixed completions
# `host:', `file ', and `folder/'. Postprocessing is required to escape
# shell special characters and to remove trailing backslash added
# to distinguish files with trailing space and spaces added after file names.
# @param $1 If `-d', complete only on directories (actually unused).
# Otherwise add `$1' prefix to each variant.
# Warning! `-d' can not be specified as a prefix,
# but `scp' does not have such option.
_comp_xfunc_ssh_scp_local_filedir()
{
local COMPREPLY=()
local dirsonly=
if [[ ${1-} == -d ]]; then
dirsonly=-d
shift
fi
local prefix=${1-}

# Do not expand tilde after prefix.
# Such case should be handled by caller.
[[ -z "$prefix" || "$cur" != \~* ]] || return

_filedir $dirsonly

local f expanded append
for f in "${COMPREPLY[@]}"; do
expanded=$f
__expand_tilde_by_ref expanded
if [[ -d "$expanded" ]]; then
append=/
elif [[ -e "$expanded" ]]; then
append=' '
elif [[ "$f" = *[\ \\] ]]; then
append=\\
else
append=
fi
printf "%s" "$prefix$f$append$IFS"
done
}

# This approach is used instead of _filedir to get a space appended
# after local file/dir completions, and -o nospace retained for others.
# If first arg is -d, complete on directory names only. The next arg is
Expand All @@ -481,20 +523,26 @@ _comp_xfunc_ssh_scp_local_files()
{
local IFS=$'\n'

local dirsonly=false
local dirsonly
if [[ ${1-} == -d ]]; then
dirsonly=true
dirsonly=-d
shift
fi

if $dirsonly; then
COMPREPLY+=($(command ls -aF1dL $cur* 2>/dev/null |
local prefix=${1-}
# e.g. "-F~file" should be completed with literal tilde
if [[ -z "$prefix" || "$cur" != \~* ]]; then
local i=${#COMPREPLY[@]}
# Unescape trailing "\ " and drop trailing "\\".
COMPREPLY+=($(_comp_xfunc_ssh_scp_local_filedir $dirsonly "$@" |
command sed -e "s/$_comp_cmd_scp__path_esc/\\\\&/g" -e 's/\\ $/ /' -e 's/\\$//'))
elif [ -n "$dirsonly" ]; then
COMPREPLY+=($(command ls -aF1dL "$cur"* 2>/dev/null |
command sed -e "s/$_comp_cmd_scp__path_esc/\\\\&/g" -e '/[^\/]$/d' \
-e "s/^/${1-}/"))
-e "s/^/$prefix/"))
else
COMPREPLY+=($(command ls -aF1dL $cur* 2>/dev/null |
COMPREPLY+=($(command ls -aF1dL "$cur"* 2>/dev/null |
command sed -e "s/$_comp_cmd_scp__path_esc/\\\\&/g" -e 's/[*@|=]$//g' \
-e 's/[^\/]$/& /g' -e "s/^/${1-}/"))
-e 's/[^\/]$/& /g' -e "s/^/$prefix/"))
fi
}

Expand Down Expand Up @@ -557,8 +605,6 @@ _scp()
;;
esac

_expand || return

case $cur in
!(*:*)/* | [.~]*) ;; # looks like a path
*:*)
Expand Down