Vim ( & ideavim ) キーマップ設定ガイド

Vim ( & ideavim ) キーマップ設定ガイド

なにやら難しそ〜うな vim の設定を、キー設定に絞って基本戦略という考え方でまとめてみようと、唐突に思った

凝ったワザとかイベント設定とかは視野に入れず、手に馴染むキー設定を自分で見つける方法を紹介します

なので設定集ではありません
自分の道具に人の設定が馴染むわけはないからね

こんな事を考えつつ自分で色々設定すると vi はグッと良い道具になるよ、というお話です

## 基本
### ヘルプ
`:tab help s`みたいにヘルプを引くと`s`の説明が確認できる

```
["x]s       [count] 文字を [レジスタ x に入れ] 削除し、挿入を始め
            る (s は Substitute --置換 を意味する)。"cl" と同義で
            ある (行単位でない linewise )。
```

開いたタブは`:bdelete`で閉じられる ( バッファの b )

ちなみに、`:tab h s`でも開けるし、`:bd`でも閉じられる

vim の命令は一意にできる長さを打てば残りは打っても打たなくても良いので、設定ファイルに書くときはフルで、手で打つときは略記で打ったりする

以後 vim のマニュアルに則り、略して良い部分は`[]`で囲って表記する

`:tab h[elp] s`, `:bd[elete]`

### 設定方法
設定ファイルに設定を書く場合は、ホームディレクトリに`.vimrc`を作ってそこに書けば良い

vim を再起動するか、`:so[urce] ~/.vimrc`で読み込むことで反映できる

設定ファイルを書く前に動作確認をしたい場合は、設定ファイルの内容を`:`で直接入力すれば良い

以下に例を示す

```vimscript
" sample
nnoremap j k
```

この設定はノーマルモードの`j`を`k`の挙動にする設定である ( コメントは`"` )

設定ファイルに書く場合はそのまま`nnoremap j k`と書き、直接入力する場合は`:nnoremap j k`とすれば良い
ただし直接入力した設定は、vim を終了すると破棄される

vim を終了せず設定を破棄したい場合は、`:nun[map] j`と入力すれば良い ( Normal UN Map )

また、`:nnoremap`だけ入力すると今ノーマルモードに設定されているキー設定が確認できる

### 設定の基本文法
先ほどの`nnoremap`について補足する

vim のモードは実は細かくいくつか存在しているが、まずはこの 3 つだけ知っていれば十分設定を読み書きできる

```vimscript
" normal mode
nnoremap a b

" visual mode
vnoremap a b

" insert mode
inoremap a b
```

ちなみに`noremap`と`map`が存在する、違いは以下の通り

```vimscript
nmap b c
nmap a b
```

と設定した場合、`a`は`c`の挙動をする


```vimscript
nnoremap b c
nnoremap a b
```

と設定した場合、`a`は`b`の挙動をする

他の設定を辿るか辿らないかの違いだが、基本的には再マップされない`nnoremap`を用いる方が安全で理解しやすいため、本記事では`noremap`を用いる

また、装飾キーは以下の様に表現する

`nnoremap <s-a> b`は`nnoremap A b`と同意である
shift の場合は大文字で設定しても良いが、ctrl キーとかを装飾とする場合は`<c-a>`と記載する

## 方針
それでは本題

いくつかのグループに分けて整理すると手に馴染みやすいと思うので、グルーピングの方針を紹介する

+ shift で逆挙動
+ shift で強化
+ prefix を統一する
+ 左右や上下の向きを統一する
+ 他頻出するが打ち辛いもの
+ IntelliJ Actions

### shift で逆挙動
デフォルトのキー設定のうち、shift をつけると挙動が逆になるものがいくつかある

`o`: カーソル**下**に空行を作って入力モードにする
`O`: カーソル**上**に空行を作って入力モードにする

とか

`p`: カーソルの**後**にペーストする
`P`: カーソルの**前**にペーストする

とか

`f`: カーソルの**右**に向かって文字を探してジャンプする
`F`: カーソルの**左**に向かって文字を探してジャンプする

とか

`n`: 検索文字を**下**に探してジャンプする
`N`: 検索文字を**上**に探してジャンプする

これに則って**逆の挙動なのに全然違うキーマップをリマップ**すると良い

例えば

`u`: undo
`<c-r>`: redo

これは覚えづらいし流れで入力しづらいので、以下の様にリマップするのがおすすめだ

```vimscript
nnoremap U <c-r>
```

他にも自分で独自のキー設定を行う場合も、これを念頭に置いて設定するのがおすすめだ

### shift で強化
デフォルトのキー設定のうち、shift をつけると挙動が強化されるものがいくつかある

`i`: カーソルの**前**で入力モードとなる
`I`: カーソルの**行頭**で入力モードとなる

とか

`s`: １**文字**を削除しつつ入力モードとなる
`S`: １**行**を削除しつつ入力モードとな

とか

`v`: **文字単位**のビジュアルモードになる
`V`: **行単位**のビジュアルモードになる

