I have the following zsh function which lets me edit symbolic links using the vared
ZLE builtin.
function lned {
emulate zsh
setopt err_return extended_glob local_options local_traps
local -a data
link_path=${1%%/##}
zstat -A data -L +link $link_path
target=$data[1]
if [[ -z $target ]]; then
print -rl 1>&2 "$link_path: not a symbolic link"
return 2
fi
vared -p "${(q)1} -> " target
if [[ -n $target && "$target" != "$data[1]" ]]; then
# We can't use 'ln -sf' if $link_path is a symlink to a directory, so remove
# it manually first.
# Check that this is still a symlink, in case the file was changed while we
# were editing (this leaves only a very small time interval where we might
# remove a non-symlink).
rm -- $link_path(@)
ln -s -- $target $link_path
fi
}
This is nice, but when I'm editing a relative symbolic link in a directory other than the current one, the file name completions are relative to the wrong directory. I want to fix that.
I could run pushd -- $link_path:h/
before calling vared
and popd
afterwards. However, this would not restore the current directory if the user interrupted the shell by pressing Ctrl+C at the wrong moment. This can be solved by setting traps exactly right, and maybe using cd
rather than pushd
, which is probably useful also to avoid having to detect whether the link is in the current directory (in which case pushd
wouldn't push anything).
I'd like to minimize the disruption caused by the directory change, which means also locally turning off chpwd
, restoring OLDPWD
, and perhaps more which I'm not thinking of. Also, if I have no permission to cd
back into the current directory, I'd be in a lurch — this is a very rare case but I'd prefer to support it.
It would be simpler if I could just set things up so that files are completed relative to a different directory during the vared
call. How can I do that? If this is impossible, what's the best way to minimize the impact of a temporary directory change?
compdef myfunction -vared-
. See zsh.org/mla/users/2007/msg01187.html for an example.ln -s tmq link; mkdir tmp; cd tmp; lned ../link
then press BackSpace and Tab. Completion offers nothing (because you're in an empty directory), buttmp
is a valid target for the link.