I use zsh
and its tab completion. When I accidentally hit tab in a (slow) NFS dir, zsh
takes way too long. Even worse, if the NFS is down, and I hit /mnt/[tab]
, my whole shell locks up.
How can I disable zsh
tab completion in these dirs?
To disable the completion completely if you are in those directories, you can use this code:
function restricted-expand-or-complete() {
if [[ ! $PWD = /mnt/* ]]; then
zle expand-or-complete
else
echo -en "\007"
fi
}
zle -N restricted-expand-or-complete
bindkey "^I" restricted-expand-or-complete
This defines a function which checks if your working directory starts with /mnt/
. If not, the default completion function is called via zle expand-or-complete
otherwise a beep is produced.
The function is declared as a widget (zle -N
) and bound to TAB (bindkey
).
However, this is only a start, because when you do somethine like that
/foo/bar$ cp hello.c /mnt/[TAB]
you are lost again. So you also had to exclude the /mnt/
tree from completion system. According to the doc that should do the trick:
zstyle ':completion:*:*files' ignored-patterns '/mnt/*'
zstyle ':completion:*:*directories' ignored-patterns '/mnt/*'
But I'm not sure if that'll prevent any stat function call to /mnt/
or only removes the matches afterwards. Please try and if there's still a noticable delay, extend the if clause in the restricted-expand-or-complete
function to
if [[ ! $PWD = /mnt/* && ! ${${(z)LBUFFER}[-1]} = */mnt/* ]]
[EDIT]
I reworked this hack to be more flexible, but it still has issues and I'm still positive directly modifying the completion functions (perhaps _path_files
) would be much cleaner. However...
This works (a summary in examples):
ls <TAB>
is blocked inside a slow dir (/mnt
)ls /mnt/<TAB>
is blockedls /home/user/symlink_to_mnt/<TAB>
is blockedcd /; ls mnt/<TAB>
is blockedtar --exclude-from=/mnt/<TAB>
is blocked (an also the other variants, symlink, relative path)This doesn't work:
/m/s/p
to /mnt/some/path
-
, e.g. apt-get inst<TAB>
won't work inside /mnt/
strange behavior occurs under Cygwin, with Linux everything is fineAnd here's the code:
function restricted-expand-or-complete() {
# split into shell words also at "=", if IFS is unset use the default (blank, \t, \n, \0)
local IFS="${IFS:- \n\t\0}="
# this word is completed
local complt
# if the cursor is following a blank, you are completing in CWD
# the condition would be much nicer, if it's based on IFS
if [[ $LBUFFER[-1] = " " || $LBUFFER[-1] = "=" ]]; then
complt="$PWD"
else
# otherwise take the last word of LBUFFER
complt=${${=LBUFFER}[-1]}
fi
# determine the physical path, if $complt is not an option (i.e. beginning with "-")
[[ $complt[1] = "-" ]] || complt=${complt:A}/
# activate completion only if the file is on a local filesystem, otherwise produce a beep
if [[ ! $complt = /mnt/* && ! $complt = /another/nfs-mount/* ]]; then
zle expand-or-complete
else
echo -en "\007"
fi
}
zle -N restricted-expand-or-complete
bindkey "^I" restricted-expand-or-complete
/usr/share/zsh/5.0.2/functions/_files
might be a starting point). I improved the LBUFFER hack a little bit, so completion is only disabled if the last word in LBUFFER contains */mnt/*
.
~srj/proj1/data
(data is on NFS). I'd like tab completion while I'm in proj1
, but not for data
. Is there a solution?
Apr 23, 2013 at 3:17
;)