zsh: Dynamically ignore files for autocomplete

2026-03-053 minWesley SchwenglezshCORRECT_IGNORE_FILEautoloadzstyle

In the zshell you can use CORRECT_IGNORE_FILE to ignore files for spelling corrections (or autocorrect for commands). While handy, it is somewhat limited as it is global. Now, I wanted to ignore it only for git and not other commands. But I haven’t found a way to only target git without having to make a wrapper around git (which I don’t want to do).

So I wrote an autoloaded function that does this for me. The idea is rather simple. In your .zshrc you set a zstyle that tells which file should be ignored based on files (or directories) that exist in the current directory. Based on this you build the CORRECT_IGNORE_FILE environment variable or you just unset it. This function is then hooked into the chpwd action. I went with three default options, check dir, file, or just exist: d, f, or e. File wins, then directory, then exists.

In addition, there is also support for whole-sale directories. If you have a directory where you know things are gonna be conflicting, for example in my git repo of git itself, my git poh conflicts with the po (i18n) directory and the ci directory with my co alias. The beauty is, nameddir support comes out of the box, so you don’t need to spell it out, you just jot down ~git for where-ever your git source directory is.

The API is a little inconsistent between the two. But one is more, if this combination exist, just ignore this path, eg, for .git and app just ignore app. I actually want to ignore things only for certain commands.
Whereas the directory option allows in this dir just ignore these two units, like ci and po.

zsh
# in your .zshrc
add-zsh-hook chpwd set-correct-ignore
# zstyle ':local:correct-ignore:d' $ignore $conditions
zstyle ':local:correct-ignore:d' app .git app
# zstyle ':local:correct-ignore:directory' $dir $ignore $ignore
zstyle ':local:correct-ignore:directory' ~git ci po

The actual autoloaded function can seen here:

zsh
# set-correct-ignore
local word dirs check_type all_exist
local ignore_words=()
for check_type in f d e; do
local -A rules
zstyle -g patterns ':local:correct-ignore:'$check_type
for word in $patterns
do
zstyle -a ':local:correct-ignore:'$check_type $word dirs
all_exist=1
for dir in ${=dirs}; do
case $check_type in
e) [[ -e $dir ]] || { all_exist=0; break };;
d) [[ -d $dir ]] || { all_exist=0; break };;
f) [[ -f $dir ]] || { all_exist=0; break };;
esac
done
(( all_exist )) && ignore_words+=($word)
done
done
zstyle -g patterns ':local:correct-ignore:directory'
for dirs in $patterns
do
zstyle -a ':local:correct-ignore:directory' $dirs words
[ $PWD != $dirs ] && continue
ignore_words+=($words)
done
if (( ${#ignore_words} )); then
export CORRECT_IGNORE_FILE="${(j:|:)ignore_words}"
else
unset CORRECT_IGNORE_FILE
fi

Now you can enter, in this case a Laravel project and git ap won’t trigger a correction from zsh: zsh: correct 'ap' to 'app' [nyae]?. Sweet! Totally :)