Jérôme Belleman
Home  •  Tools  •  Posts  •  Talks  •  Travels  •  Graphics  •  About Me

Word Completion with Zsh

23 Jan 2018

Like many other modern shells, Zsh offers completions of all kinds and flavours. One particularly handy one is word completion, explained in this post.

1 Word Completion

If you're a Vim user and enjoy the completion offered by Ctrl p and Ctrl n to respectively find the previous or next match in the document for a word starting like the one you're typing, you may be interested in that Zsh feature which can complete words from your history file. Calling compinit will give you access to the _history-complete-older and _history-complete-newer widgets. I've bound the Ctrl p and Ctrl n key combinations to mimic Vim:

autoload -Uz compinit
compinit

bindkey "^p" _history-complete-older
bindkey "^n" _history-complete-newer

2 Word Completion Bug

This word completion is so convenient that the bug that plagues it has to be as infuriatingly painful as a stray Lego brick on the floor in the middle of the night.

The symptom is that hitting on your completion key binding will display a message along the lines of failed to find end of command substitution instead of effectively completing your word. And sometimes it'll be a bad pattern message. And sometimes it'll be something else yet. And in some rare cases it'll mysteriously work after all. All the signs of some random memory corruption somewhere. It turns out it's caused by very long lines in your ~/.histfile, so long that they presumably overflow an array, somewhere.

Annoying though this problem is, I've worked through several versions without seeing it fixed, so while the developers are at it, a simple workaround such as cutting lines which are too long in your ~/.histfile will do the business. What's too long, though? I was under the impression that the critical length might have been around 65535, but while cutting at that length in a short .histfile seemed to solve the problem, doing so in a much larger one didn't. Better give it some margin:

cut -c -32767 ~/.histfile | sponge  ~/.histfile

3 References