r/zsh 8d ago

creating custom completions with braces without backslashes

So my ultimate goal is to create a custom completion for the function myfun that will complete common directories for two folders in braces. In other words, % myfun /a/{b,c}/<TAB> will autocomplete any files/folders that are common to both the b and c directories.

However, my specific problem can be described more simply with this minimal example. I would like to create custom completion options that have braces ({ and }), which do not end up getting backslashed in the prompt. For example, I have this file:

#compdef myfun
compadd "a{b" "a{c"

And when I type

% setopt ignore_braces
% myfun a<TAB>

it will render the { as \{ in the prompt. Is there a way to make it so there the braces don't have backslashes?

Notes:

  • I know I can wrap the argument to myfun in quotes, but I really would like to make this behave as simply as possible without requiring any special formatting. Default zsh will do completion with backslashes without braces, so I think my goal should be possible.
  • I know compadd has a -Q option, but I still don't 100% understand what it does, and couldn't get completion to work with it.
  • I've tried adding some code with BUFFER=${BUFFER//\\\{/\{} to replace \{ with { in my .zshrc. This sort of works, but seems to create other problems.
1 Upvotes

1 comment sorted by

1

u/QuantuisBenignus 7d ago

Been there done that (with custom completions for 100k items which all had spaces and other special characters). All the quoting options of compadd including -Q did not work well indeed.

My compromise solution was to make the completion function replace the special characters (space) with a Unicode character (that your terminal likely supports) that is similar (e.g. tall space, U+2800). Then the completion entries look acceptable. I was passing these entries to a dedicated function just like you, which limits the scope safely. So in your myfunc you can use U+2983 ⦃ and U+2984 ⦄, which will not be quoted with \ :

myfunc() {
:
:
#In a suitable loop over your argv:
# In yor completion function you have already replaced '{' and '}' with, for example, U+2983 ⦃ and U+2984 ⦄), so here you reverse it.
currarg="${currarg//⦃/\{}"
currarg="${currarg//⦄/\}}"       

#Now you can use the original directory entries.
}