Skip to content

Vi (Vim) editing mode

Koichi Murase edited this page Mar 29, 2024 · 30 revisions

[ 日本語 | English ]

1. Enabling vi/vim editing mode

Vi/vim editing mode will be enabled by one of the following settings.

With set -o vi in ~/.bashrc

Another way is to use set -o vi in ~/.bashrc.

# bashrc

if [[ $- == *i* ]]; then # in interactive session
  set -o vi
fi

Or if you want to enable the vim mode only when ble.sh is loaded, you can put set -o vi in ~/.blerc (or in ~/.config/blesh/init.sh):

# blerc

set -o vi

With ble.sh setting in ~/.blerc

The following setting in ~/.blerc also enables the vi/vim mode. This setting overwrites all the other settings presented so far, i.e., settings like set -o emacs, etc. will be overwritten.

bleopt default_keymap=vi

With a inputrc setting

In ~/.inputrc

$if Bash
  set editing-mode vi
$endif

With bind in ~/.bashrc

Or, the following setting also enables the vi/vim mode.

if [[ $- == *i* ]]; then # in interactive session
  bind 'set editing-mode vi'
fi

2. Setting timeout for ESC

The total timeout for ESC is the sum of all the timeouts on the route from your terminal to Bash. Each timeout can be configured as shown here:

Timeout of stty

The timeout in pseudo-terminal handler can be configured by stty. Usually the default timeout is 0. The timeout can be changed by the following command. The unit is 1/10 second.

# in ~/.bashrc
stty time 0

Timeout of Bash 4.3

In Bash 4.3 or later, the timeout for Readline can be configured by readline variable keyseq-timeout. The readline variable can be specified in ~/.inputrc file. The unit is millisecond.

# in ~/.inputrc
$if Bash
  set keyseq-timeout 1
$endif

Instead of specifying in ~/.inputrc, the variable can also be changed in ~/.bashrc with the following command.

# in ~/.bashrc
bind 'set keyseq-timeout 1'

Timeout of screen

If you use terminal multiplexers, they also have timeouts. The timeout for GNU Screen can be configured in ~/.screenrc as follows. The unit is millisecond. Also any key bindings of bindkey -t starting with an escape character should not be defined since the option -t disables the timeout of the escape characater.

# in ~/.screenrc
maptimeout 1

Timeout of tmux

The timeout for tmux can be configured in ~/.tmux.conf. The unit is millisecond.

# in ~/.tmux.conf
set -sg escape-time 1

3. Possible preferences

Settings for vi/vim mode can be registered to blehook keymap_vi_load. The settings can be registered to the hook by the following code:

# blerc

function blerc/vim-mode-hook {

  # Write your settings for vi/vim mode here

}
blehook/eval-after-load keymap_vi blerc/vim-mode-hook
# ble-0.3 and before
# ble/array#push _ble_keymap_vi_load_hook blerc/vim-load-hook

Mode lines

In vi/vim mode, the mode line is shown in the form -- INSERT -- (for insert mode) or ~ (for normal mode). The mode line can be disable by the following setting:

# ble-0.4
bleopt keymap_vi_mode_show=

The mode name for the normal mode can be change by keymap_vi_mode_string_nmap option:

# in blehook keymap_vi_load
bleopt keymap_vi_mode_string_nmap=$'\e[1m-- NORMAL --\e[m'

If you don't want to show a mode name in the normal mode, please add the following instead:

# in blehook keymap_vi_load
bleopt keymap_vi_mode_string_nmap=

Cursor shape for each mode

Using ble-bind -m KEYMAP --cursor NUM, control sequences to be sent on entering each mode can be specified. For example, if your terminal supports some of DECSCUSR, the following settings implement the cursor shape switching in each mode.

# ble-0.4+
ble-bind -m vi_nmap --cursor 2
ble-bind -m vi_imap --cursor 5
ble-bind -m vi_omap --cursor 4
ble-bind -m vi_xmap --cursor 2
ble-bind -m vi_cmap --cursor 0

# ble-0.2 and 0.3
bleopt keymap_vi_nmap_cursor:=2
bleopt keymap_vi_imap_cursor:=5
bleopt keymap_vi_omap_cursor:=4
bleopt keymap_vi_xmap_cursor:=2
bleopt keymap_vi_cmap_cursor:=0

If your terminal actually supports Ss entry although it's not shown in terminfo, you can directly override the terminal database of ble.sh as

_ble_term_Ss=$'\e[@1 q'

For the other details, pleaase reference ble-bind -m KEYMAP --cursor NUM.

(Insert mode) Enable Meta key modifiers

The following setting sets up the keymap settings with Meta modifiers. For example, with this setting, M-RET can be used to insert a newline in the commandline.

# hook:keymap_vi_load

ble-decode/keymap:vi_imap/define-meta-bindings

In this case, C-RET can be optionally configured so that it forcibly executes the command.

ble-bind -m vi_imap -f 'C-RET' 'accept-line'

