Menyelesaikan direktori palsu avfs di zsh

37

Bagaimana saya bisa men-tweak sistem penyelesaian zsh untuk menyelesaikan file "palsu" dalam beberapa keadaan?

Lebih tepatnya, sistem file AVFS memperlihatkan arsip sebagai direktori dengan membuat "direktori palsu" di sebelah setiap arsip. Secara default, ini mereplikasi seluruh hierarki direktori di bawah titik pemasangannya ~/.avfs. Selanjutnya, di bawah ~/.avfs, untuk setiap file arsip seperti /tmp/foo.zip, selain file arsip itu sendiri ~/.avfs/tmp/foo.zip, ada direktori yang disebut ~/.avfs/tmp/foo.zip#yang memaparkan konten arsip. Namun direktori tambahan ini tidak muncul dalam daftar ~/.avfs/tmp: hanya ada ketika diminta secara eksplisit. (Ini mirip dengan bagaimana beberapa automounters beroperasi.)

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

Ketika saya mengetik perintah seperti di atas, foo.zip#tidak muncul sebagai penyelesaian di bawah ~/.avfs/tmp/, karena tidak ada direktori seperti itu. Bagaimana saya bisa memberi tahu zsh bahwa setiap kali ada file yang path lengkapnya $arccocok ~/.avfs/**/*.(tgz|zip)¹, ia harus berpura-pura ada direktori yang dipanggil ${arc}#?

(Perhatikan bahwa saya ingin penyelesaiannya berfungsi dengan setiap panggilan _filesatau _dirs, tidak hanya untuk cdperintah. Saya lebih suka tidak harus menduplikasi kode _filesfungsi, jika mungkin.)

¹ dan semua ekstensi lainnya

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Apakah ~ / .avfs mengandung "copy" dari keseluruhan sistem file?
ctrl-alt-delor
@ Richard Ya, setiap /path/to/footerlihat sebagai ~/.avfs/path/to/foo.
Gilles 'SANGAT berhenti menjadi jahat'
Ini mungkin lebih mudah diperbaiki avfs. Jika itu mempresentasikan #entri direktori default untuk file apa pun yang cocok dengan string yang didukungnya, atau bahkan sihir menguji file dalam direktori untuk apa yang diperlukan untuk memiliki #entri, maka penyelesaiannya hanya akan berfungsi. Saya kira akan ada hit kinerja untuk sesuatu seperti findsekarang akan menjelajah melalui file terkompresi.
Matt

Jawaban:

1

Jawaban palsu tampaknya tidak cukup untuk pertanyaan palsu ini; dukungan zsh builtin untuk direktori automount beroperasi pada direktori ( fake-files dir:names), dan bukan pada pola file di dalamnya. Ini berguna untuk menambahkan file bernama tertentu ke direktori, yang mungkin cocok automountatau sshfsatau .snapshotjenis pengaturan NetApp di mana direktori yang akan dipasang adalah nama statis yang dikenal ALAS,.

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

zshall(1)mengatakan "nama" adalah string, dan eksperimen menunjukkan metakarakter (misalnya #atau \#atau '*(e:"echo hi":)') "tidak bekerja" dengan berbagai cara, sehingga tidak ada cara saya tahu untuk menyelinap segumpal ke bagian nama-nama fake-filespernyataan. (Menggali Src/Zle/computil.cmungkin akan mengungkapkan dengan tepat apa nama-nama itu, tetapi itu akan lebih berhasil.) (Juga, menggunakan gumpalan rekursif dalam posisi direktori untuk memberi nama file arsip tidak terbang, tapi sekali lagi akan membutuhkan C diving untuk melihat berapa banyak yang fake-filesmemungkinkan Anda lolos.)

Dengan compdef, seseorang dapat mendaftar .avfskelengkapan direktori:

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

Kecuali ini gagal, karena hanya akan menampilkan #file ketika itu tidak masalah, dan dengan demikian tidak dapat menyelesaikannya. (Ada kegunaan produktif untuk formulir ini, meskipun tidak untuk kasus ini.)

Menggunakan zstylemembuat Anda lebih dekat, dengan yang berikut .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'

Namun, itu hanya dapat menyelesaikan hingga \#/bit (pada squian squeeze virt dengan pengaturan default avfs), tetapi tidak ke dalam sistem file virtual untuk arsip, jadi pekerjaan tambahan akan diperlukan untuk melengkapi tab ke dalam arsip. Saya menebak-nebak melalui _call_program ... lsatau sesuatu di sepanjang baris untuk penyelesaian di \#bit, kecuali ada cara yang lebih elegan untuk zshpercaya bahwa direktori yang tidak ada lakukan.

Kabar buruk! Penyelesaian tidak berhasil melalui _path_filesdirektori palsu; Saya menduga ini terkait zsh globbing. Baik zsh 4.something on dan zsh 5.0.8 menunjukkan masalah. Jadi saya curiga bahwa perbaikan yang lengkap akan membutuhkan tambalan _path_files, atau untuk menulis sesuatu yang berbeda yang diselesaikan pada direktori palsu ini. Jejak debugging penyelesaian dapat dihasilkan dengan mengetik ls /root/.avfs/root/sometar.gz\#/dan kemudian pada akhir mengetik itu control-xdan kemudian ?, dengan asumsi bindkey -edan itu _complete_debugpasti kata keycombo, jika seseorang ingin menyelidiki mengapa ini gagal.

thrig
sumber
0

Di zsh Anda dapat menggunakan compctl -Kuntuk mendaftarkan fungsi Anda sendiri ke opsi penyelesaian generasi. Sebagai contoh:

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

Maka Anda perlu mendefinisikan fungsi Anda sendiri:

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 ... )
}

Jelas hal di atas membutuhkan lebih banyak pekerjaan, tetapi itu adalah sesuatu untuk memulai.

Fungsi penyelesaian kustom yang serupa (tetapi berbeda) dapat didaftarkan untuk bash.

Berikut ini adalah contoh dengan implementasi untuk bash dan zsh . (Ini menawarkan penyelesaian opsi baris perintah dengan mengambil opsi dari halaman manual perintah.)

Dan berikut adalah beberapa tebakan cepat pada hal-hal yang mungkin berfungsi di dalam fungsi penyelesaian Anda:

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

Atau mungkin ini:

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

Semoga berhasil!

joeytwiddle
sumber
Saya tahu cara menulis fungsi penyelesaian, terima kasih banyak. Masalahnya adalah bagaimana memodifikasi mekanisme penyelesaian yang ada untuk file. Perhatikan bahwa saya menggunakan mekanisme penyelesaian "baru", bukan compctl, yaitu saya ingin mengubah apa yang _filesdilakukan. Jawaban Anda sama sekali tidak membantu.
Gilles 'SANGAT berhenti menjadi jahat'
@Gilles Tidak memulai perang api, dan dengan risiko salah, setidaknya dia mencoba ... Ini telah duduk di "loteng" yang belum terjawab 2 tahun plus ... +1 t reset ke 0 untuk upaya .
eyoung100
@ eyoung100 Tolong jangan beri +1 untuk usaha (tidak berarti usaha itu terlihat di sini). Membalas jawaban yang tidak membantu merusak situs.
Gilles 'SANGAT berhenti menjadi jahat'