如何禁用 NFS 目录的 zsh 选项卡完成?

SRo*_*mes 7 zsh nfs

我使用zsh它的选项卡完成。当我不小心在(缓慢的)NFS 目录中点击选项卡时,zsh花费的时间太长了。更糟糕的是,如果 NFS 关闭,而我点击了/mnt/[tab],我的整个 shell 就会锁定。

如何zsh在这些目录中禁用选项卡完成?

mpy*_*mpy 5

如果您位于这些目录中,要完全禁用完成功能,可以使用以下代码:

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
Run Code Online (Sandbox Code Playgroud)

这定义了一个函数来检查您的工作目录是否以/mnt/. 如果没有,则通过调用默认完成函数,zle expand-or-complete否则会发出蜂鸣声。该函数被声明为小部件 ( zle -N) 并绑定到TAB( bindkey)。

然而,这只是一个开始,因为当你做这样的事情时

/foo/bar$ cp hello.c /mnt/[TAB]
Run Code Online (Sandbox Code Playgroud)

你又迷路了。因此,您还必须将/mnt/树从完成系统中排除。根据应该解决这个问题的文档:

zstyle ':completion:*:*files' ignored-patterns '/mnt/*'
zstyle ':completion:*:*directories' ignored-patterns '/mnt/*'
Run Code Online (Sandbox Code Playgroud)

但我不确定这是否会阻止任何 stat 函数调用/mnt/或仅删除之后的匹配项。请尝试,如果仍然存在明显的延迟,请将函数中的 if 子句扩展restricted-expand-or-complete

if [[ ! $PWD = /mnt/* && ! ${${(z)LBUFFER}[-1]} = */mnt/* ]]
Run Code Online (Sandbox Code Playgroud)

[编辑]

我重新设计了这个黑客,使其更加灵活,但它仍然存在问题,而且我仍然确信直接修改完成函数(也许_path_files)会更干净。然而...

这有效(示例中的摘要):

  • ls <TAB>被阻塞在慢速目录 ( /mnt)内
  • ls /mnt/<TAB>被阻止
  • ls /home/user/symlink_to_mnt/<TAB>被阻止
  • cd /; ls mnt/<TAB>被阻止
  • tar --exclude-from=/mnt/<TAB>被阻止(还有其他变体、符号链接、相对路径)

这不起作用:

  • 路径内完成仍然完成/m/s/p/mnt/some/path
  • 如果选项不以 开头,则命令选项的完成将被阻止-,例如apt-get inst<TAB>在 /mnt 内不起作用
  • /Cygwin 下发生奇怪的行为,在 Linux 下一切正常

这是代码:

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
Run Code Online (Sandbox Code Playgroud)