I use vi editing mode in bash. I have "show-mode-in-prompt" set to "on" in ~/.inputrc.
show-mode-in-prompt (Off)
If set to On, add a string to the beginning of the prompt indicating the editing mode: emacs, vi command, or vi insertion. The mode strings are user-settable (e.g., emacs-mode-string).
So now I can see the editing mode at the beginning of my prompt.
i:$ # This is ins mode
c?$ # This is cmd mode
i:$ cat ~/.inputrc
set editing-mode vi
set show-mode-in-prompt on
set vi-ins-mode-string "\1\e[1;32m\2i:\1\e[0m\2"
set vi-cmd-mode-string "\1\e[1;31m\2c?\1\e[0m\2"
set colored-stats on
i:$ echo $PS1
$
I'd really like this at the end of my prompt though, and prepend the current directory, i.e.
/current/dir/here $ i:
But I"m not sure if this is achievable. My first thought was to use a carriage return in PS1, but unfortunately this overwrites the mode string.
i:$ PS1='\r\w $ '
~/projects $
My second thought was to somehow get the mode string and just insert it into $PROMPT_COMMAND, instead of letting readline write it to the prompt. I can get the current mode with:
i:$ bind -v | grep keymap | awk '{print $3}'
vi-insert
But the PROMPT_COMMAND value is only executed before the prompt is issued, so I wouldn't see the mode change.
Attempt number 3 included padding my mode strings so there's room for the directory. This could work, but I don't know how I'd make the amount of space variable. Also the prompt is going to start before the mode string, the mode string will get overwritten by my command, and if I switch modes the text I've typed gets replaced by the whole mode string, effectively clearing it out due to the spaces.
i: cat ~/.inputrc
set editing-mode vi
set show-mode-in-prompt on
set vi-ins-mode-string " \1\e[1;32m\2i:\1\e[0m\2"
set vi-cmd-mode-string " \1\e[1;31m\2c?\1\e[0m\2"
set colored-stats on
i: PS1="\r\w $ "
~/projects $ i:
~/projects $ # typing stuff i:
~/projects $ # typing more stuff overwrites the mode line
~/projects $ c?verwrites the mode line
Is there some other clever way to do this? Maybe a control character like carriage return that jumps to the beginning of the line but does not overwrite the existing characters?
i:$ echo $BASH_VERSION
5.0.7(1)-release
Best Answer
You can achieve that by setting a very long mode string for cmd and insert modes, that include the other items you want in your prompt. Note that this means you won't be able to use special shortcuts available in PS1, such as
\w
for a "pretty" printing of your current directory. But you can probably achieve the same in shell code that does the same.You can set the readline variables using the
bind "set vi-ins-mode-string \"...\""
andbind "set vi-cmd-mode-string \"...\""
commands. (seehelp bind
for more details.) And you can set that from yourPROMPT_COMMAND
, so that it will get reset before each prompt (so it will reflect change of directory, date and time if you include them, etc.)Quoting can get tricky :-)
For the example you used yourself:
You could use this:
Like mentioned, the expansion of
$PWD
will include the full path and won't use relative paths from~
, etc.You can get the same expansion used in prompts by using bash's
${variable@P}
operator expansion:Please note that you need
PS1
to be set to something non-empty, otherwise no prompt is printed at all. You can use a single space in this case. You might want to consider settingPS2
appropriately, for line continuations.BTW, my recommendation for symbols and colors for the
ins
andcmd
mode strings are:cmd
should use:
(same as you can type:
commands from normal mode in Vim) and should use a green color (since that's the default color set by lightline in the status line for "Normal" mode.)ins
should use+
(which is the symbol used by Vim to show a buffer is modified, when you insert, you modify it) and should use a blue color (default color used by lightline in the status line for "Insert" mode.)Personally, I think these below are pretty cool: