Vimが本来もつ力を掘り下げる


## 注意

段取りが悪く書こうとしたことの3割程度しか書けておりません。
随時更新します。

## 動機

私はこれまでVimを軽量で高度なカスタマイズ可能なIDEとして使用してきました。
そのため、カスタマイズの方向性もIDEに近づける事を目指してきました。
しかし、カスタマイズを繰り返していくうちにプラグインを入れるまでもなく使用できる
Vimに本来備わっている機能群の多様さに気が付きました。

IDEの機能は、基本的に人間がするまでもなく機械的に仕事を私達が解釈し易いようにラッパーし、
ちょうどいいタイミングで自動で動作しいます。
いわば単純な作業を下請けしてくれるサポーターが常時横に居てくれるようなものと言っていいでしょう。

対してVimが提供するのはあくまでテキストを編集する機能であり、私達が任意で動作させる必要があります。
それはIDEのように人間の代わりに何かを勝手にやってくれるものではなく、
その用途を詳しく知るものが、効力を発揮する場面に用いて強力な力を発揮する
私達の手の延長といえるのではないでしょうか。

IDEではなくテキストエディタをあえてチョイスしている私たちは、これら手の延長をより深く理解することで、
特定の言語にとらわれることなく、テキストエディットを効率化することが可能です。

今回はそんなVimの側面について調べてみました。
なおテキストオブジェクトとかの超有名どこは割愛して自分が足りてないと思う部分を重点的に記載しました。

## 結論

さていきなり結論ですが、この記事を読むのはいいですが

