在zsh中完成avfs假目录

在zsh中完成avfs假目录

在某些情况下,如何调整 zsh 的完成系统来完成“假”文件?

更准确地说,AVFS文件系统通过在每个档案旁边创建一个“假目录”来将档案公开为目录。默认情况下,它会在其安装点下复制整个目录层次结构~/.avfs。此外,在 下~/.avfs,对于每个存档文件,例如/tmp/foo.zip,除了存档文件本身之外~/.avfs/tmp/foo.zip,还有一个名为 的目录~/.avfs/tmp/foo.zip#,它公开了存档的内容。然而,这个额外的目录不会出现在列表中~/.avfs/tmp:它仅在明确请求时才存在。 (这类似于某些自动安装程序的操作方式。)

mountavfs
cd ~/.avfs/tmp/foo.zip\#

当我输入类似上面的命令时,foo.zip#不会在 下显示为完成~/.avfs/tmp/,因为没有这样的目录。我如何告诉 zsh 每当有一个文件的完整路径与 1$arc匹配~/.avfs/**/*.(tgz|zip)时,它就应该假装有一个名为 的目录${arc}#

(请注意,我希望完成功能适用于每次调用_filesor _dirs,而不仅仅是命令cd。如果可能的话,我希望不必重复函数的代码_files。)

所有其余的扩展

答案1

对于这个假问题,假答案似乎不够; zsh 对自动挂载目录的内置支持在目录 ( fake-files dir:names) 上运行,而不是在其中的文件模式上运行。这可以方便地将特定的命名文件添加到目录中,这可能适合automountsshfs或 NetApp.snapshot类型设置,其中要安装的目录是已知的静态名称,ALAS.

autoload -U compinit
compinit
zstyle ':completion:*' fake-files $HOME/.avfs:'ALAS POOR YORICK'

zshall(1)说“名称”是字符串,实验表明元字符(例如#or\#'*(e:"echo hi":)')以各种方式“不起作用”,所以我不知道如何将 glob 偷偷添加到语句的名称部分fake-files。 (深入研究Src/Zle/computil.c可能会准确地揭示名称的含义,但这会需要更多工作。)(此外,在目录位置中使用递归 glob 来命名存档文件并不可行,但再次需要 C 潜水才能看到让fake-files多少你逃脱了。)

使用compdef,可以列出.avfs目录完成情况:

compdef '_files -g $HOME/.avfs/\*' -p \^
function andthehash {
  reply=($REPLY $REPLY\#)
}
compdef "_files -g $HOME/.avfs/'*(+andthehash)'" -p \^

但此操作会失败,因为它只会#在无关紧要的情况下显示文件,因此无法完成它们。 (这种形式有很多富有成效的用途,但不适用于本例。)

使用zstyle可以让您更接近,如下所示.zshrc

autoload -U compinit
compinit

function UnderAVFS {
  local pdir
  [[ -z $1 ]] && return 1
  pdir=$1:a
  [[ ! -d $pdir ]] && pdir=$pdir:h
  [[ ! -d $pdir || $pdir == . ]] && return 1
  while [[ $pdir != / ]]; do
    [[ $pdir == $HOME/.avfs ]] && return 0
    pdir=$pdir:h
  done
  return 1
}

function AVFSExtras {
  if UnderAVFS $REPLY; then
    reply=($REPLY)
    # TODO embiggen list of archive suffixes
    [[ $REPLY == *.(bz2|tbz2) ]] && reply+=($REPLY\#)
  fi
}

# Try to match avfs, otherwise the default pattern. Probably could greatly
# benefit from caching, to avoid hits on UnderAVFS function.
zstyle ':completion:*' file-patterns '*(+AVFSExtras):avfs-files' '%p:all-files'

但是,它只能完成该\#/位(在具有默认 avfs 设置的 debian squeeze virt 上),但不能完成存档的虚拟文件系统,因此需要额外的工作才能完成存档。我猜测via_call_program ... ls或类似的东西可以完成位\#,除非有一种更优雅的方法来zsh相信不存在的目录确实存在。

坏消息!_path_files对于假目录,补全不会成功;我怀疑这与 zsh 通配相关。 zsh 4.something on 和 zsh 5.0.8 都出现了该问题。因此,我怀疑完整的修复需要对 进行修补_path_files,或者编写一些不同的内容,否则可以在这些假目录上完成。如果有人想深入研究失败的原因,可以通过输入ls /root/.avfs/root/sometar.gz\#/和 然后在该输入结束时输入 来生成完成调试跟踪control-x,然后?假设bindkey -e和绑定到所述组合键。_complete_debug

答案2

在 zsh 中,您可以使用compctl -K注册自己的函数来生成完成选项。例如:

compctl -f -c -u -r -K myAVFScompletion "*" -tn

然后你需要定义你自己的函数:

myAVFScompletion () {
    read -c COMMAND ARGS

    # Decide what paths you want to suggest completion for
    # by looking inside the ~/.avfs folder.

    # Place your suggestions into an array:
    reply=( a_path b_path ... )
}

显然,上述内容还需要做更多的工作,但这是一个开始。

可以为 bash 注册类似(但不同)的自定义完成函数。

这是bash 和 zsh 实现的示例。 (它通过从命令的手册页中获取选项来完成命令行选项。)

以下是对完成函数中可能起作用的一些快速猜测:

if [[ -d "$ARGS#" ]]
then reply=( "$ARGS#" )
else reply=
fi

或者也许是这样的:

reply=( $(find ~/.avfs -type f -name "*.tgz" -or -name "*.zip" | sed 's+$+#+') )

祝你好运!

相关内容