I'm using the zsh shell and have the following code inside my .zshrc:
fpath=(~/.zsh/completion $fpath)
autoload -Uz _vc
autoload -Uz compinit
compinit
The first line add the path ~/.zsh/completion to the array stored inside the environment variable fpath.
The 2nd line loads a completion function, called _vc, for a custom shell function called vc. The purpose of vc is simply to edit a file inside a particular folder (~/.cheat). _vc is defined in the file ~/.zsh/completion/_vc.
The last 2 lines enable a completion system.
Here's the code for my completion function _vc:
#compdef vc
declare -a cheatsheets
cheatsheets="$(ls ~/.cheat)"
_arguments "1:cheatsheets:(${cheatsheets})" && return 0
I copied it from this address, and adapted it for my needs.
As long as the directory ~/.cheat doesn't have a file whose name contains a single quote, the completion works. But if there's one, such as foo'bar, the completion fails with this error message:
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
I found a solution, by replacing the double quotes in the line cheatsheets="$(ls ~/.cheat)", with single quotes cheatsheets='$(ls ~/.cheat)'.
Now, when I hit Tab after my vc command, zsh suggests files inside ~/.cheat, including foo\'bar (zsh seems to have escaped the single quote automatically).
However, I don't understand how or why it works. With single quotes, the variable cheatsheets sould contain a literal string. So the $(...) command substitution shouldn't be expanded. For example, if I execute the following commands:
myvar='$(ls)'
echo $myvar → outputs `$(ls)` literally
So why is '$(ls ~/.cheat)' expanded inside _arguments "1:cheatsheets:(${cheatsheets})" && return 0? And why does it automatically escape the single quote inside foo'bar?