The default mapping of M-backspace (whose actual key sequence depends on your terminal) copies the previous shell word in the kill ring. Instead, the following settings will kill the backward word as in GNU Readline.

ble-bind -m vi_imap -f 'M-C-?' kill-backward-cword
ble-bind -m vi_imap -f 'M-DEL' kill-backward-cword
ble-bind -m vi_imap -f 'M-C-h' kill-backward-cword
ble-bind -m vi_imap -f 'M-BS'  kill-backward-cword

(Insert mode) SP: magic-space / insert space

The default mapping of SP is magic-space which performs history and sabbrev expansion before inserting a space. If you want to have just a space without expansions, please add the following setting.

ble-bind -m vi_imap -f 'SP' 'self-insert'

(Insert mode) /: magic-slash / insert slash

The default mapping of SP is magic-slash which performs sabbrev expansion (starting with ~) before inserting a slash. If you want to have just a slash without expansions, please add the following setting.

ble-bind -m vi_imap -f '/' 'self-insert'

(Normal/insert mode) RET and C-m: magic newline / always run command

The default mapping of RET and C-m in the insert mode inserts newline with multiline commands or incomplete commands. They moves the cursor position to the next line in the normal mode. Instead, with the following setting, RET and C-m always causes the execution of the command as in GNU Readline, even in the multiline mode or when the command is not syntactically completed.

ble-bind -m vi_imap -f 'C-m' accept-line
ble-bind -m vi_imap -f 'RET' accept-line
ble-bind -m vi_nmap -f 'C-m' accept-line
ble-bind -m vi_nmap -f 'RET' accept-line

(Insert mode) C-k: kill-forward-line / digraphs

The default mapping of C-k is kill-forward-line. If you want to input digraphs with <C-k>{char1}{char2}, please add the following setting:

ble-bind -m vi_imap -f 'C-k' 'vi_imap/insert-digraph'

(Insert mode) C-o: single-command-mode / accept-and-next

The default mapping of C-o is vi_imap/single-command-mode. If you want to execute the current command line and load the next history entry with C-o, please add the following setting:

ble-bind -m vi_imap -f 'C-o' 'accept-and-next'

Or you may like C-@, instead of C-o, bound to accept-and-next:

ble-bind -m vi_imap -f 'C-@' 'accept-and-next'

(Normal/insert mode) C-c: cancel / discard-line

The default mapping of C-c is vi_imap/normal-mode-without-insert-leave (in vi_imap), vi-command/cancel (in vi_nmap). If you instead want to discard the current line and go to the next line, you can bind C-c to 'discard-line':

ble-bind -m vi_imap -f 'C-c' discard-line
ble-bind -m vi_nmap -f 'C-c' discard-line

g g and G: movements in command history / current command

The default mapping of g g and G moves the current position in the command history. You can use H and L for the movements in the current command entry. If you would like to move the position in the current command also with g g and G, you can overwrite the bindings as follows.

ble-bind -m vi_nmap -f 'g g' vi-command/first-nol
ble-bind -m vi_omap -f 'g g' vi-command/first-nol
ble-bind -m vi_xmap -f 'g g' vi-command/first-nol
ble-bind -m vi_nmap -f 'G' vi-command/last-line
ble-bind -m vi_omap -f 'G' vi-command/last-line
ble-bind -m vi_xmap -f 'G' vi-command/last-line

(Normal mode) C-r: redo / isearch

The default mapping of C-r in the normal mode is vi_nmap/redo. If you want to use the incremental search mode as in GNU Readline, you can use the following keybinding:

ble-bind -m vi_nmap -f 'C-r' history-isearch-backward

Note that the incremental searches are not implemented as a motion, so it might not work with operators, registers, etc. as expected.

surround.vim

Some of the functionalities are imported from github.com:tpope/vim-surround. To use them add the following setting in keymap_vi_load hook:

# in blehook keymap_vi_load
source "$_ble_base/lib/vim-surround.sh"

Currently only ys, yss, yS, ySS, cs, ds, vS, vgS are supported.

The implementation vim-surround.sh supports configurable replacements used by ys and cs with bleopt variables. The following codes show example configuration.

# in blehook keymap_vi_load
bleopt vim_surround_45:=$'$( \r )' # for ysiw-
bleopt vim_surround_61:=$'$(( \r ))' # for ysiw=
bleopt vim_surround_q:=\' # for ysiwq
bleopt vim_surround_Q:=\" # for ysiwQ

The variables of the form vim_surround_{number} is the setting for the Unicode character {number} specified in decimal. The variables of the form vim_surround_{alpha} is the setting for the character {alpha}. The form vim_surround_{alpha} is selected if both forms are defined for a character. If the value contains CR ($'\r' in bash scripts), the value is split into two parts with the first CR; the first and second part is used for the left and right enclosing delimiters, respectively. If the value does not contain CR, the value is directly used for both of the left and right delimiters.


[ 日本語 | English ]

Clone this wiki locally