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.;)
source to share
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.
source to share
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.
source to share