make my zsh prompt show mode in vi mode

I found this via SU. Here's the basic example, though I'm still customizing it for myself:

function zle-line-init zle-keymap-select {
    RPS1="${${KEYMAP/vicmd/-- NORMAL --}/(main|viins)/-- INSERT --}"
    RPS2=$RPS1
    zle reset-prompt
}

zle -N zle-line-init
zle -N zle-keymap-select

I'd explain it except I don't really understand it yet


You've already found zle-keymap-select which is executed whenever the mode changes. You could use it to set some other visual indicator than the prompt, depending on what your terminal supports it (and your taste in mode indicator display, of course).

There is a standard terminfo capability to change the shape of the cursor. However some terminals display the same cursor in both modes. Xterm's notion of a less visible cursor is to make it blink (and this must be enabled with the -bc command line argument or cursorBlink resource).

zle-keymap-select () {
  case $KEYMAP in
    vicmd) print -rn -- $terminfo[cvvis];; # block cursor
    viins|main) print -rn -- $terminfo[cnorm];; # less visible cursor
  esac
}

With some terminals, you can also change the cursor color with print -n '\e]12;pink\a' (by color name) or print -n '\e]12;#abcdef\a' (by RGB specification). These sequences are described in the xterm documentation, in the ctlseqs file; modern terminal emulators typically emulate xterm, though they might not support all its features.


For the people having problems using reset-prompt with multiline prompts, this worked for me: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.html In combination with https://stackoverflow.com/questions/3622943/zsh-vi-mode-status-line I ended up doing:

terminfo_down_sc=$terminfo[cud1]$terminfo[cuu1]$terminfo[sc]$terminfo[cud1]

function insert-mode () { echo "-- INSERT --" }
function normal-mode () { echo "-- NORMAL --" }

precmd () {
    # yes, I actually like to have a new line, then some stuff and then 
    # the input line
    print -rP "
[%D{%a, %d %b %Y, %H:%M:%S}] %n %{$fg[blue]%}%m%{$reset_color%}"

    # this is required for initial prompt and a problem I had with Ctrl+C or
    # Enter when in normal mode (a new line would come up in insert mode,
    # but normal mode would be indicated)
    PS1="%{$terminfo_down_sc$(insert-mode)$terminfo[rc]%}%~ $ "
}
function set-prompt () {
    case ${KEYMAP} in
      (vicmd)      VI_MODE="$(normal-mode)" ;;
      (main|viins) VI_MODE="$(insert-mode)" ;;
      (*)          VI_MODE="$(insert-mode)" ;;
    esac
    PS1="%{$terminfo_down_sc$VI_MODE$terminfo[rc]%}%~ $ "
}

function zle-line-init zle-keymap-select {
    set-prompt
    zle reset-prompt
}
preexec () { print -rn -- $terminfo[el]; }

zle -N zle-line-init
zle -N zle-keymap-select

Tags:

Shell

Prompt

Zsh