Vim幼稚園からVim小学校へ

emacsキーバインドに慣れ親しんだせいで長らくVim幼稚園のままだった私が来ましたよ。キーバインドを一度に覚えようとすると挫折しやすいので、以下のように少しずつボキャブラリーを増やすのがたぶん吉。

特記しない限りノーマルモードが前提。後、.vimrcでの設定については最小限にしか触れない (emacsでつい設定ファイルをいじってしまいがちだった反省から) ので各自好きにしてください。

# Level 1

最小限の使い方だけ覚えて、ぶっつけでサーバーの設定ファイルを更新したりしていた。10年以上この状態。

* `i`でその場でインサートモード
* `a`で直後の文字にインサートモード
* `:wq`で保存終了
* `:q!`で保存せずに終了
* 移動はひたすらカーソルキー
* `x`でカーソル下の文字を削除
* 困ったら`Esc`キーを連打

上はもともと、vimの先祖でずっと機能の少ないviの操作なのだけど、viなら~~ほぼどんな~~たいていのUnix系環境にプレインストールされている。逆に言えば、最小限これだけ覚えれば初めてのサーバーや古代遺跡から発掘された世界遺産クラスのサーバーでもおそらく作業できる。

Vimはめちゃくちゃ巨大なファイルでもあっさり開けるという隠れたメリットがあることを知る (たいていのエディタは巨大ファイルを食わせると数十分押し黙るかコケる)。

# Level 2

* `/`で検索できることがわかった。
* `h`左、`j`下、`k`上、`l`右のvim移動をおそるおそる覚える
* `gg`で最初の行、`G`で最終行にジャンプできる
* `ctrl-f`で1ページ後、`ctrl-b`で1ページ前に移動
* 大文字の`H`、`M`、`L`はそれぞれ画面の最上部・真ん中、最下部の行にカーソルを移動する
* `=`でその行のインデント位置を自動修正できる
* `u`でアンドゥ、`ctrl+r`でリドゥ
* `dd`で行全体を削除
* `yyp` (コピペ) と `ddp` (カットしてペースト) を覚えた

見てのとおり、まだVimのいいところを全然使っていない。スクロールもカーソルキーでもたもたやってたりする。

# Level 3

Vim魔神と出会う。教えのレベルが高すぎてなかなかついていけないので、じわじわと体に染み込ませている。

## vimのモード
vimのモードを整理しよう:
- ビジュアルモード (`v`キー) がたぶん初心者に一番わかりやすいとのこと
- インサートモード (`i`や`a`キーなど)
- ノーマルモードは基本となるモード
- コマンドモード (`:`) で各種コマンドを実行

## オペレータとモーション
vimのキー(主にノーマルモードについて)は、大きく分けて「オペレータ」と「モーション」の2種類がある。これを把握することが大事。

- オペレータ: 動詞として動作を指定する。主要なものは4つなのでここから覚えよう
- モーション: 対象範囲を指定する

オペレータは意味のあるキーバインドになっているので、以下のような感じで覚えよう:

- `c` : change (変更)
- `d` : delete (削除)
- `y` : yank (ヤンク: コピーと同義)
- `g` : go (移動全般)

ノーマルモードでは基本的に最初にオペレータを入力し、その後に範囲指定を行う(CUI的発想)が、ビジュアルモードでは範囲を最初に選んでそれからオペレータを入力する (GUI的発想)という違いがある。

なお、Vim魔神に言わせると、Vimは日本語文書の編集にはあまり向いてないそうだ。多分スペース分かち書きされる英語でないといろいろつらいかも。

# Level 4

だんだんVimらしい技を覚え始めた。

