How do I always ignore a pattern in ZSH completion?

Viewed 543

With the following in an empty directory:

$ zsh -d -f -i

% autoload -Uz compinit && compinit
% zstyle ':completion:*:*:cd:*:*' ignored-patterns foo
% mkdir foo
% mkdir bar
% mkdir zsh
  • When I type cd <TAB> I get a menu with only bar and zsh. This is great.
  • When I remove zsh and I do cd <TAB>, bar is completed without showing a menu. Also great.
  • But when I remove bar as well and I do cd <TAB>, foo is completed. I don't want that to happen.
  • Starting again, but from the parent directory and doing cd <TAB> to complete the parent directory and then cd <TAB> I see foo or get it completed for all three cases.

Is there a way to ignore foo completely so I never see it and never get it completed in the same directory and any other directory?

Edit:

I found that using zstyle ':completion:*:*:cd:*:*' ignored-patterns '**/foo' the problem of seeing the ignored pattern from a parent directory goes away, but ignored patterns are still completed when there is not other choice. So with this:

$ zsh -d -f -i

% autoload -Uz compinit && compinit
% zstyle ':completion:*:*:cd:*:*' ignored-patterns '**/foo'
% mkdir foo

and typing cd <Tab> still completes foo. Is there a way of just not completing in this case?

1 Answers

Reason for this behavior

The zsh completion system has multiple completer functions. These are enabled via:

zstyle ':completion:*' completer <list of completers>

The default value for this is _complete _ignored (see).

This means that first regular completion is tried, and if it did not produce a completion, the special _ignored completer is tried instead. The _ignored completer ignores the ignored-patterns style you defined and therefore finds the foo match.

From the zsh documentationon on _ignored:

The ignored-patterns style can be set to a list of patterns which are compared against possible completions; matching ones are removed. With this completer those matches can be reinstated, as if no ignored-patterns style were set. [...] The single-ignored style is also available as described above.

A solution

Remove _ignored from the list of completers.

You can display the current list via zstyle -L '*' completer. If this is empty, it still is at its default value and you can disable _ignored via:

zstyle ':completion:*' completer _complete

A sort-of solution

From the documentation entry on single-ignored (mentioned in the citation above):

This is used by the _ignored completer when there is only one match. If its value is ‘show’, the single match will be displayed but not inserted. If the value is ‘menu’, then the single match and the original string are both added as matches and menu completion is started, making it easy to select either of them.

So if you set it to show (or menu) (via zstyle ':completion:*' single-ignored show) then it won't immediately be completed and only show up in the tab completion menu. This means you could just ignore it and continue typing.

Appendix

It is (as far as I can tell) not possible to disable a completer only for cd (say with zstyle ':completion:*:*:cd:*:*' completer ...), as they are determined at the very beginning of the completion process.

There is also a way of ignoring certain file/directory patterns using the file-patterns style and the ^ glob pattern, but the style does not seem to be used with cd completion. But e.g. for ls this should do the trick:

zstyle ':completion:*:*:ls:*:*' file-patterns '^foo|^**/foo:directories'

The zsh guide on completion is also a good resource for all this: http://zsh.sourceforge.net/Guide/zshguide06.html

Related