Skip to content

Commit

Permalink
Merge branch 'fix-zsh-completion-for-devices-with-spaces'
Browse files Browse the repository at this point in the history
  • Loading branch information
coldfix committed Nov 23, 2023
2 parents 920cc29 + aec600e commit c9987ff
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 4 deletions.
132 changes: 132 additions & 0 deletions completions/zsh/_udiskie-canonical_paths
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#autoload

# NOTE:
# This file is a copy of the upstream _canonical_paths file that was modified
# to fix a problem with device names that contain spaces (see #253).
# The fix was taken from a discussion on the zsh-workers mailing list, see:
# https://www.zsh.org/mla/workers/2022/msg01377.html
# The original file is usually installed at:
# /usr/share/zsh/functions/Completion/Unix/_canonical_paths


# This completion function completes all paths given to it, and also tries to
# offer completions which point to the same file as one of the paths given
# (relative path when an absolute path is given, and vice versa; when ..'s are
# present in the word to be completed, and some paths got from symlinks).

# Usage: _udiskie-canonical_paths [-A var] [-N] [-MJV12onfX] tag desc [paths...]

# -A, if specified, takes the paths from the array variable specified. Paths
# can also be specified on the command line as shown above. -N, if specified,
# prevents canonicalizing the paths given before using them for completion, in
# case they are already so. `tag' and `desc' arguments are well, obvious :) In
# addition, the options -M, -J, -V, -1, -2, -o, -n, -F, -x, -X are passed to
# compadd.

_udiskie-canonical_paths_add_paths () {
# origpref = original prefix
# expref = expanded prefix
# curpref = current prefix
# canpref = canonical prefix
# rltrim = suffix to trim and readd
local origpref=$1 expref rltrim curpref canpref subdir
[[ $2 != add ]] && matches=()
expref=${~origpref} 2>/dev/null
[[ $origpref == (|*/). ]] && rltrim=.
curpref=${${expref%$rltrim}:-./}
canpref=$curpref:P
[[ $curpref == */ && $canpref == *[^/] ]] && canpref+=/
canpref+=$rltrim
[[ $expref == *[^/] && $canpref == */ ]] && origpref+=/

# Append to $matches the subset of $files that matches $canpref.
if [[ $canpref == $origpref ]]; then
# This codepath honours any -M matchspec parameters.
() {
local -a tmp_buffer
compadd -A tmp_buffer "$__gopts[@]" -a files
matches+=( "${(@)tmp_buffer/$canpref/$origpref}" )
}
else
# ### Ideally, this codepath would do what the 'if' above does,
# ### but telling compadd to pretend the "word on the command line"
# ### is ${"the word on the command line"/$origpref/$canpref}.
# ### The following approximates that.
matches+=(${(q)${(M)files:#$canpref*}/$canpref/$origpref})
fi

for subdir in $expref?*(@); do
_udiskie-canonical_paths_add_paths ${subdir/$expref/$origpref} add
done
}

_udiskie-canonical_paths() {
# The following parameters are used by callee functions:
# __gopts
# matches
# files
# (possibly others)

local __index
typeset -a __gopts __opts

zparseopts -D -a __gopts M+: J+: V+: o+: 1 2 n F: x+: X+: A:=__opts N=__opts

: ${1:=canonical-paths} ${2:=path}

__index=$__opts[(I)-A]
(( $__index )) && set -- $@ ${(P)__opts[__index+1]}

local expl ret=1 tag=$1 desc=$2

shift 2

if ! zmodload -F zsh/stat b:zstat 2>/dev/null; then
_wanted "$tag" expl "$desc" compadd $__gopts $@ && ret=0
return ret
fi

typeset REPLY
typeset -a matches files

if (( $__opts[(I)-N] )); then
files=($@)
else
files+=($@:P)
fi

local base=$PREFIX
typeset -i blimit

_udiskie-canonical_paths_add_paths $base

if [[ -z $base ]]; then
_udiskie-canonical_paths_add_paths / add
elif [[ $base == ..(/.(|.))#(|/) ]]; then

# This style controls how many parent directory links (..) to chase searching
# for possible completions. The default is 8. Note that this chasing is
# triggered only when the user enters at least a .. and the path completed
# contains only . or .. components. A value of 0 turns off .. link chasing
# altogether.

zstyle -s ":completion:${curcontext}:$tag" \
canonical-paths-back-limit blimit || blimit=8

if [[ $base != */ ]]; then
[[ $base != *.. ]] && base+=.
base+=/
fi
until [[ $base.. -ef $base || blimit -le 0 ]]; do
base+=../
_udiskie-canonical_paths_add_paths $base add
blimit+=-1
done
fi

_wanted "$tag" expl "$desc" compadd $__gopts -Q -U -a matches && ret=0

return ret
}

_udiskie-canonical_paths "$@"
2 changes: 1 addition & 1 deletion completions/zsh/_udiskie-mount
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function _udiskie-mount
local dev_tmp mp_tmp
dev_tmp=( $(udiskie-info -a) )
_alternative \
'device-paths: device path:_canonical_paths -A dev_tmp -N device-paths device\ path' \
'device-paths: device path:_udiskie-canonical_paths -A dev_tmp -N device-paths device\ path' \
&& ret=0
;;
esac
Expand Down
6 changes: 3 additions & 3 deletions completions/zsh/_udiskie-umount
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ function _udiskie-umount
loop_tmp=( ${loop_tmp##*<:5:>} )

_alternative \
'directories:mount point:_canonical_paths -A mp_tmp -N directories mount\ point' \
'device-paths: device path:_canonical_paths -A dev_tmp -N device-paths device\ path' \
'loop-files: loop file:_canonical_paths -A loop_tmp -N loop-files loop\ file' \
'directories:mount point:_udiskie-canonical_paths -A mp_tmp -N directories mount\ point' \
'device-paths: device path:_udiskie-canonical_paths -A dev_tmp -N device-paths device\ path' \
'loop-files: loop file:_udiskie-canonical_paths -A loop_tmp -N loop-files loop\ file' \
&& ret=0

;;
Expand Down

0 comments on commit c9987ff

Please sign in to comment.