とか

`zo`: 折り畳みを**１つ**開く
`zO`: 折り畳みを**再帰的に全て**開く

これに則って**デフォルトのキーに合わせて強化コマンドを設定**すると良い

例えば`j`で**一文字下**に移動するコマンドを強化して`J`を**画面の一番下**に移動するコマンドにしたりすると、手に馴染むと思う

ちなみに僕は色々試してみて**10 行下**に移動するコマンドにした

```vimscript
nnoremap J 10<Down>
```

### prefix を統一する
先述の`zo`の様に、複数のキーを使って設定することも可能だ

例えば`z`で始まるものは畳み込みに関係するものが多い ( ジャバラのイメージらしい？ )

自分でよく使う似た設定は同じプリフィックスでまとめたりすると使いやすかったりする

例えば僕はタブ操作に関係するものは`g`で始まる様に設定している

```vimscript
" 新規タブ
nnoremap gk :tabedit 

" タブを閉じる
nnoremap gj :bd<CR>

" タブを閉じる ( 強制 )
nnoremap gJ :q!<CR>
```

これはもともとタブ左右切り替えが`gt`と`gT`だったので、それに寄せたらこうなったって感じだ
`gj`に対して`gJ`が強力なコマンドになっているのも、基本方針に則っている

<details><summary>余談　イメージ</summary><div>

むかーしマウスジェスチャーとかで設定した閉じるアクションが ↓ だったので、僕はずっと閉じるは ↓ のイメージ
最近の iPhone のタスク管理とかだと ↑ スワイプで終了したりするけど、あんなイメージで使ってる

▲ 余談

</div></details>

他には「まぁ無くなってもいっかな」ってキーを prefix 用にしてしまう、というのもアリだ

例えばよく例に上がるのが`s`だ ( 僕は好きなので潰してないけど )

`s`は１文字消しつつ挿入モードになるんだけど、あんま使わないってのと`cl`が同じ結果になるのでよく潰して良いと言われている

あと`<Space>`も実質空いているので、こんな押しやすいキーを使わない手はないかな ( IntelliJ Actions で触れる )

あとは逆転の発想で`←`, `↑`, `→`, `↓`を好きに使ってしまうという発想もある

案外カーソルキーは使わないし、使わない方が良いし、稀にしか使わないけど設定しておくと便利なやつとかを当てはめておくのもアリだ

<details><summary>余談　カーソルキー</summary><div>

というかカーソルキーを使う限り、一生懸命 vi に慣れようとしてもせいぜい普通の 1.2 ~ 1.3 倍くらいのスピードにしかならない

それだったら vs code なり sublime なりに集中した方がよっぽど良いと、僕は思う

vi に慣れたいんだったらカーソルキーはやめよう

こんな感じで無効にしてしまった方がずっと良い

```vimscript
nnoremap <Left> <Nop>
```

