読者です 読者をやめる 読者になる 読者になる

vimでキーマッピングする際に考えたほうがいいこと

vim

この記事はVim Advent Calendar 2012の153日目の記事です。
152日目はmanga_osyoさんによるVim で現在の検索位置を表示するでした。

vimをある程度使うようになると、ある操作(機能)を素早く呼び出すためなどでキーマップを設定するようになります。 ですが、数あるキーの中でどのキーに機能を割り当てるか結構頭を悩ませることが多いかと思います。
ちゃんと既存のキーの機能を意識して割り当てられれば良いですが、たまに「えっ、そのキー潰しちゃうの?」と思うような キーを潰しているのを見かけます(出典:vimrc読書会にて)。
意図してやっているならいいですが、わからぬまま重要なキーを潰してその機能を全く使わないという結構もったいないものです。
そこで、キーマッピングする際に考えたほうがいいことを記述したいと思います。

いつキーマッピングするか?

まずはどういう時にキーマッピングするかについて簡単にまとめたいと思います。

pluginの呼び出しに割り当てる

便利なplugin入れたら素早く呼び出すためにキーマップを設定したいと思うのがvimmerのさがというものです。 特にコマンドの入力が必要なpluginでは毎回コマンドを入力するのは面倒なのでキーマップを設定することが多いです。 例えば、pluginのUniteのコマンドを定義する場合以下の様に設定します。

nnoremap [unite]    <Nop>
nmap     <Space>u [unite]

nnoremap <silent> [unite]c   :<C-u>UniteWithCurrentDir -buffer-name=files buffer file_mru bookmark file<CR>
nnoremap <silent> [unite]b   :<C-u>Unite buffer<CR>

この設定により、<Space>uc<Space>ubでUniteのコマンドを実行することができます。 ちなみに、初めの二行は<Space>uをprefixキーとして設定して、[unite]でキーマッピングした箇所は<Space>uで置き換えるというhackです。 このように定義しておくメリットは、vimrc上見やすくなるという効果もありますが、<Space>uと打った時に[unite]と表示されるため、prefixキーを打ったということが把握できるという効果もあります。

vim hacksにも説明があるので知らなかった方はこちらもどうぞ
Hack #59: 分かりやすいKey-mappingsを定義する

よく行う操作に割り当てる

上の「plugin呼び出しに割り当てる」と近いですが、こちらは自分で作った関数やちょっとした操作をキーマップに割り当てます。

例えば以下のようにhelpを引くキーマップを設定するなどです。

nnoremap <C-h>      :<C-u>help<Space>
nnoremap <C-h><C-h> :<C-u>help<Space><C-r><C-w><CR>

使いづらいキーを使いやすいキーに割り当てる

Vimではたくさんのキーに色々な機能が割り当てられていますが、人によって使うキー、使わないキーが結構まちまちだと思います。 マクロバリバリ使うぜ!という人や、マクロなにそれ美味しいのという人ではよく使うキーが異なるわけです。(あーでも皆さんマクロ使いましょうねマクロ。こんな便利な機能使わないともったいないですよ。) このキーよく使うのになんか押しづらいんだよなぁと思ったらキーマッピングを考える時かもしれません。 例えば、自分は以下のように置き換えてます。

コマンドラインモードに入るための:と、f,t,F,Tを繰り返す;を入れ替えてます。 ;のデフォルトの機能も使いますが、コマンドラインモードに入る方が圧倒的に多いので押しやすい;にコマンドラインモードに入る機能を割り当てています。

nnoremap ; :
nnoremap : ;

表示上の行移動(エディタで表示されている行)であるgj,gkと、実際の行移動(エディタの表示行ではなく改行コードを意識した実際の行)であるj,kを入れ替えてます。 表示上の行移動の方が直感的に便利だという判断から押しやすいj,kに割り当てています。

nnoremap j gj
nnoremap k gk
nnoremap gj j
nnoremap gk k

誤操作すると困るキーを無効化する

例えば、ZZ(保存して閉じる)とZQ(保存せず閉じる)はとても便利な機能なんですが、常用するとたまに「あ、保存したかったのに間違ってZQで閉じちゃったorz」なんてことがあり、誤タイプによるリスクが利便性を上回ります。 なのでこんな感じで無効化してしまうといいでしょう。

nnoremap ZZ <Nop>
nnoremap ZQ <Nop>

<Nop>は空マップで何もしないという意味になります(:help <nop>)。

他に無効にするといいのはQです。Qでexモードに入れるのですが、意図せずexモードに入ってしまい、特に初心者はどうしようもなくなって:qしてしまう方もいると思います(自分もその一人)。 今の時代exモードを使う事なんてほとんどないので、誤タイプ防止で無効化します。

nnoremap Q <Nop>

:help gqを参考にgqに割り当ててもいいですね。

nnoremap Q gq

どのキーにキーマッピングするか?

ここまでで、どういう時にキーマップを設定するかについてお話しました。 ではどのキーに割り当てるのがいいのかについてお話します。

といっても、感覚的にここらへんのキーが良さそうというのはあるんですが、実際本当にそうなのか整理したことがなかったので、この機会に整理してみました。 整理のポイントは2点、

  1. そのキーにデフォルトで割り当てられている機能を使うか?
  2. そのキーは押しやすいか?

1.は割り当てられている機能を使わないキーのほうがキーマッピングに適しており、2.は押しやすいほどキーマッピングに適しているということです。

上記2つのポイントで整理してまとめた資料をgistにあげました。 今回整理したのはnormalモードだけです。

vimで使うキーの機能使用頻度と打ちやすさの整理

上記を整理した結果以下のことがわかりました。

キーマッピングに適しているキー(今回はnormalモードだけ)

詳細はgistの資料を見ていただくとして、 normalモードでは特に以下のキーがキーマッピングに適していそうです。

  1. <Space>
  2. ,
  3. s
  4. t
  5. m(prefixに)
<Space>キー

<Space>のデフォルトの機能はlと同じであり、<Space>としてほぼ使う機会がない割にとても押しやすいキーです(:help <Space>)。

<Space>は他のキーと合わせてprefixキーとして使うことをおすすめします。

上でも例としてあげましたが、以下の様な感じです。 <Space>uで、plugin uniteの専用のprefixキーとして使っています。

nnoremap [unite]    <Nop>
nmap     <Space>u [unite]

nnoremap <silent> [unite]c   :<C-u>UniteWithCurrentDir -buffer-name=files buffer file_mru bookmark file<CR>
nnoremap <silent> [unite]b   :<C-u>Unite buffer<CR>
,キー

f,t,F,Tでジャンプした後に、反対方向に繰り返すのに使うキーです。 f,t,F,Tを多用する人であれば使う機会もあるかと思いますが、;の進行方向に繰り返す機能は使えど、行きすぎて戻りたいと思うことはほとんどありません。

なので自分は潰してしまっています。

<Space>ほどではありませんが、程々に押しやすいキーなので他のキーと合わせてprefixキーとして使うのがいいかもしれません。 以下のようにしてmapleaderに設定するのもお勧めです。

let mapleader = ","

" ,のデフォルトの機能は、\で使えるように退避
noremap \  ,

このように設定しておくと、mappingの際<Leader>といれた箇所が,で置き換わります。 以下の様な感じです。

nnoremap <Leader>vv  :<C-u>VimShell<CR>

" 上記は実際にはこのようにキーマッピングされる
nnoremap ,vv  :<C-u>VimShell<CR>

<Leader>は自分でキーマッピングする際にも使えますが、helpにも書かれている通り、pluginが使うことが意図されているため自分でキーマッピングする際はちょっと注意が必要です(:help mapleader)。

sキー

sのデフォルトの機能は、clで代用可能であり、この機能のためだけにsキーを使うのはちょっともったいないです(:help s)。
なので使えるキーがなくて困っている場合は思い切って潰す事をおすすめします。

<Space>より押しやすいとはいえないですが(キーの位置的に)、指一つで使える貴重なキーなので多用する機能に割り当てるのがいいです。 もちろんprefixとして使うのもいいと思います。

tキー

tのデフォルトの機能は、カーソル左方向に向かって、tの後に入力した文字までジャンプ出来る機能です(:help t)。 fと似ていますが、fと違うのはfは入力した文字までジャンプするのに対して、tは入力した文字の左側の文字までジャンプすることです。

tの機能はオペレーターモードで使う機会が多い機能ですが、normalモードで使いたいと思うことはほとんどありません。 最悪fで飛んだ後にhで同じ事が出来るので、潰してしまっても構わないと思います。

tsと同じような考えで割り当てるといいと思います。

mキー

mのデフォルトの機能は、マーカを設定することですが(:help m)、最大52個のキー(a-z,A-Z)に割り当てることができ、これらすべてのキーを使う人はめったにないと思います。

なので、例えばマーカに使うのはabcdeなどと決めておき、それ以外のキーをキーマッピング用として使ってもいいと思います。

マーカをあまり使わない人であれば、mm,mn,mk,mjなど片手で入力しやすいキーをキーマッピング対象として考えることをおすすめします。

キーマッピングの覚え方

上では、特に押しやすさに注目して話をしましたが、それだけだと困ることがあります。 マッピングするキーが増えていくごとに、忘れてしまうのです。

そこで、押しやすさ以外にも忘れにくさ(連想のしやすさ)も考慮してキーマッピングすることをおすすめします。

例えば、pluginの機能を割り当てるキーマッピングでは、そのpluginの頭文字を使うなどです。

上でも例に上げましたが(3回目)、uniteのキーマッピングは覚えやすさも考慮して、<Space>uをprefixとして設定しています。 さらに機能ごとにもなるべく連想できそうなキーを割り当てていきます。 例えば、Unite bufferなら、Uniteのu、bufferのbを取って、<Space>ubなどとします。

nnoremap [unite]    <Nop>
nmap     <Space>u [unite]

nnoremap <silent> [unite]c   :<C-u>UniteWithCurrentDir -buffer-name=files buffer file_mru bookmark file<CR>
nnoremap <silent> [unite]b   :<C-u>Unite buffer<CR>

<Space>は関係なくない?と思われるかもしれませんが、そこは、pluginに割り当てるキーは<Space>と決めておけば覚えられます。

置き換えた方が良いキー

整理した表を見ると他にも気になる点が見えてきます。 例えば、よく使うキーなのに押しづらいキーです。

最初の方でもお話しましたが、よく使うキーで押しづらいキーは、別のキーにキーマッピングする候補になります。

例えば、^,$,*などはよく使う割に、全てShiftを伴うキーであり(小指を疲弊する)、さらにホームポジションから若干遠く押しづらいキーです。 なので、私は以下のように割り当てています。

noremap <Space>h  ^
noremap <Space>l  $
nnoremap <Space>/  *

ちなみに今回整理したことで以下のキーマップを設定することにしました。%も押しづらいですよね。

noremap <Space>m  %

ちなみに、上で説明した「pluginに割り当てるキーを<Space>と決めておけば」、の説明と矛盾するのでは?と思った方はするどいです。 自分もちゃんと頭で整理してキーマッピングを行なってきたわけではないので、こういうキーマッピングもあります。 まだあまりキーマッピングしていない方は、なるべく自分の中で納得できるように整理するといいです。

まとめ

以上が、私がキーマッピングでキーを割り当てる際に考えることです。
大層な考え方でもないですが、皆さんがキーマッピングを考える際の一助となれば幸いです。
時間があれば、自分の整理表を作ってまとめて見ることをおすすめします。(きっと新たなキーマッピングの可能性が出てくると思います。) こんな考え方もあるよなどのご意見があればコメントいただけるとありがたいです。

あと、キーマッピングに限りませんが、vimレベルが上がるのでvimrc読書会に参加することをおすすめします。毎週土曜日23時からやってます。

それではVim Advent Calendar 2012の153日目を終わります。

明日のVim Advent Calendar 2012はtyruさんです。