[実践Vim　思考のスピードで編集しよう！](https://www.amazon.co.jp/dp/B00HWLJI3U/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

を読みましょう。貴方が本当にVim本来の機能を使って、より洗練されたエディットをしたいならば今すぐに購入すべき書籍です。
ですがそれでは記事にならないので、一応自分なりに咀嚼した内容を以下に記載します。

## エディット力を高める機能

### ファイル操作

Vimを使い始めの頃、GUIエディタのファイルメニューに相当するものが無いので私は相当混乱しました。
私は混乱を防ぐため、プラグインによりNERDTreeやVimFilterなどのファイラーを導入することで、
デフォルト機能を使わずにファイル操作を行っていました。
ファイラー系のプラグインはとても便利ですが、場合によっては標準のファイル操作の方がよっぽど早く操作できるときがあるのです。
あとサーバとかに入ったときにすぐ使えます。覚えておいて損はありません。

#### ファイルを開く

テキストエディタはテキストをエディットするプログラムなので、まずエディットの対象を開かねば話が始まりません。
ファイルを開くにはbash上で`vim {file}`で開きます。

しかし上記コマンドではVim起動時に指定したファイルしか開けません。
例えば貴方が100ファイルからなるプロジェクトを編集したいときにその1ファイルだけで事足りますか？
もちろん答えはNoです。

↓↓↓↓↓↓↓ あなたの記事の内容
もし貴方がファイルを色々触りたいときに、都度Vimを終了し、サイドVimを起動しているのであれば今すぐ`:edit`を使ってください。
───────
もし貴方がファイル色々触りたいときに、都度Vimを終了し、再度Vimを起動しているのであれば今すぐ`:edit`を使ってください。
↑↑↑↑↑↑↑ 編集リクエストの内容
`:edit`が長いと思う人は`:e`というショートカットコマンドが用意されているのでこちらを使用しましょう。
`:edit`を使用するとVimを起動したディレクトリ(カレントディレクトリ)に存在するファイルを開くことができます。
ちなみにカレントディレクトリがどこを指しているかは`:pwd`で確認することが可能です。

もしもカレントディレクトリにどんなファイルがあるか解らないというのであれば、以下のオプションをセットしてみてください。
`:edit <tab>`というように`:edit`の後にタブキーを押せば補完が表示されます。

```vim
:set nocompatible
:set wildmenu
```

![ファイルを補完するGIF動画]()

補完を`:set`でいちいち設定せずに出したいときは`.vimrc`に以下を追加しておいてください

```vim
set nocompatible
set wildmenu
```

なおファイルが多すぎるというときはファイルの前方と一致する文字列を打ち込めば補完候補が絞り込まれます。

#### 相対パスでファイルを開く

さて先程はカレントディレクトリからファイルを開く方法でしたが、
もし編集したいファイルが深い階層にあったらいかがでしょうか？
例えば以下のようなディレクトリ構成があった際...

```
.
├── bar
│   ├── aaa
│   │   ├── xxx.html <-既に開いている
│   │   ├── yyy.html
│   │   └── zzz.html
│   └── bbb
└── foo
```

既に`bar/aaa/xxx.html`を開いていて、同じ階層上にある`yyy.html`を開きたい場合どうするでしょう？
`:edit bar/aaa/yyy.html`を打ち込みますか？
いえ、それはナンセンスです。

`xxx.html`を開いている状態で`:edit %:h<Tab>`と押してみてください。
`:edit bar/aaa/`とファイルが展開されました。
これは`%`が現在開いているファイルのパスを意味しており、
`:h`が該当パスの親ディレクトリを指し示すキーワードだからです。
よって`%:h`を展開すれば`bar/aaa/`という解が得られるのです。

![相対パスを開くGIF動画]()

#### 新規にファイルを開く

先程は既存のファイルを開く方法をご紹介しましたが、
いまある既存ファイルだけでなく、新規ファイルを作成/編集するときもあります。
そんなときは`:new`コマンドです。そのままでわかりやすいですね。
また`:new`ですとウィンドウを横分割して表示しますが、その他にも縦分割やタブで新規ファイルを表示する方法があります。

| コマンド | 説明 |
|:-----------|:------------|
|:new    |新規ファイルを開く(横分割)|
|:vnew     |新規ファイルを開く(縦分割)|
|:tabnew     |新規ファイルを開く(タブ)|

![新規にファイルを開くGIF動画]()

#### ファイルを保存する

新規作成したファイルを保存しようとして`:write(:w)`を実行していませんか？(私は実行してました)
Vimを覚えたての頃`:w`で保存できるよ。と教えられたので仕方ないかもしれませんね。
ところが`:write(:w)`は上書き保存のコマンドのため、新規ファイルに使用できないので注意です。
新規ファイルを保存するときは`:save`を使いましょう。
なお`:saveas`で別名保存ができるので、ファイルコピーなどしたいときに便利です。

| コマンド | 説明 |
|:-----------|:------------|
|:save    |ファイルを保存する|
|:saveas     |ファイルを別名で保存する|

なお保存先はカレントディレクトリとなるため、
相対パスで保存したいときなどには前述の`%:h`なんかで指定してあげてください。

ちなみに`:new`の時点では新しいファイルは作成されないという点についても言及しておきます。
`:new`は新規ファイルを作成するコマンドではなく新規バッファを作成するコマンドなのです。
バッファについては後述します。

### 編集し易いレイアウトを整える

Vimを始めた当初、ウィンドウやらタブやらの移動がどうにも馴染めないため、
いろんな記事で紹介されているキーバインドで押しやすくしていました。(実は最近までやってた)
`<C-w>`(ウィンドウ操作のPrefix)を`s`とか`<Space>`に割当したり、
`gt`(次のタブへ移動)を`tl`や`gT`(前のタブへ移動)を`th`に割当したり。
ですがデフォルトをよく見てみると
キーバインドの統一感がでないとか、他のプラグインと干渉したりということがあって、
デフォルトのまま使うのが合理的だったりします。

#### ウィンドウを分割する

一つのウィンドウで編集に集中するのも良いですが、一つのファイルの複数箇所を見比べたり、
複数のファイルを同時に見たい場面などもあります。
そんな時はウィンドウを分割を分割しましょう。
`:split`でウィンドウを横分割。`:vsplit`でウィンドウを縦分割できます。

| コマンド | 短縮コマンド|キーバインド |説明 |
|:-----------|:------------|:------------|:------------|
|:split   |:sp |`<C-w>s` | ウィンドウを横に分割する |
|:vsplit  |:vs  |`<C-w>v` |ウィンドウを縦に分割する|

分割した後は以下のコマンドでウィンドウ間を移動しましょう。

| コマンド | 説明 |
|:-----------|:------------|
|`<C-w>w` または `<C-w><C-w>`   |次のウィンドウへ移動|
|`<C-w>j`     |上のウィンドウへ移動|
|`<C-w>k` |下のウィンドウへ移動|
|`<C-w>h`      |左のウィンドウへ移動|
|`<C-w>l`      |右のウィンドウへ移動|

![ウィンドウを分割するGIF動画]()

サイズ変更は割愛します。

#### タブ

ウィンドウをいくつも分割してしまうと一度に表示できる領域が狭まってしまうため、
エディットに編集できなくなることがありますこんなときは`<C-W>T`を押してください。
分割されたウィンドウに表示されていたファイルがタブで開かれます。

タブを開いた後で移動するには以下のコマンドを使用します。

| コマンド | 短縮コマンド|キーバインド |説明 |
|:-----------|:------------|:------------|:------------|
|:tabnext |:tabn | {count}gt |{count}で指定した番号のタブへ移動|
|:tabnext |:tabn |gt|次のタブへ移動|
|:tabprevious| :tabp| gT|前のタブへ移動|

![タブを開いて移動するGIF動画]()

#### バッファ

バッファはVimのもつ一つの大きな特徴であり、強力な機能です。
普通のテキストエディタであればファイルに対して「オープン」した状態「クローズ」した状態しか持ちえません。
れは簡単にわかることだと思います。
Vimには上記に加え「バッファ」した状態と言うものが加えられます。
Vimでファイルを開いた場合、開いたファイルはVimにバッファされます。
バッファされたファイルはバッファリストに格納され、たとえ`:q`で閉じたとしてもリストに残り続けます。
現在Vimがバッファしているファイルは`:buffers`というコマンドにて確認することができます。

バッファにはそれぞれに番号が振られており、この番号を指定することでバッファに移動したり操作することが可能です。
バッファの操作コマンドを以下に記載します。

| コマンド | 短縮コマンド | 説明 |
|:-----------|:------------|:------------|
|:buffers||バッファリストのファイル名をリスト表示|
|:buffer    | :b|バッファリストの指定したバッファを開く|
|:bnext     | :bn|バッファリストの次のバッファを開く|
|:bprevious | :bp|バッファリストの前のバッファを開く|
|:ball     | :ba|バッファリストのすべてのバッファをウィンドウを開く|
|:badd     | :bad |バッファリストにバッファを追加|
|:bdelete  | :bd|バッファリストからバッファを削除|
|:bfirst   | :bf |バッファリストの最初のバッファを開く|
|:blast    |:bl |バッファリストの最後のバッファを開く|
|:bmodified| :bm |バッファリストの次の変更済みバッファを開く|

![バッファを移動するGIF動画]()

### ジャンプ

Vimはユーザ操作によりジャンプ(大幅なカーソル移動)した箇所、編集した箇所の履歴を自動で取得しています。
履歴をたどる事でユーザは編集箇所や閲覧箇所により早くたどり着くことが可能です。

#### ジャンプリストでジャンプ

`<C-]>`によるタグジャンプや`n`による検索後の移動など大規模な移動をした履歴は、ジャンプリストに溜まります。
ジャンプリストは`:jumps`で一覧表示することができます。
これは`<C-o>`で戻ったり`<C-i>`で進んだりすることができます。
ホームポジションを崩さずともシュンシュン移動できるのでとても快適です。

| コマンド | 説明 |
|:-----------|:------------|
|:jumps | ジャンプリストを表示|
|`<C-o>`   |前のジャンプ箇所へ移動|
|`<C-i>`   |次のジャンプ箇所へ移動|

![ジャンプリストを移動するGIF動画]()

#### 変更リストでジャンプ

編集する箇所へ移動する際、多くは以前編集した箇所に戻ると思います。
編集しノーマルモードに戻る瞬間、Vimはそのカーソル位置を変更リストに蓄積しています。
変更リストは`:changes`で表示することができます。
これは`g;`で戻ったり`g,`で進んだりすることができます。

| コマンド | 説明 |
|:-----------|:------------|
|:changes | 変更リストを表示|
|g;   |前の変更箇所へ移動|
|g,   |次の変更箇所へ移動|

![変更リストを移動するGIF動画]()