How to change cursor shape depending on VI mode in Bash?

I have the following line in my .bashrc:

set -o vi

      

And I want my cursor to have a pipe shape when I am in insert mode and a block shape when I am in command mode, for example, what would I have in Vim if I placed the following in my .vimrc:

let &t_SI = "\e[6 q"
let &t_SR = "\e[4 q"
let &t_EI = "\e[2 q"

      

Except for this case, I want to have equivalent command line behavior.


I found a partial answer to my question here -   https://unix.stackexchange.com/questions/22527/change-cursor-shape-or-color-to-indicate-vi-mode-in-bash - written by @gogolb.

Here is the answer, copied:

#!/bin/bash
# Script "kmtest.sh"

TEST=`bind -v | awk '/keymap/ {print $NF}'`
if [ "$TEST" = 'vi-insert' ]; then
    echo -ne "\033]12;Green\007"
else
    echo -ne "\033]12;Red\007"
fi

export PS1="\u@\h \$(kmtest.sh)> "

      

Unfortunately though, as explained in the answer, the example script only changes the shape of the cursor after a carriage return, whereas I want the shape of the cursor to change on hitting <Esc> (i.e. when I change the mode).


I am on Linux using a native terminal application with Bash 4.4.7 and the $ TERM variable set to xterm-256color. Also, I don't know if tmux affects what I'm asking, but I would ideally like the solution to work both inside and outside tmux sessions.


DECISION

I ended up discovering the answer to this question, which I describe here in another question that I posted:

How to properly link the patched GNU readline library with all existing programs?

Don't worry, the solution doesn't require any fixes.;)

+5


source to share


2 answers


DECISION:

I am posting my answer to my own question here as recommended.


This solution works for Bash 4.4+ since this version of Bash uses version 7.0 of the GNU readline library, which includes the necessary variable additions vi-cmd-mode-string

and vi-ins-mode-string

.

These variables can be set as follows in your .inputrc file to achieve the functionality described above:

set show-mode-in-prompt on
set vi-cmd-mode-string "\1\e[2 q\2"
set vi-ins-mode-string "\1\e[6 q\2"

      



Explaination:



For those who are really interested in how this solution works.


These two variables, vi-cmd-mode-string

and vi-ins-mode-string

, are printed to your terminal along with the command line to provide a visual indicator of which mode you are in (for example, command line mode or insert mode).

The default values ​​for these two variables are " (cmd) " and " (ins) " for command line and insert modes, respectively. So if you just leave them at the default and get the command line, say PS1='>>>'

, then your prompt looks like this:

  • Command Mode:

    (cmd) >>>
    
          

  • Insert mode:

    (ins) >>>
    
          


According to the man page for readline (see below), you can also specify non-printable characters, such as terminal control sequences, by embedding sequences between the escape characters \ 1 and \.

vi-cmd-mode-string ((cmd))
       This  string  is  displayed immediately before the last line of the primary prompt when vi editing mode is active and in command mode.  The value is expanded like a key binding, so the
       standard set of meta- and control prefixes and backslash escape sequences is available.  Use the \1 and \2 escapes to begin and end sequences of non-printing characters, which  can  be
       used to embed a terminal control sequence into the mode string.
vi-ins-mode-string ((ins))
       This  string is displayed immediately before the last line of the primary prompt when vi editing mode is active and in insertion mode.  The value is expanded like a key binding, so the
       standard set of meta- and control prefixes and backslash escape sequences is available.  Use the \1 and \2 escapes to begin and end sequences of non-printing characters, which  can  be
       used to embed a terminal control sequence into the mode string.

      


Therefore, in my solution above, I insert terminal escape sequences, \e[2 q

(make the cursor a vertical bar) and \e[6 q

(make the cursor on the pipe) between those escape characters \ 1 and \ 2, resulting in my cursor being a vertical bar in command mode and the shape of the pipe in insert mode.

+10


source


That's cool. I want to add that in addition to setting the cursor, it is still possible to have a text message about the state of the mode. This code works:

set show-mode-in-prompt on
set vi-cmd-mode-string "\1\e[2 q\2cmd"
set vi-ins-mode-string "\1\e[6 q\2ins"

      



cmd

and ins

will be displayed to the left of the prompt, depending on the mode.

0


source







All Articles