参考: [Vimのカーソルキーを封じる - Qiita](https://qiita.com/suzuki-hoge/items/90fce0d763a8d11d2587)

▲ 余談

</div></details>

### 左右や上下の向きを統一する
例えばジャンプのデフォルトのキーはこうなっている
( vim で言語設定してジャンプできる様にしてない場合は、`:tab h[elp] x`で開いたヘルプの中や、IntelliJ の vim プラグイン ( IdeaVim ) で試すと確認できる )

`<C-]>`: 進む
`<C-t>`: 戻る

こんな押しづらくて覚えづらい**２つ**のコマンド、手に馴染むわけないよね！

僕はこう変えた

```vimscript
nnoremap tl <C-]>
nnoremap th <C-t>
```

基本的に新しいタブは右側に開くので、カーソル移動の`l`, `h`とイメージを合わせてみた感じだ
これなら「ジャンプは`t`と方向だったな」って感じで習得できる

それから、タブ切り替えも僕はこう変えた

```vimscript
nnoremap gh gT
nnoremap gl gt
```

同じ考え方で、右のタブに切り替えるのを`l`に、左を`h`にしている

もう一つ僕の設定を
こんなのもアリだと思う

```vimscript
nnoremap zj zt
nnoremap zk zb
```

`zz`はカーソルのある行を画面の真ん中になる様に位置調整するコマンドで、「もうちょっと上も下も見たいな」って時に重宝する

`zj`と`zk`で画面の真ん中ではなくて画面の上下端に調整することができる ( わかりづらいけど、カーソルを動かすのではなくスクロールバーを動かす動き )

もちろんこれもカーソル移動の`j`, `k`と合わせて設定している

こういうのは自分でうまく設定すると本当に手に馴染むので、ぜひ試してみて欲しい

### 他頻出するが打ち辛いもの
ここは今までの法則に則らないものだが、２つ発想の種を紹介したい

何が頻出するかは本当に人によるので、「よく使うな」と思ったら都度色々設定してみるのが良いと思う

僕は例えばこんなのを設定している

```vimscript
vnoremap v <C-v>
vnoremap , <ESC>ggVG
```

一つ目は`vnoremap`だけど、実質はノーマルモードで`vv`と同じで、これで矩形選択ができる
矩形選択は縦に消したり縦に行末セミコロンを書いたりできるので極めて重宝する

これは**装飾キーは os や pc によって位置が違ったりするのであまり使いたくない**という考えから来ている
家は mac だけど会社の特定の環境は windows なんだ、とかあるよね

二つ目も実質ノーマルモードの`v,`と同じで、これは範囲全選択ができる
僕はチャットやメールも vi で書くので、書き終わったら`v,y`ってすることがとても多いためだ ( ctrl + a, ctrl + c と同じ感じ )

これは見る通り`ggVG`という普段から多用するキーのただの連打だけど、**使用頻度を考えたらリマップした方が楽そうだな**という考えから来ている

この辺は好みの問題なので、参考までにという感じだ

### IntelliJ Actions
最後に IntelliJ に特化した話をしたい

何度か出てきている ideavim だが、こいつは結構すごい

設定ファイルは`~/.ideavimrc`という別のファイルだが、基本的に vimscript の文法のままキーマップとかができる

さらにすごいのは、`.ideavimrc`からは IntelliJ の機能が呼べるということだ
例えば「横断検索」とか「リファクタンリング」が`nnoremap a Refactor`みたいな感じで呼べてしまうのだ


あんまりちゃんとした？マニュアルがなさそうだったので、僕はここを見て探した
[IdeaVim actionlist gist](https://gist.github.com/zchee/9c78f91cc5ad771c1f5d)

僕の設定の一部を抜粋して紹介したい

```vimscript
nnoremap <Space>r :action Replace<CR>
vnoremap <Space>r :action Replace<CR>

nnoremap <Space>R :action ReplaceInPath<CR>
vnoremap <Space>R :action ReplaceInPath<CR>

nnoremap <Space>f :action Find<CR>
vnoremap <Space>f :action Find<CR>

nnoremap <Space>F :action FindInPath<CR>
vnoremap <Space>F :action FindInPath<CR>
```

基本方針に則って普段使っていたアクションをマッピングしたものだ

目立つくせに暇をしている`<Space>`を**共通の prefix**にし、`r`と`R`や`f`と`F`が**強化の関係**になっている

また、ジャンプもこんな感じに設定している

```vimscript
nnoremap tl :action GotoDeclaration<CR>
nnoremap tL :action GotoImplementation<CR>
nnoremap th :action Back<CR>
```

`tl`と`th`が先述の通り**左右の方向と合わせた**進むと戻るで、`tL`が interface ではなく implementation にジャンプするアクションになっている ( 極めて便利 )
これも基本方針通り`tl`と`tL`が**強化の関係**になっている

<details><summary>余談　os やエディタを使い分ける面倒さ</summary><div>

実はこの設定は最近取り入れた

リモートワークになり windows を触らないといけなかったりリモート接続でキーの位置が狂ったりしていて、装飾キーを使う操作が苦痛だった

装飾キーから離れて vi に依存する様にすると os や物理キーに縛られづらくなると思うので、今後も積極的に考えていきたいと思う

ちなみにエディタを乗り換えたときに「１行消す」「置換ウィンドウを開く」とかのショートカットキーを覚え直すのが嫌なので、僕は vi 操作一本に絞って覚える様にしている

▲ 余談

</div></details>

## 自分の設定を作るには
基本スタンスはこんな感じだ、どうだろう？

あくまで個人的な考え方だけど、僕はこんな感じだったので参考まで
( ちなみに僕は勝手に vi を使い始めて今 8 年、周りに vimmer はほぼいなかったので完全に我流 )

+ いきなり人の設定を真似したりチートシートを覚えようとしても、無理に使う感じがするので合わない
+ 基本的に vi は素で使って「あ、僕これよく使うな」「んーこれ面倒だな vimmer はどうやってるんだろう」って思ったら都度調べたり設定したりしてた
+ そうすると本当に自分が使うものだけが自分の形で残る
+ 知見を広げるには人の設定ファイルを google とか git とかで探して、片端からヘルプを読んで取り捨て選択をしていた
+ たまに設定の棚卸しをして、捨てたりリマップしたりする ( これ絶対便利！って気持ちで設定したのを一度も使ってなかったりするw )

とにかく**自分の欲に忠実に、そして堅実にヘルプを見てカスタマイズするのが醍醐味**だと、僕は思うな！

良い道具磨きを

## こちらもよろしく
Vim および作業効率化でいくつかネタをしたためている、こっちも見てもらえると嬉しいな

+ Vim ( & ideavim ) キーマップ設定ガイド ( 本記事 )
+ [Vim パワーはテキストオブジェクトと繰り返しが７割 - 脱初心者の一歩](https://qiita.com/suzuki-hoge/items/b0619996723cbbb7f2cd)
+ Vim でテキストを "見る" - テキストを読む tips ( 仮 )
+ タブを支配せよ ( 仮 )