Vimで複数のモードのマッピングを一括で設定する
Vimのキーマッピングは、対象のモードにより、nmap
やxmap
など複数のコマンドが存在します(:h map-commands
)。
しかし、「ノーマルモードでもビジュアルモードでも同じマッピングを設定したい」と思うことがあります。
通常は、このためにほぼ同じ(最初の1文字だけ違う)コマンドを何回も使用することになり、冗長な記述になってしまいます。
nnoremap s <Cmd>DoSomething<CR>
xnoremap s <Cmd>DoSomething<CR>
今回は、この複数モードでのマッピングを一括で指定するコマンドを作ったのでご紹介します。
導入
以下のコードを.vimrc
やinit.vim
などの設定ファイル内に記載してください。
つかいかた
:Keymap {modes} {arguments-of-map-commands}
で実行できます。
modes
は必須引数です。対象のモードを文字列で渡します。ノーマルモードだけのマッピングならn
、ノーマルモードとビジュアルモードならnx
とします。
arguments-of-map-commands
は通常のマッピングコマンドに渡す引数であれば何でも受け取れます。
マッピングの定義
基本的には、モード指定とマッピングを渡すだけです。
渡されたモード全てに対して同じマッピングを定義します。
Keymap nx s <Cmd>DoSomething<CR>
" same as ↓
" nnoremap s <Cmd>DoSomething<CR>
" xnoremap s <Cmd>DoSomething<CR>
引数arguments-of-map-commands
はマッピングコマンドに透過的に渡されるので、<expr>
などのオプションもそのまま使用できます。
Keymap no <script> <expr> s SomeCondition() ? '<Plug>(do-something)' : 's'
" same as ↓
" nnoremap <script> <expr> s SomeCondition() ? '<Plug>(do-something)' : 's'
" onoremap <script> <expr> s SomeCondition() ? '<Plug>(do-something)' : 's'
旧バージョンの解説
以前この記事で紹介していたものでは、マッピング文字列の中に<Plug>
が存在する場合はnoremap
ではなくmap
を使う形にしていました。
Keymap nx s <Plug>(do-something)
" same as ↓
" nmap s <Plug>(do-something)
" xmap s <Plug>(do-something)
また、以下のように「関数を呼び出し、その返り値の中に<Plug>
が含まれる」ような場合は正しく判定できず、noremap
が使われてしまうため…
function! s:some_function() abort
return "\<Plug>(do-something)"
endfunction
Keymap n <expr> s <SID>some_function()
" same as ↓
" nnoremap <expr> s <SID>some_function()
Keymap!
を使うことで、引数に関わらずmap
を呼び出せるようにしていました。
Keymap! n <expr> s <SID>some_function()
" same as ↓
" nmap <expr> s <SID>some_function()
現在は、VimもNeovimも<Plug>
をnoremap
することが可能になっているため、こういった工夫は不要になっています。
Vim: https://github.com/vim/vim/commit/1fc34225acbee5ddca2b9ec3f82b3014d385b7f8
Neovim: https://github.com/neovim/neovim/pull/17591
マッピングの確認
{arguments-of-map-commands}
を省略すると、nmap
などを無引数で使った場合のように、定義済みのマッピングを表示します。
Keymap nx
" same as ↓
" nmap
" xmap
引数としてマッピングを表示したいキーを渡すことも可能です。このあたりはマッピングコマンドと同じです。
Keymap nx s
" same as ↓
" nmap s
" xmap s
なぜつくったか
実は、Neovimには既にnvim_set_keymap()
およびvim.keymap.set()
というAPIが存在します。
しかし、これらの「モードを配列で渡す」「<expr>
などのオプションを辞書として渡す」といった点が 個人的な好みに合わなかった 改善できると感じたため、今回のKeymap
を自作しました。
Vim scriptで実装しているので、Vimでも同様のコマンドを利用できるという点もポイントです。
おわりに
今回のコマンドを使用し、重複した記述を減らせたことで、設定ファイルの見通しが良くなりました。
よろしければご利用ください。
Discussion