zshzsh-completion

ZSH completion matching control : fuzzy match on one part of input


I'm writing a zsh completion for some program, and parts of it involves completing resource routes (/they/look/like/this).
I have a command mycmd that I can use to generate some completion candidates of resource routes, and provide completions for my program, using:

_multi_parts '/' "($(mycmd /some/resource/id))"

Now, I would like to implement a specific behavior to match resources that contain the last identifier in my query, not only those that start with it.

For example, $(mycmd "/resource/identifier/bc") gives completions like :

/resource/identifier/abc456/
/resource/identifier/123abcXYZ/

We get resource names whose identifier contains bc, which is the intended behavior.

Now here is the problem: zsh completion prevents these completions from showing up, because none of them matches "/resource/identifier/bc*", the default pattern for zsh.

I read the documentation for ZSH _multi_parts , compadd. It appears that using -M <pattern> described in compadd doc and available for _multi_parts could do the trick, by specifying a custom pattern for completion as described in ZSH Matching Control documentation. However this doc is lacking useful examples and is overall very obscure to me.

I spent hours of trials and errors to find the right pattern argument for _multi_parts -M <pattern> to achieve what I want with no success. Any hint on this would be much appreciated.

EDIT: actually, simply ignoring the last resource identifier bc would also work. I did not manage to do this either using -M.


Solution

  • Finally found out how to do this. The correct specification is:

    _multi_parts -M 'l:|=*' '/' $completions
    

    The pattern l:|=* allows to recognize matches which contain extra character after the string on the command line. Looking at zsh completion log below (C-x ?), we find that it also uses patterns r:|/=* r:|=*. In my understanding, using both r:|=* and l:|=* allows recognizing any completion candidate -- which is fine in my case, since filtering relevant suggestions is done with $mycmd.

    Extract from ZSH completion log:

    +_multi_parts:94> compadd -O tmp1 -M 'r:|/=* r:|=* l:|=*' - ENSG00000170615_SLC26A5_NT
    +_multi_parts:96> [[ 1 -eq 0 ]]
    +_multi_parts:99> [[ 1 -eq 1 ]]
    +_multi_parts:106> [[ SLC = */* ]]
    +_multi_parts:109> matches=( ENSG00000170615_SLC26A5_NT/ ) 
    +_multi_parts:111> PREFIX=/run/echolocation_example/SLC 
    +_multi_parts:112> SUFFIX='' 
    +_multi_parts:114> [[ 0 -ne 0 ]]
    +_multi_parts:115> zstyle -t :completion::complete:pelican:argument-2: expand suffix
    +_multi_parts:119> ((  1  ))
    +_multi_parts:120> compadd -p /run/echolocation_example/ -r / -S / -M 'r:|/=* r:|=* l:|=*' - ENSG00000170615_SLC26A5_NT