* `^`または`0`で行頭へジャンプ、`$`で行末へジャンプ。正規表現と同じにしたということだけど、自分はemacsの`ctrl-a`と`ctrl-e`操作に慣れきっていたのと、キー配列で`^`が右で`$`が左というふうにジャンプ方向と逆になっているのが直感に反していて、これは今でも個人的にいただけない感じ。あまり使わないようにしてる。
* `o`を打つと次の行を空けてインサートモードになる。`O`を打つと前の行を空けてインサートモードになる。これは現在のカーソルがその行のどこにあっても関係なく実行できる。これを知って、初めてVimがうらやましくなった。
* 単語の上で`*`を押すといきなりその単語を検索して全部ハイライトしてくれる。`n`で次の検索結果、`N`で前の検索結果にジャンプ。ハイライトを消すには`:noh`(no highlightのことだろう)と打つ。
* 一文字だけ置き換えたいときはその文字の上で`r`(replace)キーを打ち、差し替えたい語を打つだけでいい。差し替え後自動的にノーマルモードに戻るので、いちいち`i`でインサートモードに入って`delete`で削除して`Esc`でノーマルモードに抜けるより早い。
* `w`を打つと次の単語の頭に、`b`を押すと前の単語の頭にジャンプする。大文字の`W`と`B`は記号を単語の一部とみなすのでジャンプ距離が伸びる。これは単なるショートカットではなく、`w`はこの後いろいろと応用が効く。行内での左右移動は基本これにするのが吉。
* （修正）`e`を打つと現在の単語の末尾にジャンプする。既に現在の単語の末尾にいる場合は次の単語の末尾にジャンプする。ところで前の単語の末尾にジャンプってあるんだろうか(追記: `ge`だそうです)。
* 追記: `ea`と打つと、現在の単語の直後でインサートモードになる。これも地味に便利。

# Level 5

* ""で囲まれている中にカーソルを置いて、`ci"`(change inner quoteと覚えよう)と打つと、""の中身を消してインサートモードに変わってくれる。""の末尾までカーソルを移動して`i`を押して""の中身を`delete`で1つずつ消して、とやるより早い。これを覚えて、俄然Vimがよさげに見えてきた。この`ciなんちゃら`は応用が効く。たとえば`ciw`とすれば、カーソルがある単語だけが消えてインサートモードに変わるし、`ci'`とすれば''で囲まれたところで同じことができる。
* 追伸: 最近覚えた`cit`は、HTMLタグに挟まれた要素をまるっと消してインサートモードになってくれる。
* 魔神いわく、インサートモードの`Esc`を`jj`にバインドしておくとめちゃ便利だそうだ。.vimrcに`inoremap <silent> jj <ESC>`と書けばよい。jjという文字の並びはまず出てこないので実用上支障はない。
* `.`は直前に行った「一連」の操作を繰り返す。単なるRedoと違い、上で説明した`ci"`のような塊を繰り返してくれる。カーソル移動などのモーションは繰り返されない。`.`はうまく使うと、操作をガンガン半自動化できるらしいので、今後の研究課題。
* レコーディング機能を使うと一種のスニペットのように使える (もっと強力な使い方もあるらしい)。`q`に続けて打った文字に登録される(登録できるのは1文字なのでアルファベット26文字と数字といくつかの記号ぐらいしか使えない)。以後の操作は記録され、再度`q`を押すとレコーディング終了。再生するには、`@`に続けてそのキーを押す。とりあえず自分はRubyのshebangとGolangのテンプレートを登録してみた。

# Level 6

何だかこの自虐的な記事が妙に多くの人にストックされてしまった。続きを別の記事にしようかと思ったけど、この記事に書き足すことにする。

* Level 4で「行末へのジャンプ`$`が押しにくくてつらい」と書いた。しかし考えてみれば行末や行頭に行くときはどうせそこで何かを挿入するのだから、`A`で「行末移動&インサートモード」、`I`で「行頭移動&インサートモード」の方が圧倒的に押しやすく、しかも押すキーが1つ減る。これで`$`とおさらば。通常のエディタだと「そこに行ってから挿入」という2アクションになるのが、Vimだと1アクションになる。

* そろそろビジュアルモードというものも使ってみよう。選択部分のインデントを揃える方法:

1. `ggVG`で全選択する。`gg`は行頭移動、大文字の`V`は行選択、大文字の`G`で行末移動なので、これを一気に実行できる。なお、小文字の`v`で`ggvG`とすると、最終行が微妙に全選択されそこなう。
2. `=`を押すとインデントが一気に揃う。以上。

* 選択範囲をコメントアウトする方法: 

1. 開始地点で`Ctrl-v`を押し、ビジュアルモードの矩形選択を始める
2. `j`で下に降りてコメントアウトしたい範囲を選択する
3. 大文字の`I`を押して行頭挿入を開始し、その言語に合ったコメントアウト文字(`#`とか)を挿入
4. `esc`を押すと、選択範囲に一気にコメントアウト文字が追加される。

これについてはSublimeやRubyMineの`⌘+/`の方が楽だと思う。コメントアウト文字を言語ごとに思い出さなくても済むので。

* http://qiita.com/okuramasafumi/items/50c64825cf365e8f6e78 でいいコマンドを覚えた。大文字の`S`(slaughterと覚えた)を押すと、いきなり現在の行を全削除してインサートモードになる。今までは一行消してから書くために`dd`で削除して`i`でインサートモードになって改行を挿入してそれから1つ上に戻って...と相当無駄なことをしていた。

* 同じく大文字の`C`(cutと覚えた)を押すと、現在の位置から右を全削除してインサートモードになる。大文字の`D`で右を全削除までは知ってたけど、インサートモードにまでなるので1ステップ節約できる。
* 追伸: 小文字の`s`は、カーソル下を1文字だけ消してインサートモードになる。一見使い道なさそうだけど、スタブの#をURLに置き換えるときとかいいんですよね。こんな特等席のキーバインドをこれに与えるのはちょっともったいない気がしないでもないけど。

* 保存して終了を大文字の`ZZ`で行なうと、`:wq`より通っぽいかも。

# Level 7
魔神からまた教わる。

* vimは実はzipファイルやgzipファイルを解凍せずにそのまま開ける。
* `dG`とすると、カーソルのあるところから最下部までを一気に削除する。`vGd`より1つ少ない。
* `s`はカーソル上の文字を削除してかつインサートモードになる。`x`を押して`i`を押すより早い。Level 6の大文字`S`とペアで覚えるとよい。
* 大文字の`K`を押すと、外部コマンドを呼んで検索してくれる。何も設定していなければ`man`コマンドが発行されるのでmanを引くことができる。カスタマイズしたければ、.vimrcに`set keywordprg=コマンド`という要領で書けばいい。manの代わりに英和辞書を指定したり好きな言語のリファレンスを指定したりなどできる。
* `g;`と打つたびに、直前の変更箇所にジャンプする。戻るときは`g,`だそうだ。

# Level 8

* インサートモードで行頭に何か入力して`ctrl+x``ctrl-l`と押すと、そのファイルの中にある行のうち入力とマッチした行がずらりと下に表示されて補完できる。つまり「行補完」。ちょうどExcelのセル入力時に上のセルの内容がドロップボックスに表示されるようなあれ。
* インサートモードで何か入力して`ctrl+p`を押すと、現在vimで開かれているすべてのファイルに出現した単語が補完候補として表示される。
* ファイルパスを入力しかけて`ctrl-x``ctrl-f`を押すと、現在の環境でのファイルパスを補完してくれる。`/etc`と打ってからこのキーを押せば`/etc/passwd`などの候補が表示される。
* とここまで書いておいて何だけど、neocomplete というプラグインを入れておくと入力するだけでどんどん補完候補が表示される(ファイルパス補完も行われる)。インストール方法はググればすぐ見つかる。

# Level 9

そろそろ小学3年生ぐらいにはなっただろうか。

* `:r! コマンド`とすると、その場でシェルのコマンドを実行して結果をそこに貼り付けられる。たとえば`:r! ls`とすればカレントディレクトリのファイルの一覧を貼り付けられる。これはシステム管理者的に非常にありがたい機能だと思う。
* `ctrl-x``ctrl-o`はオムニ補完と言って、文脈に合った候補を表示してくれるのだそうだ。詳細と設定はググってください。
* 魔神いわく、vimで一番重要な機能といってもよいスニペットはぜひとも導入すべきであると。これに比べればvimの他の機能などおまけのようなものだとまで言い切ってた。ということでneosnippet ( https://github.com/Shougo/neosnippet.vim )というものを導入しましょう。そして定型化可能な入力は片っ端からスニペットに登録して瞬時に呼び出せるようにしましょう。詳細と設定はググってください。
* 書こうと思って忘れていたのを久しぶりに追加。`gj`や`gk`と入力すると、改行のない長い段落の中を普通に1行ずつ上下移動できる。いつもの`j`と`k`だと、1行ずつではなく1段落の上下移動になってしまうので。なぜかこれをすぐ忘れてしまう。

# Level 10
* http://easyramble.com/join-lines-with-vim.html で紹介されている複数行を一気に結合する技がいい。ノーマルモードで大文字の`J`を打つと次の行との間の改行がスペースに置き換わって1行に結合される(英語向き)。さらに`gJ`にすればスペースに置き換えずに結合される(日本語向き)。これを応用して`5J`とすれば現在位置からの5行を一気に結合できる。そういえばこの数字を最初に指定して操作するのをあんまりやってこなかった。もっとやろう。
* こちらの記事 http://qiita.com/jnchito/items/57ffda5712636a9a1e62 にもう少し応用系の技がある。
* http://itchyny.hatenablog.com/entry/2014/12/25/090000 も読んどくと幸せになれそう。大文字系の`D`とか`C`とか`Y`とか知らなかった。

# Level 11 -- 横道にそれる

と、ここまで進んできて自分の中にジレンマが生じる。IDEやSublime Textも使っている自分は、Vim以外のところでも同じスニペットを使用したい。でもVimのスニペットはVimの外で使う仕様ではない。その一方、Gitコミットメッセージの書き込みなどはVimが一番安定しているのでVimもこのまま使い続けたい。

どうしよう。

すると、今までヘルプ検索にしか使ってなかったDash ( http://kapeli.com/dash )というドキュメント検索アプリのスニペット機能が実は優れものだったということに気付き、むしろこれを中心にエディタ環境を整備し直すことにする。

DashのスニペットはMacのどこからでも呼び出せる。誤動作を防ぐため`;`などの記号をスニペット名の頭に付けるのがよい。

以下を.vimrcに追記してvimからも`K`呼び出しができるようにした。Dash.vimを導入してもいいかもしれない。

```vim
" Dash integration for objc and nimrod.
command! DashNim silent !open -g dash://nimrod:"<cword>"
command! DashDef silent !open -g dash://"<cword>"
nmap K :DashDef<CR>\|:redraw!<CR>
au FileType nim  nmap K :DashNim<CR>\|:redraw!<CR>
```

そしてSublime TextもキーバインドをVim式に変更し、Dashdocをインストールして`ctrl-h`でDashを参照できるようにした。Vim小学校3年の自分からみて、Sublime TextのVimキーバインド再現率は8-9割ぐらいという感じ。

Sublime TextをVimキーバインドにしてみると、`⌘-s`などの普通のMacのコマンドキーが使えてありがたい。保存のために`:w`とかいちいち打つよりやっぱり便利。`⌘-/`で言語にかかわらずコメントを付け外しできる機能とか待ってましたという感じ。VimではMacのコマンドキーがまったく前提にないのが不自由なのだけど、カスタマイズしてコマンドキーを使うようにしたところでキーバインドを考えるのも変えるのも面倒だし、環境が変わればズタボロになってしまうので、VimはVimで完結させておくことにした。

ということで、当面Sublime TextでVimモード+Dashでやってみます。何だかVim小学校からVim養護学級へ移籍した感があるけど。

# 追伸

この先のレベルがどこまであるのか知らないけど、Level 50 ぐらいはありそう。そこまでくると天下一Vim武闘会で優勝するクラス。

なお、魔神作のマークダウン編集用Vimプラグイン https://github.com/yaasita/ore_markdown が一部で異様に評判がいい。自分はまだインストールしてないけど。