How to properly make custom zsh completions “just work”?zsh refusing to accept new autocomplete scriptgit...
What should we do with manuals from the 80s?
What would it take to get a message to another star?
Why do so many people play out of turn on the last lead?
What is the hottest thing in the universe?
Simulation optimisation: Monte carlo simulation, regression, optimise within regression model?
Output the list of musical notes
Why won't the Republicans use a superdelegate system like the DNC in their nomination process?
Go to last file in vim
What modifiers are added to the attack and damage rolls of this unique longbow from Waterdeep: Dragon Heist?
Who is the controller of a Pacifism enchanting my creature?
What can Amex do if I cancel their card after using the sign up bonus miles?
Is it possible to represent any positive integer with a sum of arbitrarily many distinct powers of 3, 5, and 7?
Is there any way I will not use l'Hôpital's rule here?
How can I communicate my issues with a potential date's pushy behavior?
Cycle of actions and voice signals on a multipitch climb
Where can I find the records of WW1 deserters?
Unconventional examples of mathematical modelling
Sum Square Difference, which way is more Pythonic?
Telephone number in spoken words
Why aren't rainbows blurred-out into nothing after they are produced?
Suspension compromise for urban use
Do I have to cite common CS algorithms?
"Mouth-breathing" as slang for stupidity
Why aren’t there water shutoff valves for each room?
How to properly make custom zsh completions “just work”?
zsh refusing to accept new autocomplete scriptgit completion with zsh: filenames with spaces aren't being escaped properlyHow to combine zsh autocomplete for wrapper function arguments and existing commandDynamic zsh autocomplete for custom commandsZsh git filename completion with “--git-dir=… --work-tree=…”: not a git repositorytmux stopped working properly with zsh and oh-my-zshCustom bash tab completion showing possible completions, but not actually completing inputHow to make custom zsh script executable automatically?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
Please forgive me if I'm doing something stupid here, the documentation is huge and searching didn't turn up anything yet.
I'm trying to create shell completions for my custom script called fab. For bash it was easy, just drop them in /etc/bash_completion.d and they work. But oh boy, is zsh a PITA...
I have the completion function _fab and it works fine when enabled with compdef _fab fab. I put it in /usr/share/zsh/vendor-completions/_fab which already was in my $fpath. The file starts with #compdef fab and ends with compdef _fab fab. Looks good:
$ type _fab
_fab is an autoload shell function
But whenever I started a new shell, fab completions didn't work (other functions from vendor-completions, like _docker, were fine). compinit fixed this for that specific shell. I figured out that rm ~/.zcompdump ~/.zcompdump-$(hostname)-5.1.1; compinit make it work permanently (5.1.1 = my zsh version).
Questions:
- What and when reads
~/.zcompdumpto set up initial completions?
man zshallsays:
The next invocation of compinit will read the dumped file instead of performing a full initialization.
If that was the case,
compinitwouldn't fix my completions before I deleted~/.zcompdump, right? Am I missing something?
- What's
~/.zcompdump-$(hostname)-5.1.1and how is it related to.zcompdump? The only difference is one completion which is in~/.oh-my-zsh/completions(because$ZSHpoints to~/.oh-my-zsh). Is it an oh-my-zsh thing? - If I were to package these completions into a redistributable package or create an installer script, where should I place zsh completions and what else should I do during installation to make sure everything just works?
I'm targeting Ubuntu 16.04, 18.04 and 19.04, but non-distro-specific information is welcome. I'm testing this on Ubuntu 16.04 with zsh 5.1.1 and recent oh-my-zsh.
ubuntu zsh autocomplete oh-my-zsh
add a comment |
Please forgive me if I'm doing something stupid here, the documentation is huge and searching didn't turn up anything yet.
I'm trying to create shell completions for my custom script called fab. For bash it was easy, just drop them in /etc/bash_completion.d and they work. But oh boy, is zsh a PITA...
I have the completion function _fab and it works fine when enabled with compdef _fab fab. I put it in /usr/share/zsh/vendor-completions/_fab which already was in my $fpath. The file starts with #compdef fab and ends with compdef _fab fab. Looks good:
$ type _fab
_fab is an autoload shell function
But whenever I started a new shell, fab completions didn't work (other functions from vendor-completions, like _docker, were fine). compinit fixed this for that specific shell. I figured out that rm ~/.zcompdump ~/.zcompdump-$(hostname)-5.1.1; compinit make it work permanently (5.1.1 = my zsh version).
Questions:
- What and when reads
~/.zcompdumpto set up initial completions?
man zshallsays:
The next invocation of compinit will read the dumped file instead of performing a full initialization.
If that was the case,
compinitwouldn't fix my completions before I deleted~/.zcompdump, right? Am I missing something?
- What's
~/.zcompdump-$(hostname)-5.1.1and how is it related to.zcompdump? The only difference is one completion which is in~/.oh-my-zsh/completions(because$ZSHpoints to~/.oh-my-zsh). Is it an oh-my-zsh thing? - If I were to package these completions into a redistributable package or create an installer script, where should I place zsh completions and what else should I do during installation to make sure everything just works?
I'm targeting Ubuntu 16.04, 18.04 and 19.04, but non-distro-specific information is welcome. I'm testing this on Ubuntu 16.04 with zsh 5.1.1 and recent oh-my-zsh.
ubuntu zsh autocomplete oh-my-zsh
add a comment |
Please forgive me if I'm doing something stupid here, the documentation is huge and searching didn't turn up anything yet.
I'm trying to create shell completions for my custom script called fab. For bash it was easy, just drop them in /etc/bash_completion.d and they work. But oh boy, is zsh a PITA...
I have the completion function _fab and it works fine when enabled with compdef _fab fab. I put it in /usr/share/zsh/vendor-completions/_fab which already was in my $fpath. The file starts with #compdef fab and ends with compdef _fab fab. Looks good:
$ type _fab
_fab is an autoload shell function
But whenever I started a new shell, fab completions didn't work (other functions from vendor-completions, like _docker, were fine). compinit fixed this for that specific shell. I figured out that rm ~/.zcompdump ~/.zcompdump-$(hostname)-5.1.1; compinit make it work permanently (5.1.1 = my zsh version).
Questions:
- What and when reads
~/.zcompdumpto set up initial completions?
man zshallsays:
The next invocation of compinit will read the dumped file instead of performing a full initialization.
If that was the case,
compinitwouldn't fix my completions before I deleted~/.zcompdump, right? Am I missing something?
- What's
~/.zcompdump-$(hostname)-5.1.1and how is it related to.zcompdump? The only difference is one completion which is in~/.oh-my-zsh/completions(because$ZSHpoints to~/.oh-my-zsh). Is it an oh-my-zsh thing? - If I were to package these completions into a redistributable package or create an installer script, where should I place zsh completions and what else should I do during installation to make sure everything just works?
I'm targeting Ubuntu 16.04, 18.04 and 19.04, but non-distro-specific information is welcome. I'm testing this on Ubuntu 16.04 with zsh 5.1.1 and recent oh-my-zsh.
ubuntu zsh autocomplete oh-my-zsh
Please forgive me if I'm doing something stupid here, the documentation is huge and searching didn't turn up anything yet.
I'm trying to create shell completions for my custom script called fab. For bash it was easy, just drop them in /etc/bash_completion.d and they work. But oh boy, is zsh a PITA...
I have the completion function _fab and it works fine when enabled with compdef _fab fab. I put it in /usr/share/zsh/vendor-completions/_fab which already was in my $fpath. The file starts with #compdef fab and ends with compdef _fab fab. Looks good:
$ type _fab
_fab is an autoload shell function
But whenever I started a new shell, fab completions didn't work (other functions from vendor-completions, like _docker, were fine). compinit fixed this for that specific shell. I figured out that rm ~/.zcompdump ~/.zcompdump-$(hostname)-5.1.1; compinit make it work permanently (5.1.1 = my zsh version).
Questions:
- What and when reads
~/.zcompdumpto set up initial completions?
man zshallsays:
The next invocation of compinit will read the dumped file instead of performing a full initialization.
If that was the case,
compinitwouldn't fix my completions before I deleted~/.zcompdump, right? Am I missing something?
- What's
~/.zcompdump-$(hostname)-5.1.1and how is it related to.zcompdump? The only difference is one completion which is in~/.oh-my-zsh/completions(because$ZSHpoints to~/.oh-my-zsh). Is it an oh-my-zsh thing? - If I were to package these completions into a redistributable package or create an installer script, where should I place zsh completions and what else should I do during installation to make sure everything just works?
I'm targeting Ubuntu 16.04, 18.04 and 19.04, but non-distro-specific information is welcome. I'm testing this on Ubuntu 16.04 with zsh 5.1.1 and recent oh-my-zsh.
ubuntu zsh autocomplete oh-my-zsh
ubuntu zsh autocomplete oh-my-zsh
asked yesterday
gronostajgronostaj
2693 silver badges13 bronze badges
2693 silver badges13 bronze badges
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
TL,DR: In normal operations, just drop the file into the appropriate directory. While testing, you need to remove the cache file (.zcompdump by default, but users can put it in a different location, and oh-my-zsh does put it in a different location).
The simple answer is to write the completion function in a file where the first line is #compdef fab. The file must be in a directory on $fpath.
The file can either contain the function body, or a definition of the function followed by a call to the function. That is, either the file contains something like
#compdef fab
_arguments …
or
#compdef fab
function _fab {
_arguments …
}
_fab "$@"
The file must be present on $fpath before compinit runs. That means you need to pay attention to the order of things in .zshrc: first add any custom directories to $fpath, then call compinit. If you use a framework such as oh-my-zsh, make sure to add any custom directories to $fpath before the oh-my-zsh code.
compinit is the function that initializes the completion system. It reads all the files in $fpath and checks their first line for magic directives #autoload and #compdef.
.zcompdump is a cache file used by compinit. ~/.zcompdump is the default location; you can choose a different location when running compinit. Oh-my-zsh calls compinit with the -d option to use a different cache file name given by the variable ZSH_COMPDUMP, which defaults to
ZSH_COMPDUMP="${ZDOTDIR:-${HOME}}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
The host name is included for the sake of people whose home directory is shared between machines and who may have different software installed on different machines. The zsh version is included because the cache file is incompatible between versions (it includes code that changes from version to version).
I think all of your problems are due to a stale cache file (and that's made you overcomplicate the situation). Unfortunately, zsh's algorithm to determine whether the cache file is stale is not perfect, presumably in the interest of speed. It doesn't check the content or the timestamps of the files on $fpath, it just counts them. A .zcompdump file starts with a line like
#files: 858 version: 5.1.1
If the zsh version and the number of files are correct, zsh loads the cache file.
The cache file only contains associations between command names, not the code of completion functions. Here's are some common scenarios where the cache works transparently:
- If you add a new file to
$fpath, this invalidates the cache. - More generally, if you add and remove files on
$fpath, and the total number of removed files is not the same as the total number of removed files, this invalidates the cache. - If you move a file to a different directory in
$fpathwithout changing its name, this does not affect anything that's in the cache, so the cache remains correct. - If you modify a file in
$fpathwithout changing its first line, this does not affect anything that's in the cache, so the cache remains correct.
Here are some common scenarios where the cache becomes invalid, but zsh doesn't realize it.
- You add some files to
$fpathand remove exactly the same number of files. - You rename a file in
$fpath. - You add or modify the
#compdef(or#autoload) line at the top of the file.
That last point is what tends to bite during testing. If you change the #compdef line, you need to remove the .zcompdump file and restart zsh (or rerun compinit).
If you put completions in a redistributable package, just drop the completion file into a directory that's in the system-wide $fpath. For an Ubuntu package, the appropriate place is /usr/share/zsh/vendor-completions. For something installed under /usr/local, that's /usr/local/share/zsh/site-functions. That's all you need to do.
The one thing that isn't transparent is if you need to change the #compdef line in an upgrade, or if you remove or rename some files. In such cases, users will need to remove their cache file, and that's not something you can do from a package that gets installed on a multiuser machine.
Thanks for an answer. Maybe oh-my-zsh was loading outdated completions from itszcompdumpand then I was runningcompinitmanually with the default zcompdump to fix it... Is there a standardized path where I should put completions so that they work both with and without oh-my-zsh? Can I rely on$ZSH?
– gronostaj
10 hours ago
@gronostaj Oh-my-zsh doesn't affect what system directories are included in$fpath. On the other hand, distributions might change the default fpath, so you may need to tune your packaging scripts for each distribution (like any other system path). Zsh doesn't use the variableZSHfor anything.
– Gilles
10 hours ago
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f535509%2fhow-to-properly-make-custom-zsh-completions-just-work%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
TL,DR: In normal operations, just drop the file into the appropriate directory. While testing, you need to remove the cache file (.zcompdump by default, but users can put it in a different location, and oh-my-zsh does put it in a different location).
The simple answer is to write the completion function in a file where the first line is #compdef fab. The file must be in a directory on $fpath.
The file can either contain the function body, or a definition of the function followed by a call to the function. That is, either the file contains something like
#compdef fab
_arguments …
or
#compdef fab
function _fab {
_arguments …
}
_fab "$@"
The file must be present on $fpath before compinit runs. That means you need to pay attention to the order of things in .zshrc: first add any custom directories to $fpath, then call compinit. If you use a framework such as oh-my-zsh, make sure to add any custom directories to $fpath before the oh-my-zsh code.
compinit is the function that initializes the completion system. It reads all the files in $fpath and checks their first line for magic directives #autoload and #compdef.
.zcompdump is a cache file used by compinit. ~/.zcompdump is the default location; you can choose a different location when running compinit. Oh-my-zsh calls compinit with the -d option to use a different cache file name given by the variable ZSH_COMPDUMP, which defaults to
ZSH_COMPDUMP="${ZDOTDIR:-${HOME}}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
The host name is included for the sake of people whose home directory is shared between machines and who may have different software installed on different machines. The zsh version is included because the cache file is incompatible between versions (it includes code that changes from version to version).
I think all of your problems are due to a stale cache file (and that's made you overcomplicate the situation). Unfortunately, zsh's algorithm to determine whether the cache file is stale is not perfect, presumably in the interest of speed. It doesn't check the content or the timestamps of the files on $fpath, it just counts them. A .zcompdump file starts with a line like
#files: 858 version: 5.1.1
If the zsh version and the number of files are correct, zsh loads the cache file.
The cache file only contains associations between command names, not the code of completion functions. Here's are some common scenarios where the cache works transparently:
- If you add a new file to
$fpath, this invalidates the cache. - More generally, if you add and remove files on
$fpath, and the total number of removed files is not the same as the total number of removed files, this invalidates the cache. - If you move a file to a different directory in
$fpathwithout changing its name, this does not affect anything that's in the cache, so the cache remains correct. - If you modify a file in
$fpathwithout changing its first line, this does not affect anything that's in the cache, so the cache remains correct.
Here are some common scenarios where the cache becomes invalid, but zsh doesn't realize it.
- You add some files to
$fpathand remove exactly the same number of files. - You rename a file in
$fpath. - You add or modify the
#compdef(or#autoload) line at the top of the file.
That last point is what tends to bite during testing. If you change the #compdef line, you need to remove the .zcompdump file and restart zsh (or rerun compinit).
If you put completions in a redistributable package, just drop the completion file into a directory that's in the system-wide $fpath. For an Ubuntu package, the appropriate place is /usr/share/zsh/vendor-completions. For something installed under /usr/local, that's /usr/local/share/zsh/site-functions. That's all you need to do.
The one thing that isn't transparent is if you need to change the #compdef line in an upgrade, or if you remove or rename some files. In such cases, users will need to remove their cache file, and that's not something you can do from a package that gets installed on a multiuser machine.
Thanks for an answer. Maybe oh-my-zsh was loading outdated completions from itszcompdumpand then I was runningcompinitmanually with the default zcompdump to fix it... Is there a standardized path where I should put completions so that they work both with and without oh-my-zsh? Can I rely on$ZSH?
– gronostaj
10 hours ago
@gronostaj Oh-my-zsh doesn't affect what system directories are included in$fpath. On the other hand, distributions might change the default fpath, so you may need to tune your packaging scripts for each distribution (like any other system path). Zsh doesn't use the variableZSHfor anything.
– Gilles
10 hours ago
add a comment |
TL,DR: In normal operations, just drop the file into the appropriate directory. While testing, you need to remove the cache file (.zcompdump by default, but users can put it in a different location, and oh-my-zsh does put it in a different location).
The simple answer is to write the completion function in a file where the first line is #compdef fab. The file must be in a directory on $fpath.
The file can either contain the function body, or a definition of the function followed by a call to the function. That is, either the file contains something like
#compdef fab
_arguments …
or
#compdef fab
function _fab {
_arguments …
}
_fab "$@"
The file must be present on $fpath before compinit runs. That means you need to pay attention to the order of things in .zshrc: first add any custom directories to $fpath, then call compinit. If you use a framework such as oh-my-zsh, make sure to add any custom directories to $fpath before the oh-my-zsh code.
compinit is the function that initializes the completion system. It reads all the files in $fpath and checks their first line for magic directives #autoload and #compdef.
.zcompdump is a cache file used by compinit. ~/.zcompdump is the default location; you can choose a different location when running compinit. Oh-my-zsh calls compinit with the -d option to use a different cache file name given by the variable ZSH_COMPDUMP, which defaults to
ZSH_COMPDUMP="${ZDOTDIR:-${HOME}}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
The host name is included for the sake of people whose home directory is shared between machines and who may have different software installed on different machines. The zsh version is included because the cache file is incompatible between versions (it includes code that changes from version to version).
I think all of your problems are due to a stale cache file (and that's made you overcomplicate the situation). Unfortunately, zsh's algorithm to determine whether the cache file is stale is not perfect, presumably in the interest of speed. It doesn't check the content or the timestamps of the files on $fpath, it just counts them. A .zcompdump file starts with a line like
#files: 858 version: 5.1.1
If the zsh version and the number of files are correct, zsh loads the cache file.
The cache file only contains associations between command names, not the code of completion functions. Here's are some common scenarios where the cache works transparently:
- If you add a new file to
$fpath, this invalidates the cache. - More generally, if you add and remove files on
$fpath, and the total number of removed files is not the same as the total number of removed files, this invalidates the cache. - If you move a file to a different directory in
$fpathwithout changing its name, this does not affect anything that's in the cache, so the cache remains correct. - If you modify a file in
$fpathwithout changing its first line, this does not affect anything that's in the cache, so the cache remains correct.
Here are some common scenarios where the cache becomes invalid, but zsh doesn't realize it.
- You add some files to
$fpathand remove exactly the same number of files. - You rename a file in
$fpath. - You add or modify the
#compdef(or#autoload) line at the top of the file.
That last point is what tends to bite during testing. If you change the #compdef line, you need to remove the .zcompdump file and restart zsh (or rerun compinit).
If you put completions in a redistributable package, just drop the completion file into a directory that's in the system-wide $fpath. For an Ubuntu package, the appropriate place is /usr/share/zsh/vendor-completions. For something installed under /usr/local, that's /usr/local/share/zsh/site-functions. That's all you need to do.
The one thing that isn't transparent is if you need to change the #compdef line in an upgrade, or if you remove or rename some files. In such cases, users will need to remove their cache file, and that's not something you can do from a package that gets installed on a multiuser machine.
Thanks for an answer. Maybe oh-my-zsh was loading outdated completions from itszcompdumpand then I was runningcompinitmanually with the default zcompdump to fix it... Is there a standardized path where I should put completions so that they work both with and without oh-my-zsh? Can I rely on$ZSH?
– gronostaj
10 hours ago
@gronostaj Oh-my-zsh doesn't affect what system directories are included in$fpath. On the other hand, distributions might change the default fpath, so you may need to tune your packaging scripts for each distribution (like any other system path). Zsh doesn't use the variableZSHfor anything.
– Gilles
10 hours ago
add a comment |
TL,DR: In normal operations, just drop the file into the appropriate directory. While testing, you need to remove the cache file (.zcompdump by default, but users can put it in a different location, and oh-my-zsh does put it in a different location).
The simple answer is to write the completion function in a file where the first line is #compdef fab. The file must be in a directory on $fpath.
The file can either contain the function body, or a definition of the function followed by a call to the function. That is, either the file contains something like
#compdef fab
_arguments …
or
#compdef fab
function _fab {
_arguments …
}
_fab "$@"
The file must be present on $fpath before compinit runs. That means you need to pay attention to the order of things in .zshrc: first add any custom directories to $fpath, then call compinit. If you use a framework such as oh-my-zsh, make sure to add any custom directories to $fpath before the oh-my-zsh code.
compinit is the function that initializes the completion system. It reads all the files in $fpath and checks their first line for magic directives #autoload and #compdef.
.zcompdump is a cache file used by compinit. ~/.zcompdump is the default location; you can choose a different location when running compinit. Oh-my-zsh calls compinit with the -d option to use a different cache file name given by the variable ZSH_COMPDUMP, which defaults to
ZSH_COMPDUMP="${ZDOTDIR:-${HOME}}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
The host name is included for the sake of people whose home directory is shared between machines and who may have different software installed on different machines. The zsh version is included because the cache file is incompatible between versions (it includes code that changes from version to version).
I think all of your problems are due to a stale cache file (and that's made you overcomplicate the situation). Unfortunately, zsh's algorithm to determine whether the cache file is stale is not perfect, presumably in the interest of speed. It doesn't check the content or the timestamps of the files on $fpath, it just counts them. A .zcompdump file starts with a line like
#files: 858 version: 5.1.1
If the zsh version and the number of files are correct, zsh loads the cache file.
The cache file only contains associations between command names, not the code of completion functions. Here's are some common scenarios where the cache works transparently:
- If you add a new file to
$fpath, this invalidates the cache. - More generally, if you add and remove files on
$fpath, and the total number of removed files is not the same as the total number of removed files, this invalidates the cache. - If you move a file to a different directory in
$fpathwithout changing its name, this does not affect anything that's in the cache, so the cache remains correct. - If you modify a file in
$fpathwithout changing its first line, this does not affect anything that's in the cache, so the cache remains correct.
Here are some common scenarios where the cache becomes invalid, but zsh doesn't realize it.
- You add some files to
$fpathand remove exactly the same number of files. - You rename a file in
$fpath. - You add or modify the
#compdef(or#autoload) line at the top of the file.
That last point is what tends to bite during testing. If you change the #compdef line, you need to remove the .zcompdump file and restart zsh (or rerun compinit).
If you put completions in a redistributable package, just drop the completion file into a directory that's in the system-wide $fpath. For an Ubuntu package, the appropriate place is /usr/share/zsh/vendor-completions. For something installed under /usr/local, that's /usr/local/share/zsh/site-functions. That's all you need to do.
The one thing that isn't transparent is if you need to change the #compdef line in an upgrade, or if you remove or rename some files. In such cases, users will need to remove their cache file, and that's not something you can do from a package that gets installed on a multiuser machine.
TL,DR: In normal operations, just drop the file into the appropriate directory. While testing, you need to remove the cache file (.zcompdump by default, but users can put it in a different location, and oh-my-zsh does put it in a different location).
The simple answer is to write the completion function in a file where the first line is #compdef fab. The file must be in a directory on $fpath.
The file can either contain the function body, or a definition of the function followed by a call to the function. That is, either the file contains something like
#compdef fab
_arguments …
or
#compdef fab
function _fab {
_arguments …
}
_fab "$@"
The file must be present on $fpath before compinit runs. That means you need to pay attention to the order of things in .zshrc: first add any custom directories to $fpath, then call compinit. If you use a framework such as oh-my-zsh, make sure to add any custom directories to $fpath before the oh-my-zsh code.
compinit is the function that initializes the completion system. It reads all the files in $fpath and checks their first line for magic directives #autoload and #compdef.
.zcompdump is a cache file used by compinit. ~/.zcompdump is the default location; you can choose a different location when running compinit. Oh-my-zsh calls compinit with the -d option to use a different cache file name given by the variable ZSH_COMPDUMP, which defaults to
ZSH_COMPDUMP="${ZDOTDIR:-${HOME}}/.zcompdump-${SHORT_HOST}-${ZSH_VERSION}"
The host name is included for the sake of people whose home directory is shared between machines and who may have different software installed on different machines. The zsh version is included because the cache file is incompatible between versions (it includes code that changes from version to version).
I think all of your problems are due to a stale cache file (and that's made you overcomplicate the situation). Unfortunately, zsh's algorithm to determine whether the cache file is stale is not perfect, presumably in the interest of speed. It doesn't check the content or the timestamps of the files on $fpath, it just counts them. A .zcompdump file starts with a line like
#files: 858 version: 5.1.1
If the zsh version and the number of files are correct, zsh loads the cache file.
The cache file only contains associations between command names, not the code of completion functions. Here's are some common scenarios where the cache works transparently:
- If you add a new file to
$fpath, this invalidates the cache. - More generally, if you add and remove files on
$fpath, and the total number of removed files is not the same as the total number of removed files, this invalidates the cache. - If you move a file to a different directory in
$fpathwithout changing its name, this does not affect anything that's in the cache, so the cache remains correct. - If you modify a file in
$fpathwithout changing its first line, this does not affect anything that's in the cache, so the cache remains correct.
Here are some common scenarios where the cache becomes invalid, but zsh doesn't realize it.
- You add some files to
$fpathand remove exactly the same number of files. - You rename a file in
$fpath. - You add or modify the
#compdef(or#autoload) line at the top of the file.
That last point is what tends to bite during testing. If you change the #compdef line, you need to remove the .zcompdump file and restart zsh (or rerun compinit).
If you put completions in a redistributable package, just drop the completion file into a directory that's in the system-wide $fpath. For an Ubuntu package, the appropriate place is /usr/share/zsh/vendor-completions. For something installed under /usr/local, that's /usr/local/share/zsh/site-functions. That's all you need to do.
The one thing that isn't transparent is if you need to change the #compdef line in an upgrade, or if you remove or rename some files. In such cases, users will need to remove their cache file, and that's not something you can do from a package that gets installed on a multiuser machine.
answered 22 hours ago
GillesGilles
570k136 gold badges1174 silver badges1686 bronze badges
570k136 gold badges1174 silver badges1686 bronze badges
Thanks for an answer. Maybe oh-my-zsh was loading outdated completions from itszcompdumpand then I was runningcompinitmanually with the default zcompdump to fix it... Is there a standardized path where I should put completions so that they work both with and without oh-my-zsh? Can I rely on$ZSH?
– gronostaj
10 hours ago
@gronostaj Oh-my-zsh doesn't affect what system directories are included in$fpath. On the other hand, distributions might change the default fpath, so you may need to tune your packaging scripts for each distribution (like any other system path). Zsh doesn't use the variableZSHfor anything.
– Gilles
10 hours ago
add a comment |
Thanks for an answer. Maybe oh-my-zsh was loading outdated completions from itszcompdumpand then I was runningcompinitmanually with the default zcompdump to fix it... Is there a standardized path where I should put completions so that they work both with and without oh-my-zsh? Can I rely on$ZSH?
– gronostaj
10 hours ago
@gronostaj Oh-my-zsh doesn't affect what system directories are included in$fpath. On the other hand, distributions might change the default fpath, so you may need to tune your packaging scripts for each distribution (like any other system path). Zsh doesn't use the variableZSHfor anything.
– Gilles
10 hours ago
Thanks for an answer. Maybe oh-my-zsh was loading outdated completions from its
zcompdump and then I was running compinit manually with the default zcompdump to fix it... Is there a standardized path where I should put completions so that they work both with and without oh-my-zsh? Can I rely on $ZSH?– gronostaj
10 hours ago
Thanks for an answer. Maybe oh-my-zsh was loading outdated completions from its
zcompdump and then I was running compinit manually with the default zcompdump to fix it... Is there a standardized path where I should put completions so that they work both with and without oh-my-zsh? Can I rely on $ZSH?– gronostaj
10 hours ago
@gronostaj Oh-my-zsh doesn't affect what system directories are included in
$fpath. On the other hand, distributions might change the default fpath, so you may need to tune your packaging scripts for each distribution (like any other system path). Zsh doesn't use the variable ZSH for anything.– Gilles
10 hours ago
@gronostaj Oh-my-zsh doesn't affect what system directories are included in
$fpath. On the other hand, distributions might change the default fpath, so you may need to tune your packaging scripts for each distribution (like any other system path). Zsh doesn't use the variable ZSH for anything.– Gilles
10 hours ago
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f535509%2fhow-to-properly-make-custom-zsh-completions-just-work%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown