Note: I no longer use the configuration below, and I no longer maintain it, so I provide the information as is.
I decided to switch to using something called “vi-mode” when using Zsh. If you’re into using the command line a lot, and you’re using Zsh, then you might find this interesting.
If you’re using “vi-mode” — and this entry isn’t really about using “vi-mode”, so I suggest you look elsewhere on what that is and how to use it — then you might desire to know offhand what mode you’re in when you look at your shell prompt. This is probably a natural desire, and it’s what occurred to me when I made the switch. I took a look at the vi-mode
plugin that comes with oh-my-zsh
. It has some nifty thing that can be inserted into the prompt.
I wanted something subtle, so I made it change the color of my lightning bolt. I wasn’t satisfied, though, because I remembered a Vim tip that let me change the cursor shape on the fly in exactly the same circumstances when using Vim proper. It uses a trick that works in iTerm2 (and evidently Konsole over on Linux), using a proprietary escape sequence.
I searched a little bit more, but I only ever saw information about this escape sequence in the context of Vim, so I’m evidently the first ever to want to use this escape sequence outside of Vim. I think it’s actually pretty useful, so I thought I’d jot down how I did it.
First, here’s what it looks like…
Now, as for how I did it. This is the relevant excerpt from my ~/.zshrc
, omitting all the other things I have in there that accomplish the color change and other features I like.
function zle-keymap-select zle-line-init zle-line-finish { case $KEYMAP in vicmd) print -n -- "\E]50;CursorShape=0\C-G";; # block cursor viins|main) print -n -- "\E]50;CursorShape=1\C-G";; # line cursor esac zle reset-prompt zle -R } zle -N zle-line-init zle -N zle-line-finish zle -N zle-keymap-select
That’s about it. Again, this only really works if you’re using iTerm 2 on a Mac.
Update:
I noticed one pernicious drawback of the methodology I outlined above. Whenever executing a command, it would use the line-style cursor just as a matter of course, since that’s what the shell had set earlier, and there was nothing to reset it when a command were issued.
For this reason, I split out the above Zsh widget functions so that the block cursor is always restored when the shell finishes reading a line of input. That is to say, I choose the line-style cursor when initializing a prompt to accept a new line of input (or when $KEYMAP
changes), but as soon as I finish reading in input and move on to execute a command, I restore the block-style cursor. Here’s what that looks like:
function zle-keymap-select zle-line-init { # change cursor shape in iTerm2 case $KEYMAP in vicmd) print -n -- "\E]50;CursorShape=0\C-G";; # block cursor viins|main) print -n -- "\E]50;CursorShape=1\C-G";; # line cursor esac zle reset-prompt zle -R } function zle-line-finish { print -n -- "\E]50;CursorShape=0\C-G" # block cursor } zle -N zle-line-init zle -N zle-line-finish zle -N zle-keymap-select
You can always find the most recent version of my settings in my .zshrc configuration script.