How do I always ignore a pattern in ZSH completion? - zsh

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?

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

zsh issue : have the most recents files or directories near to the prompt and suggested most recent files or directories

On MacOS Big Sur 11.3, here is my .zshrc. I would like to get the newest files or directories near to the prompt (sorted from the most recent up to the oldest ones).
For the moment, I make test with the following command alias of ls :
The issue is that when I press TAB after a "l" which is actually the alias:
alias l='grc -es --colour=auto ls --color -Gh -C -lrt'
grc is a tool to colorify the files.
Here my current config in ~/.zshrc :
# ZSH completion
autoload -Uz compinit
compinit
# Colorize completions using default `ls` colors.
zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
# Zsh reverse auto-completion
zmodload zsh/complist
# To get new binaries into PATH
zstyle ':completion:*' rehash true
# Completion
zstyle ':completion:*:complete:(ls|cd|cp|mv|vim|cat|more|tail|head|open):*' file-sort date reverse
bindkey '^[[Z' menu-complete
If I do a FIRST l + space + TAB, I have the following suggestion :
If I type a SECOND pushing on TAB, I want a correct listing ordered from oldest to newest files automatically like this :
Finally, I want that a THIRD TAB pushing suggests the most recent file or directory (that I can browse with SHIFT + TAB)
in my case from figure above, the first suggestion that should appear is filenme_2.
But currently, the first suggestion with a THIRD TAB is the oldest one : this is not what I want.
Maybe there is something to do like adding :
bindkey '^\t' reverse-menu-complete or something slightly different but I can't succeed since with this bindkey, I have the suggestion as soon as I have pushed the FIRST TAB.
To list files sorted by creation/birth date/time, you can use:
ls -lt --time=birth
So all the suggestions should be ordered from the newest to the oldest
alias l='grc -es --colour=auto ls -lt --time=birth --color -Gh -C -lrt'
Also if you like colorful output in your console you can check colorls

Fix zsh _arguments options (--whatever) completion after non-options (noDashes) input

I would like to allow completion for --flags after other input in my gradle completion script, but _arguments seems to require that
specs that describe option flags must precede specs that describe non-option ("positional" or "normal") arguments of the analyzed line (from the zsh completion docs)
In other words: command foo --o[TAB] does nothing, but command --o[TAB] works fine. Is there any way to configure _arguments or do I need to use other control functions?
NOTE: Separate completion functions do not seem like an option in my case as the inputs are not in a fixed list (gradle tasks are arbitrary and multiple can be specified, gradle myfoo mybar --o[TAB] must work).
So you want to be able to type something like vim foo -[TAB] and have a list auto expand to show flags and switches, where currently you have to type vim -[TAB] to get your flags and switches and then type foo, yes?
Hopefully I am understanding your question correctly.
My current zsh completion options might be able to help with this, as I can do what I described, which seems to be what you are asking for? It has been quite a while sense I set these up so I don't remember precisely what each one does. What I belive you want though is the setopt COMPLETE_IN_WORD , unset LIST_AMBIGUOUS, as well as the zstyle ':completion::approximate*:*' prefix-needed false options. If I am wrong someone please correct me.
I have included what I use in my zsh as my completion section. I have tested this as standalone and it works on my zsh as is.
#{{{ Completion Stuff
zmodload -i zsh/complist
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
bindkey -M viins '\C-i' complete-word
# Faster! (?)
zstyle ':completion::complete:*' use-cache 1
# case insensitive completion
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' \
'r:|[._-]=* r:|=*' 'l:|=* r:|=*'
zstyle ':completion:*' verbose yes
zstyle ':completion:*:descriptions' format '%B%d%b'
zstyle ':completion:*:messages' format '%d'
zstyle ':completion:*:warnings' format 'No matches for: %d'
zstyle ':completion:*' group-name ''
# generate descriptions with magic.
zstyle ':completion:*' auto-description 'specify: %d'
# Don't prompt for a huge list, page it!
zstyle ':completion:*:default' list-prompt '%S%M matches%s'
# Don't prompt for a huge list, menu it!
zstyle ':completion:*:default' menu 'select=0'
# Have the newer files last so I see them first
zstyle ':completion:*' file-sort modification reverse
# color code completion
zstyle ':completion:*' list-colors "=(#b) #([0-9]#)*=36=31"
unsetopt LIST_AMBIGUOUS
setopt COMPLETE_IN_WORD
# Separate man page sections.
zstyle ':completion:*:manuals' separate-sections true
#
zstyle ':completion:*' list-separator 'fREW'
# complete with a menu for xwindow ids
zstyle ':completion:*:windows' menu on=0
zstyle ':completion:*:expand:*' tag-order all-expansions
# more errors allowed for large words and fewer for small words
zstyle ':completion:*:approximate:*' max-errors 'reply=( $(( ($#PREFIX+$#SUFFIX)/3 )) )'
# Errors format
zstyle ':completion:*:corrections' format '%B%d (errors %e)%b'
# Don't complete stuff already on the line
zstyle ':completion::*:(rm|vi):*' ignore-line true
# Don't complete directory we are already in (../here)
zstyle ':completion:*' ignore-parents parent pwd
zstyle ':completion::approximate*:*' prefix-needed false
I was able to solve this with this commit at least to allow options after 1 task is specified.
The trick is to set the state within _arguments with :->statename, reset the context to the next word, and provide a wildcard matcher that matches non-command words and use _arguments again.
There's almost certainly a way to allow options specified after an arbitrary number of words and avoid some duplication, but this is a workable start.

