Завершение фальшивых каталогов avfs в zsh

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)should, он должен делать вид, что существует каталог с именем ${arc}#?

(Обратите внимание, что я хочу, чтобы завершение работало с каждым вызовом _filesили _dirs, а не только с cdкомандой. Я бы предпочел не дублировать код _filesфункции, если это возможно.)

¹ и все остальные расширения

Жиль "ТАК - прекрати быть злым"
источник
Содержит ли ~ / .avfs «копию» всей файловой системы?
Ctrl-Alt-Delor
@ Richard Да, каждый /path/to/fooвиден как ~/.avfs/path/to/foo.
Жиль "ТАК - перестань быть злым"
Это может быть легче исправить avfs. Если он представляет #запись каталога по умолчанию для любых файлов, которые соответствуют строкам, которые он поддерживает, или даже магически проверяет файлы в каталоге на предмет того, что нужно для #записи, тогда завершение будет просто работать. Я полагаю, что это может привести к снижению производительности примерно так же, findкак это теперь происходит при сжатии сжатых файлов.
Мэтт

Ответы:

1

Поддельный ответ кажется недостаточным для этого поддельного вопроса; встроенная поддержка zsh для каталогов automount работает с каталогами ( fake-files dir:names), а не с шаблонами файлов в них. Это удобно , чтобы добавить конкретные именованные файлы в каталог, который может удовлетворить automountили sshfsили NetApp .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'

Тем не менее, он может выполняться только до \#/мелочей (в debian squeeze virt с настройкой avfs по умолчанию), но не в виртуальной файловой системе для архива, поэтому потребуется дополнительная работа, чтобы завершить вкладку в архив. Я догадываюсь через _call_program ... lsили что-то в этом духе для дополнений \#, если нет более элегантного способа zshверить, что несуществующие каталоги существуют.

Плохие новости! Завершение не проходит через _path_filesподдельные каталоги; Я подозреваю, что это связано с Zsh Globbing. Как zsh 4.something on, так и zsh 5.0.8 демонстрируют проблему. Поэтому я подозреваю, что для полного исправления потребуются исправления _path_filesили запись чего-то другого, что в противном случае завершается на этих поддельных каталогах. Трассировка отладки завершения может быть сгенерирована, набрав ls /root/.avfs/root/sometar.gz\#/и затем в конце этого набора, control-xа затем ?, если предположить, bindkey -eчто _complete_debugэто связано с указанным сочетанием клавиш, если кто-то хочет разобраться, почему это не удается.

thrig
источник
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+$+#+') )

Удачи!

joeytwiddle
источник
Я знаю, как написать функцию завершения, большое спасибо. Проблема в том, как изменить существующий механизм завершения для файлов. Обратите внимание, что я использую «новый» механизм завершения, compctlто есть я хочу изменить то, что _filesделает. Ваш ответ не поможет вообще.
Жиль "ТАК - перестань быть злым"
@ Жиль Не начинать пламенную войну и рискуя ошибиться, по крайней мере, он пытался ... Это сидело на "чердаке" без ответа 2 года плюс ... +1 т сбрасывается в 0 за усилия ,
eyoung100
@ eyoung100 Пожалуйста, не давайте +1 за усилие (здесь это не очевидно). Проголосование бесполезных ответов наносит ущерб сайту.
Жиль "ТАК - перестань быть злым"