9

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?

1 Answer 1

5

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 blocked
  • ls /home/user/symlink_to_mnt/<TAB> is blocked
  • cd /; ls mnt/<TAB> is blocked
  • tar --exclude-from=/mnt/<TAB> is blocked (an also the other variants, symlink, relative path)

This doesn't work:

  • in-path completion still completes /m/s/p to /mnt/some/path
  • completion of command options is blocked, if the option does not start with -, e.g. apt-get inst<TAB> won't work inside /mnt
  • in / strange behavior occurs under Cygwin, with Linux everything is fine

And 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
7
  • The function worked, the zstyle didn't. But, there are still ways that the completion gets triggered but doesn't match the LBUFFER - and, I only want to skip completion on that part, not on other things when I'm in that dir. Is there any way to simply omit checking from these dirs, without using the LBUFFER hack? Apr 22, 2013 at 21:12
  • @SRobertJames: You are right, this solution has some issues. I'm not aware of a possibility to exclude a specific path hierarchy from completion completely -- that does not mean, there is none (/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/*.
    – mpy
    Apr 22, 2013 at 22:33
  • 1
    Thanks, that's a neat solution. The other issue I had with LBUFFER hack is I have symlink to ~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
  • @SRobertJames: Yesterday I would have said "no", but today I had some more ideas. There are still issues (I made a list with what came to my mind), but this is the best you can get from me ;)
    – mpy
    Apr 23, 2013 at 11:23
  • Neat, I'm going to check this out. Where do I specify the names of my NFS dirs and their symlinks? BTW is this problem unique to zsh, or does bash suffer from it too? Apr 25, 2013 at 1:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .