Why does a value '-' (hyphen) in "tag-order" style prevent matching of the "executables" tag even if that tag is explicitly specified?

4

0

With the code below, everything works as expected:

  • When I write c and hit the TAB key, I get the appropriate completions in correct order.

    Image

  • When I write ./ and hit the TAB key, I get the completion for the executables tag.

    Image


# Always use menu selection when using unambiguous completions.
zstyle ':completion:*:*:*:*:*' menu 'select'

# Show only completions.
zstyle ':completion:*:*:*:*:*' completer _complete

# Group name becomes the name of the matching tag.
zstyle ':completion:*:*:*:*:*' group-name ''

# Configure the order of tag matching as well as their descriptions.
zstyle -e ':completion:*:*:-command-:*:*' tag-order '
    reply=(
           "executables:Executables:Executables
            builtins:Builtins:Builtins
            commands:Commands:Commands
            aliases:Aliases:Aliases
            functions:Functions:Functions
            parameters:Variables:Variables
            reserved-words:Keywords:Keywords"
          )
'

# Configure the order in which completion groups will be shown.
zstyle ':completion:*:*:-command-:*:*' group-order 'Executables' 'Builtins' 'Commands' 'Aliases' 'Functions' 'Variables' 'Keywords'

# Configure the format for each group/tag description.
zstyle ':completion:*:*:*:*:descriptions' format $'%{\e[0;38;2;0;0;0;48;2;200;150;0m%} %d %{\e[0;38;2;200;150;0;48;2;0;0;0m%}%{\e[0m%}'

# Initialize completion system.
autoload -Uz compinit && compinit

However if the tags that I've specified do not produce any completion, other tags will be tried as well.

Easiest way to prove this is to exclude the functions tag from tag-order style:

zstyle -e ':completion:*:*:-command-:*:*' tag-order '
    reply=(
           "executables:Executables:Executables
            builtins:Builtins:Builtins
            commands:Commands:Commands
            aliases:Aliases:Aliases
            parameters:Variables:Variables
            reserved-words:Keywords:Keywords"
          )
'

and then create 2 functions with a unique prefix:

function unique_prefix_A() { }
function unique_prefix_B() { }

Now when I write unique_prefix_ and hit the TAB key, I don't expect to see anything since functions tag was removed from tag-order.
However, because Executables, Builtins, Commands, Aliases, Variables and Keywords didn't provide any completions, zsh will by default try to match other tags, namely the excluded functions tag, to try to give any completion.

Because of this, the functions unique_prefix_A and unique_prefix_B will be suggested:

Image

I don't like this behavior and want to limit the search only to tags that I have explicitly specified.

The manual for the tag-order style suggests a simple solution:

- If any value consists of only a hyphen, then only the tags specified in the other values are generated. Normally all tags not explicitly selected are tried last if the specified tags fail to generate any matches. This means that a single value consisting only of a single hyphen turns off completion.

Applying the solution:

# Configure the order of tag matching as well as their descriptions.
zstyle -e ':completion:*:*:-command-:*:*' tag-order '
    reply=(
           "executables:Executables:Executables
            builtins:Builtins:Builtins
            commands:Commands:Commands
            aliases:Aliases:Aliases
            functions:Functions:Functions
            parameters:Variables:Variables
            reserved-words:Keywords:Keywords"
           "-"
          )
'

Current behavior is:

  • When I write c and hit the TAB key, I get the appropriate completions in correct order.

    Image)

  • When I write ./ and hit the TAB key, I get nothing.

    Image


Why is now only executables tag not working?

How can I fix it and get the desired behavior?

Iskustvo

Posted 2018-05-05T15:33:09.477

Reputation: 122

I understand the text "If any value consists of only a hyphen, then only the tags specified in the other values are generated" to mean that the hyphen restricts you to the values in the list. As ./ is not in the list you get nothing. – harrymc – 2018-05-12T17:51:26.323

I tried using your code but couldn't seem to replicate your problem (with zsh 4.3.17). Any chance you are trying to complete ./ in a folder that doesn't contain any executables? Can you give an example of the undesired behaviour? – JRI – 2018-05-12T19:02:27.467

@harrymc Yeah, I understand it like that too. However I don't understand your point about ./, how should it be in the list? executables tag is responsible for the completions on ./ or am I wrong? – Iskustvo – 2018-05-12T23:55:59.047

@JRI That is strange. I am using zsh 5.5.1, do you think it might be a regression in zsh source code? Unfortunately, no, there are executables and directories. I have updated the question with images for each case. The last image obviously represents the undesired behavior :D – Iskustvo – 2018-05-13T00:00:56.570

@JRI and Iskustvo: Which Linux versions are you on? JRI: Have you tried the exact same commands as above without additions? – harrymc – 2018-05-13T06:39:46.997