Have zsh return case-insensitive auto-complete matches, but prefer exact matches

I am using zsh with oh-my-zsh's rc file and there is some behavior I find particularly annoying. By default, oh-my-zsh is configured to return case-insensitive matches when auto-completing. This behavior is sometimes good, but other times it really sucks. Is there a way I can configure zsh to only use case-insenstive matching when there are no case-sensitive matches?
For instance, this case would use case-sensitive matching:
> ls
LICENSE.txt lib/
> emacs l <-- should autocomplete to lib/
In this case, case-insensitive auto-completion would happen:
> ls
README lib/
> emacs r <-- should autocomplete to README
Thanks!
Just uncomment the following line in ~/.zshrc:
# Uncomment the following line to use case-sensitive completion.
# CASE_SENSITIVE="true"
It worked for me
Create a file ~/.oh-my-zsh/custom/better-completion.zsh (assuming you are using default paths for oh-my-zsh) with the following lines
zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'
Explanation:
Rules for matches in zsh completion in general are defined in the matcher-list style. For oh-my-zsh this is defined in ~/.oh-my-zsh/lib/completion.zsh (once for case-sensitive and once for case-insensitive). You could change it there but it would probably be gone if you updated your oh-my-zsh. ~/.oh-my-zsh/custom is specifially intended for customization and files with extension .zsh are loaded from there by .oh-my-zsh/oh-my-zsh.sh at the end of the configuration.
The default (case-insensitive) settings for matcher-list in oh-my-zsh are:
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'
The first of which tells to handle upper and lower case interchangeable.
As it is the first rule, it will be invariably used for every match.
The only change needed is to prepend '' for simple completion (it is even the first example in zshcompsys(1) for matcher-list)
zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'
This tries first to complete the current word exactly as its written, before trying case-insensitive or other matches.
To be complete:
The second (original) rule allows for partial completion before ., _ or -, e.g. f.b -> foo.bar.
The third rule allows for completing on the left side of the written text, e.g. bar -> foobar)
For those not using oh-my-zsh, you can add the following two lines to ~/.zshrc
zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*'
autoload -Uz compinit && compinit

Zsh: Smart autocompletion feature?

I have the following alias in my ~/.zshrc:
~ which pulseaudio-restart
pulseaudio-restart: aliased to killall pulseaudio && pulseaudio --start
Is it possible to configure Zsh in a way that typing restart will output me pulseaudio-restart as a suggestion since it contains the string restart?
Currently, typing restart only brings up:
~ rest
restart restore-trash
Yes it is possible. For this you have to set/modify the matcher-list style for the completion module. This can be done with the following command:
zstyle ':completion:*' matcher-list 'l:|=* r:|=*'
This tells the completion to look for completion on the left as well as on the right side of the typed word (specifics can be found in zshcompwid(1)).
As the name matcher-list indicates, there may be more than one match specification, in which case it is important that 'l:|=* r:|=*' is the first one. The specifications are tried in the order they appear until something returns a match.
For oh-my-zsh the matcher-list is set in lib/completion.zsh and it already contains the required specification, but only as the last option. You can either change the order there or add your own settings in ~/.zshrc after oh-my-zsh is loaded.

Zsh autocomplete from the middle of filename

is it possible that zsh complete the whole file name from partial words of correct filename ? For example, there are (helloABC, helloabc, helloworld) under this folder, and I want to type only (oab + tab) to get (helloABC, helloabc.)
Yes this is possible. It can be enabled in the zsh completion system.
Adding these lines to your .zshrc will give you this feature:
zstyle ':completion:*' completer _complete
zstyle ':completion:*' matcher-list '' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' '+l:|=* r:|=*'
autoload -Uz compinit
compinit
_completer gives normal completion behaviour
'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' '+l:|=* r:|=*' takes care of case-insensive matching and that matching may occur on both sides of the current word (that is matching from the middle part of a filename).
Note: Some of these or similar lines may already be in your ~/.zshrc. In that case you may have to edit them:
if not already there _complete has to be added to the line starting with the definition for completer
If already present the rule for case-insensitivity might look different, for example m:{A-Za-z}={a-zA-Z}, which you can either be replaced or left as is.
+l:|=* r:|=* has to come immediatelly after the rule for case-insensitivity (it may also work if there are only rules starting with + between those two rules, but I did only check some basic combinations, which worked)

Resources