在zsh中完成avfs伪目录


37

在某些情况下,如何调整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,只要有一个完整路径$arc匹配~/.avfs/**/*.(tgz|zip)¹ 的文件,它就应该假装存在一个名为的目录${arc}#

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

¹ 以及所有其他扩展名


〜/ .avfs是否包含整个文件系统的“副本”?
ctrl-alt-delor 2014年

@richard是的,每个/path/to/foo都可以通过看到~/.avfs/path/to/foo
吉尔斯(Gillles)“所以-别再邪恶了”

在中修复可能会更容易avfs。如果它提供了#与它支持的字符串相匹配的任何文件的默认目录条目,或者甚至对目录中的文件进行了魔术测试以查找需要具有#条目的内容,那么完成工作就可以了。我猜想像这样的东西会降低性能,find因为它现在会通过压缩文件进行拖网。
马特

Answers:


1

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

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

zshall(1)说“名称”是字符串,并且实验表明元字符(例如#\#'*(e:"echo hi":)')以各种方式“不起作用”,因此我不知道有什么方法可以将全局变量放到fake-files语句的名称部分。(钻研过Src/Zle/computil.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压缩virt上),而不能完成存档的虚拟文件系统,因此,需要完成一些附加工作才能完全完成存档。我正在猜测是通过via _call_program ... ls还是类似的东西来完成\#,除非有一种更优雅的方法可以让您zsh相信不存在的目录可以完成。

坏消息!完成不会使_path_files伪目录通过;我怀疑这与zsh遍历有关。zsh 4.something和zsh 5.0.8都存在此问题。因此,我怀疑完整的修复程序将需要修补程序_path_files,或编写与其他伪造目录有关的其他内容。可以通过打字来生成完成调试跟踪ls /root/.avfs/root/sometar.gz\#/,然后在该打字结束control-x?,假设bindkey -e_complete_debug必然说keycombo,如果有人想通过深入研究为什么这种失败。


0

在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+$+#+') )

祝好运!


我知道如何编写完成功能,非常感谢。问题是如何修改文件的现有完成机制。请注意,我没有使用“新”完成机制compctl,即我想更改_files功能。您的回答根本没有帮助。
吉尔(Gilles)“所以,别再邪恶了”

@吉尔斯(Gilles)不要发动火焰战争,冒着犯错的危险,至少他尝试过...这已经坐了2年未回答的“阁楼”了... +1 t重置为0 。
eyoung100

@ eyoung100请不要付出+1的努力(在这里显然努力不明显)。提出无用的答案对站点不利。
吉尔斯(Gillles)“所以-别再作恶了”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.