Bashをviモードで使う際のfzfキーバインド

Bash(readline)のviモード

自分はBashをviモードで使用しています。

set editing-mode vi
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"

$if mode=vi
    set keymap vi-insert
        Control-l: clear-screen
$endif

テキストオブジェクトなど使用できない機能はたくさんありますがccでの行削除やjkでの履歴移動はとても便利です。

カーソルの形状で自分がどのモードにいるかも判別できます。

demo_vi-mode.gif

fzf

jkでの履歴移動は便利ですが履歴を検索したいこともあります。

readlineのreverse-search-historyで履歴検索をすることも可能ですがリッチなUIがほしいのと、あいまい検索ができるためfzfを使用しています。

.bashrcの中でfzfのセットアップを行っています。

type fzf >/dev/null 2>&1 && eval "$(fzf --bash)"

意図しないタイミングで__fzf_cd__が起動してしまう現象が発生

echo Hello Worldと入力後にCtrl-[でノーマルモードへ移動、ccで行を削除を行うつもりが__fzf_cd__が起動してしまいます。

ccのcを入力した時点で__fzf_cd__が起動し検索欄にcが入力されます。

normal_fzf-cd.gif

上のgifを生成したvhs

Output demo.gif

Require echo
Require fzf

Set Shell "bash"
Set FontSize 32
Set Width 800
Set Height 600
Set TypingSpeed 50ms

Hide
Type `eval "$(fzf --bash)"`
Enter
Show

Type "echo Hello World"

Sleep 1s

Ctrl+[
Sleep 100ms
Type "cc"

Sleep 3s

Ctrl+[の直後にあるSleep 100msを500ms以上にすると想定した動作になります。

normal_cc.gif

原因

fzf --bashを読み込んで追加されるキーバインドの一つにAlt-cで__fzf_cd__を呼び出すものがあります。

bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'

bind -XSでbashにどのようなキーバインドが追加されているかを調べることができます。

Alt-cはESC-cと同じキーコードを送信するものであるため、それと同様のキーコードを送信するCtrl-[cに反応していたようです。

odで実際にAlt-cとCtrl-[cが同じであることが確かめることもできます。

od -Ax -tx1a
000000  1b  63  1b  63
       esc   c esc   c

解決方法

fzfのセットアップを行った後に\ecのキーバインドを削除しています。

そもそもfzfでディレクトリを移動したいことがないためあまり不便には感じていませんが今後別の方法を取ることもあり得ます。

type fzf >/dev/null 2>&1 && eval "$(fzf --bash)" && bind -r '\ec'

別の解決方法としてreadlineの設定でkeyseq-timeoutを小さな値にする方法があります。

デフォルトで500ms待つためもう少し短くしても良いかもしれません。

参考

端末アプリで Ctrl-[ が Esc になる理由

vi キーバインドで、なぜ J が下で K が上なのか?

No comments yet