インサートモードから出ずにVimを使いこなす

このエントリーをはてなブックマークに追加

この記事はCamphor Advent Calendar 2019 9日目の記事です。投稿日が一致していませんが、この記事を書き始めてgit addした日付になるようになっているだけなので気にしないでください

皆さん、Vim使ってますか?
この記事はVimを使ってない人にはおそらく役に立たないと思いますので、お帰りいただいたほうがいいかもしれません。

Vimの最大の特徴にして魅力にして初心者殺しの一つは、モード切替でしょう。文字を入力するインサートモードだけでなく、主に移動・入力場所の指定を行うノーマルモードや、スクリプトコマンドを入力するExモードを切り替えながら入力します。
これにより、キーボードを押す回数を減らしながら、高い操作性を確保しているのは周知のとおりです。モナドアーツみたいでかっこいいですね。

しかし、悲しいかな、Vimのノーマルモードは日本語IMEと非常に相性が悪いです。ノーマルモードにEscキーで戻っても、IMEを英語に切り替えておかないと、IME変換窓が開いてしまってノーマルモードコマンドを入力することができません。これは面倒です。

これを理由に日本語の文章を書く際にはEmacsのほうが優れているとする意見も見られます。Emacsのコマンド入力の多くはCtrlキー+他のキーなので、日本語IMEで入力していても変換窓が開くことなく直接入力できるからです。

しかし、思いませんか?ならばノーマルモードに戻らなければいい。VimもCtrlキー+他のキーでコマンド入力ができるようになればいいじゃないか、と。

そう、Vimは高度にカスタマイズできるエディタ。Vimを愛するあなたが、たかが日本語が楽しく入力できないからって泣く泣く別のエディタに乗り換える必要なんてないのです!インサートモードで入力しやすいようにカスタマイズしてしまいましょう!

あ、日本語キーボードではCtrlがキーボードの左下にありますが、これだと小指が死ぬと思います。英字キーボードに合わせてAの左(日本語だとCapsLockがある場所)にリマップするなり、押しやすい位置に動かしましょう。

事前調査

(以下Ctrlを押しながらx<C-x>と表記します)

とりあえず、インサートモードにおける<C-x>は標準で何に対応しているか見ていきましょう1。すでに便利な機能にマッピングされているのに上書きしてしまうともったいないですからね。下の表で全部だと思います。

これ使う?のところには、そのキーバインドを(僕が)よく使うかどうかが書いています。これがいらないだったら、他のコマンドに「再利用」できそうということですね。

入力 効果 これ使う?
<C-a> 一つ前のインサートモードで入力したものを再度入力 いらない
<C-b> 割当なし いらない
<C-c> インサートモードをquit2 びみょう
<C-d> インデント削る
<C-e> 一行下の文字を入力 いらない
<C-f> この行をインデントし直す =使うし、いらない
<C-g> 組み合わせて使う
<C-h> <BS>(バックスペース)する 押しやすいので重宝
<C-i> Tabにおなじ いらないって人がもしいたら逆に教えてほしい
<C-j> 改行する 押しやすいので重宝
<C-k> マルチバイト文字を入力 スニペットの展開ですでに使っている
<C-l> 割当なし3 いらない
<C-m> 改行する <C-j>とどっちかでいい気はする
<C-n> 次の変換候補 補完窓が出ているときのみいる
<C-o> インサートモードから一旦抜ける
<C-p> 前の変換候補 補完窓が出ているときのみいる
<C-q> 「文字通り」入力(ターミナルでは働かないことあり) 動かないことがあるらしいので使わない
<C-r> レジスタから入力
<C-s> 割当なし。tmuxのプレフィックスをこれにしてる tmuxと被るので使わない
<C-t> インデント追加
<C-u> 行頭まで削除
<C-v> 「文字通り」入力 びみょう
<C-w> 単語を削除
<C-x> 主に補完ができるサブモードに移行 押しにくい
<C-y> 一行上の文字を入力 いらない
<C-z> Vimをサスペンド4
<C-[> Escに同じ いらないって人がもしいたら逆に教えてほしい
<C-]> その場でabbreviation5を発動
<C-_> ヘブライ語入力(右から入力)に切り替え6 英字キーボードでは押しにくい
<C-^> 言語設定の切り替え 押しにくい

