Changing cursor style based on mode in both zsh and vim
Solution 1
I think it's better to use precmd()
instead of preexec()
:
# .zshrc
_fix_cursor() {
echo -ne '\e[5 q'
}
precmd_functions+=(_fix_cursor)
This way:
- you don't have to change
.vimrc
- cursor is fixed also when you create a new prompt without executing a command
- you don't have to write
echo -ne '\e[5 q'
twice in your.zshrc
.
Solution 2
This works perfectly for me, it's taken from here: https://gist.github.com/LukeSmithxyz/e62f26e55ea8b0ed41a65912fbebbe52
# vi mode
bindkey -v
export KEYTIMEOUT=1
# Change cursor shape for different vi modes.
function zle-keymap-select {
if [[ ${KEYMAP} == vicmd ]] ||
[[ $1 = 'block' ]]; then
echo -ne '\e[1 q'
elif [[ ${KEYMAP} == main ]] ||
[[ ${KEYMAP} == viins ]] ||
[[ ${KEYMAP} = '' ]] ||
[[ $1 = 'beam' ]]; then
echo -ne '\e[5 q'
fi
}
zle -N zle-keymap-select
zle-line-init() {
zle -K viins # initiate `vi insert` as keymap (can be removed if `bindkey -V` has been set elsewhere)
echo -ne "\e[5 q"
}
zle -N zle-line-init
echo -ne '\e[5 q' # Use beam shape cursor on startup.
preexec() { echo -ne '\e[5 q' ;} # Use beam shape cursor for each new prompt.
You can customise the type of cursor you want (blinking or not, |, rectangle or _) by changing the numbers in the following sequences \e[5 q
(5 is for beam, 1 is for block) as follows:
Set cursor style (DECSCUSR), VT520.
0 ⇒ blinking block.
1 ⇒ blinking block (default).
2 ⇒ steady block.
3 ⇒ blinking underline.
4 ⇒ steady underline.
5 ⇒ blinking bar, xterm.
6 ⇒ steady bar, xterm.
Solution 3
I have found a solution:
I put this in my ~/.vimrc
:
autocmd VimEnter * silent exec "! echo -ne '\e[1 q'"
autocmd VimLeave * silent exec "! echo -ne '\e[5 q'"
Solution 4
Simply add the line:
export VI_MODE_SET_CURSOR=true
to your ~/.zshrc
.
It is mentioned in the discussion of issue #9570.
Related videos on Youtube
maddingl
Updated on September 18, 2022Comments
-
maddingl over 1 year
I use vi-mode in oh-my-zsh with the af-magic theme.
I want the cursor style to indicate whether I am in normal mode (block) or insert mode (beam), both in
zsh
and invim
.This is what I have so far:
In my
~/.zshrc
:# vim mode config # --------------- # Activate vim mode. bindkey -v # Remove mode switching delay. KEYTIMEOUT=5 # Change cursor shape for different vi modes. function zle-keymap-select { if [[ ${KEYMAP} == vicmd ]] || [[ $1 = 'block' ]]; then echo -ne '\e[1 q' elif [[ ${KEYMAP} == main ]] || [[ ${KEYMAP} == viins ]] || [[ ${KEYMAP} = '' ]] || [[ $1 = 'beam' ]]; then echo -ne '\e[5 q' fi } zle -N zle-keymap-select # Use beam shape cursor on startup. echo -ne '\e[5 q' # Use beam shape cursor for each new prompt. preexec() { echo -ne '\e[5 q' }
As found here.
In
vim
, I use Vundle and terminus.With these configurations, both
zsh
andvim
work as they should when considered independently. However, when I entervim
fromzsh
in insert mode,vim
starts in normal mode (as it should) but still shows the beam shape cursor. Similarly, when I exitvim
, I get back tozsh
in insert mode, but the cursor is still in block shape (since the last mode invim
was normal).When after this, I switch modes for the first time (in both
zsh
andvim
), the cursor behaves the way it should again.How can I make them display the correct cursor after entering and exiting
vim
as well?I tried putting
autocmd VimEnter * stopinsert autocmd VimLeave * startinsert
in my
~.vimrc
, but this does not affect the cursor. -
maddingl over 5 yearsyes, this is nicer and works pretty well. Thanks! :)
-
statox about 5 years@maddingl Maybe you should consider changing the accepted answer to this one instead :)
-
Unix over 4 yearsI use
zle-line-finish() { echo -ne "\e[2 q" }
and it's working as well. -
Max Coplan over 4 yearsBut this doesn't change back to a block when going into normal mode
-
kctong529 about 3 yearsWorks like a charm. For those who want to extend this feature to interactive shell (e.g. python, scheme), you might find this helpful (unix.stackexchange.com/a/409587/459602)