Prosím, odpusťte mi, pokud zde dělám něco hloupého, dokumentace je obrovská a vyhledávání zatím nic nenašlo.
Snažím se vytvořit dokončení shellu pro můj vlastní skript s názvem fab
. Pro bash to bylo snadné, stačí je vložit do /etc/bash_completion.d
a fungují. Ale chlapče, to je zsh PITA…
Mám funkci dokončení _fab
a funguje to dobře, když je povoleno pomocí compdef _fab fab
. Vložil jsem to do /usr/share/zsh/vendor-completions/_fab
který už byl v mém $fpath
. Soubor začíná #compdef fab
a končí compdef _fab fab
. Vypadá dobře:
$ type _fab
_fab is an autoload shell function
Ale kdykoli jsem spustil nový shell, fab
dokončení nefungovalo (další funkce z vendor-completions
, například _docker
, jsme v pohodě). compinit
opraveno pro tento konkrétní shell. Přišel jsem na to, že rm ~/.zcompdump ~/.zcompdump-$(hostname)-5.1.1; compinit
aby to fungovalo trvale (5.1.1 =moje verze zsh).
Otázky:
- Co a kdy čte
~/.zcompdump
nastavit počáteční dokončení? -
man zshall
říká:Další vyvolání compinit přečte dumpingový soubor namísto provedení úplné inicializace.
Pokud tomu tak bylo,
compinit
by neopravil moje dokončení, dokud nesmažu~/.zcompdump
, že jo? Uniká mi něco? - Co je
~/.zcompdump-$(hostname)-5.1.1
a jak to souvisí s.zcompdump
? Jediný rozdíl je v jednom dokončení, které je v~/.oh-my-zsh/completions
(protože$ZSH
ukazuje na~/.oh-my-zsh
). Je to něco? - Pokud bych měl zabalit tato dokončení do redistribuovatelného balíčku nebo vytvořit instalační skript, kam bych měl umístit dokončení zsh a co dalšího bych měl během instalace udělat, abych se ujistil, že vše funguje?
Zaměřuji se na Ubuntu 16.04, 18.04 a 19.04, ale vítám informace, které nejsou specifické pro distribuci. Testuji to na Ubuntu 16.04 se zsh 5.1.1 a nedávným oh-my-zsh.
Přijatá odpověď:
TL,DR:V normálním provozu stačí přetáhnout soubor do příslušného adresáře. Během testování musíte odstranit soubor mezipaměti (.zcompdump
ve výchozím nastavení, ale uživatelé jej mohou umístit na jiné místo a oh-my-zsh jej umístí na jiné místo).
Jednoduchá odpověď je napsat funkci dokončení do souboru, kde první řádek je #compdef fab
. Soubor musí být v adresáři na $fpath
.
Soubor může obsahovat buď tělo funkce, nebo definici funkce následovanou voláním funkce. To znamená, že buď soubor obsahuje něco jako
#compdef fab
_arguments …
nebo
#compdef fab
function _fab {
_arguments …
}
_fab "[email protected]"
Soubor se musí nacházet na $fpath
před compinit
běží. To znamená, že musíte věnovat pozornost pořadí věcí v .zshrc
:nejprve přidejte libovolné vlastní adresáře do $fpath
a poté zavolejte compinit
. Pokud používáte rámec, jako je oh-my-zsh, nezapomeňte přidat jakékoli vlastní adresáře do $fpath
před kódem oh-my-zsh.
compinit
je funkce, která inicializuje dokončovací systém. Přečte všechny soubory v $fpath
a zkontroluje jejich první řádek na magické příkazy #autoload
a #compdef
.
.zcompdump
je soubor mezipaměti používaný compinit
. ~/.zcompdump
je výchozí umístění; při spuštění compinit
můžete zvolit jiné umístění . Oh-my-zsh volá compinit
pomocí -d
možnost použít jiný název souboru mezipaměti daný proměnnou ZSH_COMPDUMP
, která je výchozí
ZSH_COMPDUMP="${ZDOTDIR:-${HOME}}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
Název hostitele je uveden kvůli lidem, jejichž domovský adresář je sdílen mezi počítači a kteří mohou mít na různých počítačích nainstalován odlišný software. Verze zsh je zahrnuta, protože soubor mezipaměti je nekompatibilní mezi verzemi (obsahuje kód, který se verze od verze mění).
Související:Co dělá CTRL+V ve vim?
Myslím, že všechny vaše problémy jsou způsobeny zastaralým souborem mezipaměti (a to vás přimělo situaci příliš zkomplikovat). Algoritmus zsh k určení, zda je soubor mezipaměti zastaralý, bohužel není dokonalý, pravděpodobně v zájmu rychlosti. Nekontroluje obsah ani časová razítka souborů na $fpath
, prostě je počítá. .zcompdump
soubor začíná řádkem jako
#files: 858 version: 5.1.1
Pokud je verze zsh a počet souborů správný, zsh načte soubor mezipaměti.
Soubor mezipaměti obsahuje pouze přidružení mezi názvy příkazů, nikoli kód funkcí dokončení. Zde je několik běžných scénářů, kdy mezipaměť funguje transparentně:
- Pokud do
$fpath
přidáte nový soubor , toto zruší platnost mezipaměti. - Obecněji, pokud přidáváte a odebíráte soubory na
$fpath
a celkový počet odstraněných souborů není stejný jako celkový počet odstraněných souborů, což znehodnocuje mezipaměť. - Pokud přesunete soubor do jiného adresáře v
$fpath
beze změny názvu to neovlivní nic, co je v mezipaměti, takže mezipaměť zůstane správná. - Pokud upravíte soubor v
$fpath
beze změny prvního řádku to neovlivní nic, co je v mezipaměti, takže mezipaměť zůstane správná.
Zde jsou některé běžné scénáře, kdy se mezipaměť stane neplatnou, ale zsh si to neuvědomuje.
- Přidáte nějaké soubory do
$fpath
a odstraňte přesně stejný počet souborů. - Přejmenujete soubor v
$fpath
. - Přidáte nebo upravíte
#compdef
(nebo#autoload
) řádek v horní části souboru.
Poslední bod je to, co má tendenci kousat během testování. Pokud změníte #compdef
řádek, musíte odstranit .zcompdump
soubor a restartujte zsh (nebo znovu spusťte compinit
).
Pokud vložíte dokončení do redistribuovatelného balíčku, jednoduše přesuňte soubor dokončení do adresáře, který je v systémovém $fpath
. Pro balíček Ubuntu je vhodné místo /usr/share/zsh/vendor-completions
. Pro něco nainstalovaného pod /usr/local
, to je /usr/local/share/zsh/site-functions
. To je vše, co musíte udělat.
Jedna věc, která není transparentní, je, pokud potřebujete změnit #compdef
řádek při upgradu nebo pokud odstraníte nebo přejmenujete některé soubory. V takových případech budou uživatelé muset odstranit svůj soubor mezipaměti, a to není něco, co můžete udělat z balíčku, který se nainstaluje na víceuživatelský počítač.