ble.sh icon indicating copy to clipboard operation
ble.sh copied to clipboard

Vi mode prompt feature requests

Open excited-bore opened this issue 5 months ago • 13 comments

  1. Is there a way to show the current mode before the prompt?

In regular bash, there's a way to show both vi-insert/vi-command modes in the prompt before PS1

bind 'set show-mode-in-prompt on'
bind 'set vi-ins-mode-string  (ins)\1\e[5 q\2\1\e[3m\2'
bind 'set vi-cmd-mode-string (cmd)\1\e[2 q\2\1\e[3m\2'

this essentially makes the default prompt (when starting in bash's vi-insert) from:

[user@user-machine /home/user]$

to

(ins)[user@user-machine /home/user]$

which i prefer over the way ble.sh seems to do it, which is show the state of the line editor after prompt and the current line. It comes over as a bit chaotic, and i'd love to have an option that updates bind 'set vi-cmd-mode-string` every time the mode for ble changes (since it seems to register all modes except insert mode as command), so something like

(visual)[user@user-machine /home/user]$

would be possible.

  1. Also regarding vi mode prompts; there doesn't seem to be complete control over the customizaibility of the modeprompts. Right now you can fully change -- NORMAL -- to (cmd) or something else using bleopt keymap_vi_mode_string_nmap, but you can't do the same for bleopt keymap_vi_mode_string_imap or other modes (because these options don't exist, only for nmap). You can set bleopt keymap_vi_mode_name_insert='(ins)', but if done the prompt goes from
[user@user-machine /home/user]$
*-- INSERT --*

to

[user@user-machine /home/user]$
*-- (ins) --*

while I don't really like the --'s and I might not want it to be printed out in bold.

So I see out of 2 approaches to this:

  • Either add bleopt keymap_vi_mode_string_imap, bleopt keymap_vi_mode_string_xmap, bleopt keymap_vi_mode_string_omap, etc.. because right now only bleopt keymap_vi_mode_string_nmap is an option
  • Or, another way would be to add the option bleopt keymap_vi_mode_name_normal (since right now this option doesn't exist) and make the text set by these options reflect more accurately by what is being shown when printed out.

Like if I were to set bleopt keymap_vi_mode_name_insert='(ins)' then it wouldn't print the added --'s. Then if the user wanted to change the style from bold to something different, it might be more appropriate to add something like keymap_vi_mode_name_*mode*_style as typeface options for each specific mode (which at default are set to bold) because typing the typeface is cleaner then using escape codes (and one for each specific mode to maximize customizability to the user). TL;DR I'd be really awesome if changing the keymap_vi_mode_name_*mode* removed the --'s that are printed out right now, as well as the ability to set styles using something like this:

bleopt keymap_vi_mode_name_ insert_style='bold'
bleopt keymap_vi_mode_name_replace_style='bold'
bleopt keymap_vi_mode_name_vreplace_style='italicbold'
bleopt keymap_vi_mode_name_visual_style='italic'
bleopt keymap_vi_mode_name_select_style=
bleopt keymap_vi_mode_name_linewise_style=
bleopt keymap_vi_mode_name_blockwise_style=

excited-bore avatar Aug 16 '25 04:08 excited-bore

  1. Is there a way to show the current mode before the prompt?

In regular bash, there's a way to show both vi-insert/vi-command modes in the prompt before PS1

bind 'set show-mode-in-prompt on'
bind 'set vi-ins-mode-string  (ins)\1\e[5 q\2\1\e[3m\2'
bind 'set vi-cmd-mode-string (cmd)\1\e[2 q\2\1\e[3m\2'

this essentially makes the default prompt (when starting in bash's vi-insert) from:

[user@user-machine /home/user]$

to

(ins)[user@user-machine /home/user]$

which i prefer over the way ble.sh seems to do it, which is show the state of the line editor after prompt and the current line. It comes over as a bit chaotic, and i'd love to have an option that updates bind 'set vi-cmd-mode-string` every time the mode for ble changes (since it seems to register all modes except insert mode as command), so something like

(visual)[user@user-machine /home/user]$

would be possible.

I wanted to add onto this that one way this could be possible if there was a vim-change-mode-hook, together with an environment variables like VIM_MODE to check the current mode and set a different prompt based on that, so something like

if [[ "$VI_MODE" == 'normal' ]]; then
     bind "set vi-cmd-mode-string $VI_MODE\1\e[5 q\2\1\e[3m\2"
else
     bind "set vi-cmd-mode-string $VI_MODE\1\e[2 q\2\1\e[3m\2"
fi

inside said vim-change-mode-hook would set the user prompt accordingly.

I'm fairly confident that these requests are no small feat and will probably take some time if taken consideration to implement. In the meantime, i guess I'll stick to the vim-airline plugin as i've just come across it and it at least seems to be pretty good looking alternative for what i'm trying to accomplish with this request...

excited-bore avatar Aug 16 '25 07:08 excited-bore

This is a duplicate of #57, https://github.com/akinomyoga/ble.sh/issues/85#issuecomment-783131577, https://github.com/akinomyoga/ble.sh/issues/114#issuecomment-846518295, https://github.com/akinomyoga/ble.sh/issues/205#issuecomment-1179744670 and also linked from item 3 of the prompt section in Q&A. There is also a module ble-import prompt-vim-mode, which implements an example.

In regular bash, there's a way to show both vi-insert/vi-command modes in the prompt before PS1

bind 'set show-mode-in-prompt on'
bind 'set vi-ins-mode-string  (ins)\1\e[5 q\2\1\e[3m\2'
bind 'set vi-cmd-mode-string (cmd)\1\e[2 q\2\1\e[3m\2'

ble.sh also supports this. You can just put the same settings to achieve the same behavior in ble.sh.

It comes over as a bit chaotic, and i'd love to have an option that updates bind 'set vi-cmd-mode-string` every time the mode for ble changes (since it seems to register all modes except insert mode as command), so something like

(visual)[user@user-machine /home/user]$

If you want finer control, please define a custom prompt sequence as described in https://github.com/akinomyoga/ble.sh/issues/205#issuecomment-1179744670, https://github.com/akinomyoga/ble.sh/issues/114#issuecomment-846518295, https://github.com/akinomyoga/ble.sh/issues/85#issuecomment-783131577, https://github.com/akinomyoga/ble.sh/issues/57#issuecomment-631273762. To disable the original one, please use bleopt keymap_vi_mode_show=.

So I see out of 2 approaches to this:

  • Either add bleopt keymap_vi_mode_string_imap, bleopt keymap_vi_mode_string_xmap, bleopt keymap_vi_mode_string_omap, etc.. because right now only bleopt keymap_vi_mode_string_nmap is an option

I will not support this for the reason explained in https://github.com/akinomyoga/ble.sh/issues/57#issuecomment-631186355 and other places. There are about 30 different states due to combinatorics, and it is a bad idea to provide a configuration for each combination of states. For a more flexible configuration, you should implement a shell function that resolves the state (as explained below). This is consistent with the situation in Vim, where there is no way to configure the styles and details of the default mode indicator, and other Vim plugins implement an independent indicator (which is completely unrelated to the default mode indicator).

  • Or, another way would be to add the option bleopt keymap_vi_mode_name_normal (since right now this option doesn't exist) and make the text set by these options reflect more accurately by what is being shown when printed out.

Use keymap_vi_mode_string_nmap. The normal mode in the original Vim doesn't show a name, and the default configuration of ble.sh tries to be consistent with that. This means that the content of the mode string in Vim is special when it is in the normal mode; there is no place to show the "name" when it is in the normal mode. This is the reason that ble.sh provides the special configuration keymap_vi_mode_string_nmap specifically for the normal mode so that the contents of the entire mode string can be specified.

I wanted to add onto this that one way this could be possible if there was a vim-change-mode-hook, together with an environment variables like VIM_MODE to check the current mode and set a different prompt based on that, so something like

The function ble/keymap:vi/script/get-mode called in the above-mentioned examples automatically registers the dependencies to the vim mode change, so you don't need a special hook. As long as you use ble/keymap:vi/script/get-mode in the prompt sequence, the prompt will automatically be updated on the necessary timing.

akinomyoga avatar Aug 16 '25 08:08 akinomyoga

This is a duplicate of #57, #85 (comment), #114 (comment), #205 (comment) and also linked from item 3 of the prompt section in Q&A. There is also a module ble-import prompt-vim-mode, which implements an example.

My bad! Thank you for the quick response and all those sources, the prompt-vim-mode plugin was exactly what I was looking for.

I will not support this for the reason explained in #57 (comment) and other places. There are about 30 different states due to combinatorics, and it is a bad idea to provide a configuration for each combination of states. For a more flexible configuration, you should implement a shell function that resolves the state (as explained below). This is consistent with the situation in Vim, where there is no way to configure the styles and details of the default mode indicator, and other Vim plugins implement an independent indicator (which is completely unrelated to the default mode indicator).

That's completely understandable. I wasn't really trying to suggest that you should add features in spite of the all ways those adding those could break the editor out of random. I was mostly coming from an angle where it seemed plausible enough to set the mode-indicator strings for all the modes like is possible with normal mode without it being too outlandish of a change.

The function ble/keymap:vi/script/get-mode called in the above-mentioned examples automatically registers the dependencies to the vim mode change, so you don't need a special hook. As long as you use ble/keymap:vi/script/get-mode in the prompt sequence, the prompt will automatically be updated on the necessary timing.

Didn't mean to incentivize the addition of a completely unnecesary rework there - should have searched more through the closed issues/Q&A - my bad!

Either way - thank you! I refined the example from #57 to be a little more verbose like the plugin in #85 (comment) (and fixed the visual prompt because it looked for *x which should have been *v )

prompt-vim-mode.bash

function ble/prompt/backslash:contrib/vim-mode {
  local mode; ble/keymap:vi/script/get-mode
    case $mode in
      (*n)  ble/prompt/print '(cmd)' ;;
      (*v)  ble/prompt/print '(vis)' ;;
      (*V)  ble/prompt/print '(v-line)' ;;
      (*^V) ble/prompt/print '(v-block)' ;;
      (*s)  ble/prompt/print '(sel)' ;;
      (*S)  ble/prompt/print '(s-line)' ;;
      (*^S) ble/prompt/print '(s-block)' ;;
      (i)   ble/prompt/print '(ins)' ;;
      (R)   ble/prompt/print '(replace)' ;;
      (^R)  ble/prompt/print '(v-place)' ;;
      (*)   ble/prompt/print '(???)' ;; 
  esac
}

.blerc

function blerc/vim-load-hook {
  ((_ble_bash>=40300)) && builtin bind 'set keyseq-timeout 1'

   bleopt keymap_vi_mode_show:=

  ... 
  
  #----------------------------------------------------------------------------
  # plugins

  ble-import prompt-vim-mode
  
  ...

}
blehook/eval-after-load keymap_vi blerc/vim-load-hook
PS1_MODE='\q{contrib/vim-mode}'

Would be great if these a reference to prompt-vim-mode added to ble.sh.example since i was just jumping back and forth between it and the How to set up vim mode wiki page

Idk if this is relevant but it did take me a while to figure out that this approach wasn't going to work with starship like with set vi-cmd/ins-mode-string where readline elevates the fact of setting PS1 manually for stuff like this, so instead of putting the line eval $(starship init bash) in ~/.bashrc - which prints out starship.bash - I did have to end up saving said printout to a file, link it to .bashrc and add a check for whether PS1_MODE is empty to potentially change the prompt. Knowing how manually setting PS1 just bodes well with fancy prompts like starship, this was expected in the end...

On a completely unrelated note, I noticed going into select mode using the shift+arrowkeys doesn't change the prompt to SELECT and have been trying to see what went wrong. I was able to find some workarounds for the PS1 prompt and vim-airline, but I haven't been able to come to grasp why the mode indicator -- INSERT -- prompt doesn't want to change.

I'm sorry if you had preferred me opening a new issue, but I'm going to just post the patches I made so far for you to do with them whatever you think is most appropriate:

vim-airline.sh

...
function ble/prompt/unit:_ble_lib_vim_airline_mode/update {
  ...
  ble/keymap:vi/script/get-mode
  case $mode in
  (*[vV^VsS^S]) m='visual' ;;
  ([R^R]*)      m='replace' ;;
  (i*)          m='insert' ;;
  (*c)          m='commandline' ;;
  (*n)          m='normal' ;;
  (*)
  esac
  ...
}

keymap.vi.sh

function ble/keymap:vi/script/get-mode {
case $keymap:${_ble_edit_mark_active%+} in
  ...  
  (vi_smap:*|vi_imap:S) mode=$mode's' ;;
  ...
  esac
...
}

I have the hunch that something in the function ble/prompt/backslash:keymap:vi/mode-indicator in keymap.vi.sh is the culprit for the mode-indicator not working, but from what I can tell ${_ble_edit_mark_active%+} in that function, even when declared at the top of the function doesn't become S like ${_ble_edit_mark_active%+} in get-mode, and since I have no idea what that var is even supposed to represent i'm just gonna leave at that and hope this is helpfull in some way or another.

excited-bore avatar Aug 16 '25 18:08 excited-bore

(and fixed the visual prompt because it looked for *x which should have been *v )

prompt-vim-mode.bash

Ah, thanks.

Would be great if these a reference to prompt-vim-mode added to ble.sh.example since i was just jumping back and forth between it and the How to set up vim mode wiki page

There's a corresponding section on the wiki page, so I believe descriptions should be added there.

Idk if this is relevant but it did take me a while to figure out that this approach wasn't going to work with starship like with set vi-cmd/ins-mode-string where readline elevates the fact of setting PS1 manually for stuff like this, so instead of putting the line eval $(starship init bash) in ~/.bashrc - which prints out starship.bash - I did have to end up saving said printout to a file, link it to .bashrc and add a check for whether PS1_MODE is empty to potentially change the prompt. Knowing how manually setting PS1 just bodes well with fancy prompts like starship, this was expected in the end...

I'm not exactly sure what you wanted to achieve and what you tried, and I'm also unfamiliar with Starship, but I guess format of the Starship configuration can be set to include the literal string \q{contrib/vim-mode} so that ble.sh can replace the string.

On a completely unrelated note, I noticed going into select mode using the shift+arrowkeys doesn't change the prompt to SELECT and have been trying to see what went wrong. I was able to find some workarounds for the PS1 prompt and vim-airline, but I haven't been able to come to grasp why the mode indicator -- INSERT -- prompt doesn't want to change.

The selection by shift+arrowkeys is unrelated to the select mode of Vim. The select mode is started by C-g in a visual mode and is something different from the selection by shift+arrowkeys.

akinomyoga avatar Aug 21 '25 01:08 akinomyoga

Hi, recently came across this amazing framework while I was trying to bring parity between my zsh and bash configs. I had some requests of my own too regarding the tool, and I apologize in advance if it has already been implemented.

I would like it if there was an environment variable that could be customised from the blerc to let me use it in my oh-my-posh config to let me update the vi-mode indicator on demand.

I am not sure if ble.sh already supports dynamic prompt reloads like this, but this would be awesome to have rather than having a separate line for the modes or having to use the ble.sh native prompt instead.

My oh-my-posh config :- https://github.com/sametaor/sametaor_CLIconfig/blob/master/misc/sametaor.omp.json My bashrc and bash + blerc configs :- bashrc bash + blerc

So far I've got this under my local .blerc, idk if it will work though:-

function ble_vi_mode_env {
  local mode="$_ble_decode_keymap"
  case "$mode" in
    (vi_nmap) export VI_MODE=" N" ;;    # Normal
    (vi_imap) export VI_MODE="󱩽 I" ;;    # Insert
    (vi_vmap) export VI_MODE=" V" ;;    # Visual
    (vi_Vmap) export VI_MODE="󰡮 VL" ;;   # Visual Line
    (vi_smap|vi_xmap) export VI_MODE="󱂔 VB" ;;   # Visual Block/Select
    (vi_Rmap) export VI_MODE=" R" ;;    # Replace
    (*) export VI_MODE="" ;;
  esac
}
PROMPT_COMMAND="ble_vi_mode_env${PROMPT_COMMAND:+; $PROMPT_COMMAND}"

sametaor avatar Aug 26 '25 16:08 sametaor

I would like it if there was an environment variable that could be customised from the blerc to let me use it in my oh-my-posh config to let me update the vi-mode indicator on demand.

Could you explain it in more detail? I'm not sure what you are trying to achieve. The above just seems like the one that can be achieved by the descriptions I mentioned in my first reply https://github.com/akinomyoga/ble.sh/issues/616#issuecomment-3193506192:

This is a duplicate of #57, #85 (comment), #114 (comment), #205 (comment) and also linked from item 3 of the prompt section in Q&A. There is also a module ble-import prompt-vim-mode, which implements an example.

You can just let Oh My Posh output the literal string \q{blerc/vim-mode} (or \q{contrib/my-vim-mode}, etc. depending on how you named the custom prompt sequence). Then ble.sh will replace that part with the string reflecting the current vim-mode.

So far I've got this under my local .blerc, idk if it will work though:-

function ble_vi_mode_env {
  local mode="$_ble_decode_keymap"
  case "$mode" in
    (vi_nmap) export VI_MODE=" N" ;;    # Normal
    (vi_imap) export VI_MODE="󱩽 I" ;;    # Insert
    (vi_vmap) export VI_MODE=" V" ;;    # Visual
    (vi_Vmap) export VI_MODE="󰡮 VL" ;;   # Visual Line
    (vi_smap|vi_xmap) export VI_MODE="󱂔 VB" ;;   # Visual Block/Select
    (vi_Rmap) export VI_MODE=" R" ;;    # Replace
    (*) export VI_MODE="" ;;
  esac
}
PROMPT_COMMAND="ble_vi_mode_env${PROMPT_COMMAND:+; $PROMPT_COMMAND}"

First of all, the evaluation of PROMPT_COMMAND is only performed once for each prompt, but the vim mode can change on every keystroke as a possibility. If you want to update the vim mode indicator as the vim mode changes, you cannot use PROMPT_COMMAND. Also, I'm wondering if Oh My Posh supports the environment variable VI_MODE, though I'm not an Oh-My-Posh user. If you need to generate the vim-mode indicator within Oh My Posh, shouldn't you ask Oh My Posh for it?

akinomyoga avatar Aug 27 '25 00:08 akinomyoga

@sametaor Have you solved your problem?

akinomyoga avatar Sep 10 '25 05:09 akinomyoga

@sametaor Have you solved your problem?

Really sorry for not seeing your comment earlier, I will get back to you after I implement your solutions and fixes as you had mentioned earlier.

sametaor avatar Sep 10 '25 05:09 sametaor

OK, thanks for letting me know the current situation.

akinomyoga avatar Sep 10 '25 05:09 akinomyoga

Could you explain it in more detail? I'm not sure what you are trying to achieve. The above just seems like the one that can be achieved by the descriptions I mentioned in my first reply https://github.com/akinomyoga/ble.sh/issues/616#issuecomment-3193506192:

I essentially want it to replicate the way I have setup my vi-mode indicator on zsh's zle to change right away based on what mode I change into. I have no issues with the modes themselves, but what I can't seem to be able to do is to change the prompt right away, it does work as the segment shows the correct mode for Insert mode, but no other modes' respective text appear. Perhaps I should've added this bit earlier so apologies for that.

You can just let Oh My Posh output the literal string \q{blerc/vim-mode} (or \q{contrib/my-vim-mode}, etc. depending on how you named the custom prompt sequence). Then ble.sh will replace that part with the string reflecting the current vim-mode.

So rather than a workaround via the .bashrc or .blerc, I just need to add this string in my oh my posh config, yes?

First of all, the evaluation of PROMPT_COMMAND is only performed once for each prompt, but the vim mode can change on every keystroke as a possibility. If you want to update the vim mode indicator as the vim mode changes, you cannot use PROMPT_COMMAND. Also, I'm wondering if Oh My Posh supports the environment variable VI_MODE, though I'm not an Oh-My-Posh user. If you need to generate the vim-mode indicator within Oh My Posh, shouldn't you ask Oh My Posh for it?

As mentioned earlier, yes, omp does support it, but I cannot seem to make it change, based on what mode I am in. It remains with the default insert mode text in the respective omp segment. Essentially omp respects any variable defined in any config, be VI_MODE or be it VI_MODE_TEXT or anything, as long as it is explicitly defined in the config. As for the PROMPT_COMMAND part, would your workaround as given work instead? I cannot seem to make the segment itself appear otherwise.

I have used zsh more than bash, so honestly I am a proper newbie at ble.sh 😅 Thanks for being patient nonetheless!

sametaor avatar Sep 10 '25 05:09 sametaor

You can just let Oh My Posh output the literal string \q{blerc/vim-mode} (or \q{contrib/my-vim-mode}, etc. depending on how you named the custom prompt sequence). Then ble.sh will replace that part with the string reflecting the current vim-mode.

So rather than a workaround via the .bashrc or .blerc, I just need to add this string in my oh my posh config, yes?

You need to define your function ble/prompt/backslash:blerc/vim-mode in your ~/.blerc (or ~/.config/blesh/init.sh), and then you can let Oh My Posh include \q{blec/vim-mode} at the desired place in PS1. prompt-vim-mode is illustrative.

akinomyoga avatar Sep 10 '25 05:09 akinomyoga

You need to define your function ble/prompt/backslash:blerc/vim-mode in your ~/.blerc (or ~/.config/blesh/init.sh), and then you can let Oh My Posh include \q{blec/vim-mode} at the desired place in PS1. prompt-vim-mode is illustrative.

Alright, thanks for letting me know!

sametaor avatar Sep 10 '25 10:09 sametaor

For what it's worth, I couldn't get ^ to match the Ctrl modifiers, but I am by no means a bash expert. This is what I ended up with for my prompt:

function ble/prompt/backslash:blerc/vim-mode {
  local mode
  ble/keymap:vi/script/get-mode
  case $mode in
  (*$'\x12') ble/prompt/print 'VR' ;;
  (*R)       ble/prompt/print 'R ' ;;
  (i*)       ble/prompt/print 'I ' ;;
  (*s)       ble/prompt/print 'S ' ;;
  (*$'\x13') ble/prompt/print 'SB' ;;
  (*S)       ble/prompt/print 'SL' ;;
  (*v)       ble/prompt/print 'V ' ;;
  (*$'\x16') ble/prompt/print 'VB' ;;
  (*V)       ble/prompt/print 'VL' ;;
  (n*)       ble/prompt/print 'N ' ;;
  (*)        ble/prompt/print '??' ;;
  esac
}
Image

gtbuchanan avatar Oct 30 '25 14:10 gtbuchanan