こうしてみると、この中にも便利なものがたくさんありますね……これだけでも一つ記事がかけちゃいそうです。

さて、これをもとにいらないものにマッピングしていきます。

マッピング

運命的なことに、<C-a><C-e><C-f><C-b><C-n><C-p>などがマッピングできそうです。Emacsのマッピングと似た構成にできるので嬉しいですね!

行頭、行末への移動

Emacsと同じく、<C-a><C-e>で行頭・行末へ移動できるようにします。

" 行頭へ移動
cnoremap <C-a> <Home>
inoremap <C-a> <Home>
" 行末へ移動
cnoremap <C-e> <End>
inoremap <C-e> <End>

行移動

Emacsと同じく、<C-n><C-p>で一行先・一行前へ移動できるようにします。

" Exコマンドを実装する関数を定義
function! ExecExCommand(cmd)
  silent exec a:cmd
  return ''
endfunction
inoremap <silent> <expr> <C-p> "<C-r>=ExecExCommand('normal k')<CR>"
inoremap <silent> <expr> <C-n> "<C-r>=ExecExCommand('normal j')<CR>"

単語移動

Emacsライクな感じで、<C-f><C-b>で単語単位で前後に移動できるようにします。

" 補完せず補完ウィンドウを閉じてから移動
inoremap <silent> <expr> <C-b> pumvisible() ? "<C-e><C-r>=ExecExCommand('normal b')<CR>" : "<C-r>=ExecExCommand('normal b')<CR>"
inoremap <silent> <expr> <C-f> pumvisible() ? "<C-e><C-r>=ExecExCommand('normal w')<CR>" : "<C-r>=ExecExCommand('normal w')<CR>"

Emacsでは文字単位移動なので、自分も最初はそうしていたのですが、単語単位のほうがよく使うのでこちらにしました。

保存

空いているキーならどれでもいいのですが、ここでは<C-l>を採用します。

inoremap <silent> <expr> <C-l> "<C-r>=ExecExCommand('update')<CR>"
" プラグインによってはこちらのほうが相性がいいかも:
inoremap <C-l> <ESC>:update<CR>a

保存するたびに文書がコンパイルされるようなプラグインを使っているときは、保存を多用するので特に便利です。

マウス移動

カーソルを大きく動かしたい場合は、マウスを使ってしまいましょう。当然ですが、マウス/マウスホイールもIME/モードを切り替えることなく使用できます。

set mouse=a

まとめ

数は多くないので上の表が長かった割に一瞬でした。

繰り返しになりますが、これら<C-x>は、日本語IMEで入力している最中でも変換窓が起動することなく入力できるはずなので、これくらいやっておけば、日本語で文章を書いているときでも、ほとんどIME切り替えに煩わされることなく作業できるのではないでしょうか。
実際、この設定を導入してから、僕は学生実験のレポートからこの記事自体 に至るまで、全部Vimで書いています!

また、英語の文章を書いているときでも、「数単語だけ前の入力をいじりたいけど、ノーマルモードにいちいち戻るの面倒だなあ……」などなどのよくあるシチュエーションで役に立つとおもいます。

上の表に上げた中には<C-c><C-m><C-_>など、今回はまだ使っていないものがあります。今回挙げたこと以外にもインサートモードでやりたいことがある人は、再利用を考えてみてはいかがですか。


  1. Escキーによるノーマルモードへの移行との違いは、abbreviationをチェックしないことと、IAで複数行に渡って一括入力したときに残りの入力が行われないこと
  2. set insertmodeしている場合は、ノーマルモードに移行
  3. 試しに押してみたらターミナルに出てしまった?→fgで戻れます。これを使うと、一旦Vimを抜けて別の作業をすることができるので便利かもですね
  4. abbreviationについては以前書いた記事を参照
  5. set allowrevinsされているときのみ可能で、これは標準でオフ。この機能を知らない人が誤タイプして爆死するのを防ぐため
Share