tmux in zsh with vi mode, toggle cursor shape between normal and insert mode

Solution 1:

After a few hours of diving into a wide variety of GitHub issues and man-pages I've found a setup that works for me, achieving what I believe you set out to achieve.

I am using rxvt-unicode v9.22, tmux 2.9a, neovim v0.4.2 and zsh 5.7.1 under Arch Linux. My setup is configured to use non-blinking beam cursor in insert mode, and non-blinking block cursor in normal mode.

For zsh, I use vi-mode with the following in my .zshrc:

bindkey -v
export KEYTIMEOUT=1

# Change cursor with support for inside/outside tmux
function _set_cursor() {
    if [[ $TMUX = '' ]]; then
      echo -ne $1
    else
      echo -ne "\ePtmux;\e\e$1\e\\"
    fi
}

function _set_block_cursor() { _set_cursor '\e[2 q' }
function _set_beam_cursor() { _set_cursor '\e[6 q' }

function zle-keymap-select {
  if [[ ${KEYMAP} == vicmd ]] || [[ $1 = 'block' ]]; then
      _set_block_cursor
  else
      _set_beam_cursor
  fi
}
zle -N zle-keymap-select
# ensure beam cursor when starting new terminal
precmd_functions+=(_set_beam_cursor) #
# ensure insert mode and beam cursor when exiting vim
zle-line-init() { zle -K viins; _set_beam_cursor }

For my tmux configuration, the only important lines are:

set -g default-terminal "tmux-256color"
set -ga terminal-overrides '*:Ss=\E[%p1%d q:Se=\E[ q'

To make sure that neovim behaves correctly for urxvt, $TERM needs to be correct. I do this with .Xresources with the following line (don't forget to merge afterwards with xrdb -merge ~/.Xresources):

URxvt*termName: rxvt-256color

Now for neovim, no configuration should be necessary, other than making sure not to tamper with guicursor. Some GitHub issues mention setting set guicursor= in your init.vim, however my setup does not work if I add that.

Hope this setup is reproducible given what I've provided, otherwise my dotfiles are available on GitHub.