@harrymc Linux Arch 4.16.4-1-ARCH #1 SMP PREEMPT Thu Apr 24 13:21:29 UTC 2018 x86_64 GNU/Linux. Does Linux version really play a roll with how zsh uses completions? – Iskustvo – 2018-05-13T10:56:43.923

There may be source differences between Linux distributions. – harrymc – 2018-05-13T12:42:25.850

You should have ask on unix & linux stackexchange there are some very good guy with zsh over there. – Kiwy – 2018-05-17T07:27:08.497

Thank you, first I gave it a shot on StackOverflow. Then I found out about this site and posted same question here and when there wasn't a single response on neither of these sites I posted the question on Unix&Linux as well. I gave bounty on all 3 sites and this is the only one where someone actually commented something relevant. Others are just ignored... – Iskustvo – 2018-05-17T20:09:54.453

Answers

2

The executable tag invokes _files -g '*(-*) in this case. Then _files calls more _tags, so it would be necessary to specify these implicitly specified tags in the completion functions, too.

zstyle -e ':completion:*:*:-command-:*:*' tag-order '
    reply=(
           "executables:Executables:Executables
            builtins:Builtins:Builtins
            commands:Commands:Commands
            aliases:Aliases:Aliases
            functions:Functions:Functions
            parameters:Variables:Variables
            reserved-words:Keywords:Keywords
            globbed-files directories"
           "-"
          )
'

It would be useful to add globbed-files and directories in this case:

% ls -al
total 80
drwxr-xr-x  3 t    t     4096 May 18 08:27 .
drwxrwxrwt 16 root root 69632 May 18 15:27 ..
drwxr-xr-x  2 t    t     4096 May 18 08:27 directory
-rwxr-xr-x  1 t    t        0 May 18 08:27 executable-file
-rw-r--r--  1 t    t        0 May 18 08:27 test
% ./<TAB>
Executables
directory/        executable-file*

But on the above setting, directories and local executable files will go into the same "Executable" group. If we would like to make "directories" go into other groups, we could specify the file-patterns directly and use it like this:

zstyle ':completion:*:*:-command-:*:*' file-patterns \
 '*(#q-*):executables:Executables *(-/):directories:Directories'

zstyle -e ':completion:*:*:-command-:*:*' tag-order '
    reply=(
           "executables:Executables:Executables
            builtins:Builtins:Builtins
            commands:Commands:Commands
            aliases:Aliases:Aliases
            functions:Functions:Functions
            parameters:Variables:Variables
            reserved-words:Keywords:Keywords
            directories:Directories"
            -
          )
'

In the below example, "directory" and "executable-file" are in the separated groups:

% ls -al
total 80
drwxr-xr-x  3 t    t     4096 May 18 08:27 .
drwxrwxrwt 15 root root 69632 May 18 15:24 ..
drwxr-xr-x  2 t    t     4096 May 18 08:27 directory
-rwxr-xr-x  1 t    t        0 May 18 08:27 executable-file
-rw-r--r--  1 t    t        0 May 18 08:27 test
% ./<TAB>
Executables
executable-file*
Directories
directory/

Below is the resulted smallest .zshrc example:

autoload -Uz compinit && compinit
zstyle ':completion:*:*:*:*:*' group-name ''
zstyle ':completion:*:descriptions' format '%B%F{black}%d%f%b'
zstyle ':completion:*:*:*:*:*' menu 'select'

# This comment out block is just for a reminder of my answer's first half.
# zstyle -e ':completion:*:*:-command-:*:*' tag-order '
#       reply=(
#                    "executables:Executables:Executables
#                       builtins:Builtins:Builtins
#                       commands:Commands:Commands
#                       aliases:Aliases:Aliases
#                       functions:Functions:Functions
#                       parameters:Variables:Variables
#                       reserved-words:Keywords:Keywords
#                       globbed-files directories"
#                    "-"
#                   )
# '

zstyle ':completion:*:*:-command-:*:*' file-patterns \
 '*(#q-*):executables:Executables *(-/):directories:Directories'

zstyle -e ':completion:*:*:-command-:*:*' tag-order '
    reply=(
           "executables:Executables:Executables
            builtins:Builtins:Builtins
            commands:Commands:Commands
            aliases:Aliases:Aliases
            functions:Functions:Functions
            parameters:Variables:Variables
            reserved-words:Keywords:Keywords
            directories:Directories"
            -
          )
'

Updated: comment out the unecessary block.

hchbaw

Posted 2018-05-05T15:33:09.477

Reputation: 516

I've copied from my original answer. https://stackoverflow.com/a/50403671/4387039

– hchbaw – 2018-05-18T23:11:18.990