vim入門記事では見かけないマイナーかもしれない機能

一般的なVIM入門記事などではあまり見かけない標準機能など、
その中でも人によっては便利かもしれないややマイナーな機能を紹介します。

# インサートモード

## `<C-@>` または `<C-a>`

直前のインサートモードで入力した文字を再入力できる。

`a`と`@`では入力後の挙動が異なる

* `<C-@>`: そのままインサートモードを抜ける
* `<C-a>`: インサートモードのまま入力を続ける

例えばノーマルモードで`5a<C-@>`と入力すれば...

```
例えば例えば例えば例えば例えば
```

直前に入力した文字(`例えば`)が5回入力される。

ちなみに動きとしては`<C-a>`は`<C-r>.`でも代用できる。

## `<C-r><c-o>`または`<C-r><C-p>`

`<C-r>`や`<C-r><C-r>`とは異なり、`.`キーによる繰り返し処理ではキー入力のまま再現される。

例えば

1. `abc`をヤンクする
2. インサートモードにて`<C-r><C-o>"`で貼り付ける。`abc`が出力される。
3. `def`をヤンクする
4. `.`キーによるリピートを行う。`def`が出力される。

もし2で`<C-r>"`を利用した場合、4の処理では`abc`が出力されるだけ。

これは内部的な実装が異なるためで(バグ？)、レジスタ`.`の内容を確認してもその違いが確認できる。
つまり上記手順の実施後

* `<C-r><C-o>"`の場合：レジスタ`.`には`^R^O"`が格納されている
* `<C-r>"`の場合：レジスタ`.`には`abc`が格納されている

`<C-r><C-o>"`の場合は、キー入力したそのままが格納されていることがポイント。

* ちなみに`<C-r><C-p>`でも同様に機能する。違いはインデントの扱い。
* ちなみに`<C-r><C-o>.`はやらない方が良い。ちょっとした無限ループにはまる。


詳しい解説
[In vim, what is the difference between <c-r>+register and <c-r><c-p>+register with the . command?](http://stackoverflow.com/questions/20617329/in-vim-what-is-the-difference-between-c-rregister-and-c-rc-pregister-wi)


## インデント

基本として

* `<C-i>`: カーソル位置にインデントを1つ追加
* `<C-t>`: 行頭にインデントを1つ追加
* `<C-d>`: 行頭のインデントを1つ削除

応用として`^<C-d>`を入力するとその行でのみ行頭のインデントをすべて削除し、
次の行から元のインデントが復元されるのでインデントのないラベルの入力などに便利らしい。

## スクロール

ノーマルモードの`<C-e>`および`<C-y>`に相当するスクロールは、
`<C-o>`を利用して`<C-o><C-e>`および`<C-o><C-y>`で利用可能。

* `<C-o>`: 一度だけノーマルモードのコマンド入力可能なコマンド

そして`<C-x>`によりサブモードを利用すれば、
`<C-x><C-e>`および`<C-x><C-y>`でもスクロール可能。
連続でスクロールする場合にはこちらの方が便利。`<C-x><C-e><C-e>..`。

ただインサートモード中にスクロールする場面はあまり無い。

### ついでに補足：`<C-o>`と`<C-g>`の違い

上記で利用した`<C-o>`とよく似た`<C-g>`が存在するが、
両者はカーソル位置の扱いが異なる。

実例の方がわかりやすいので、
例えば以下の文字列でカーソルが`1`にあるとして...

```
123
456
789
```

* `R0<C-o>j0<C-o>j0<ESC>` の場合

```
023
406
780
```

* `R0<C-g>j0<C-g>j0<ESC>` の場合

```
023
056
089
```

## アンドゥの分割

入力途中で`<C-g>u`を押すとアンドゥの単位がその時点で分割される。

要するに一度ノーマルモードに戻ったことと同じなので、
長い文章を入力している時はキリの良いタイミングで押しておくと良い事があるかも。

## スペース込みの補完

例えば `hello world !` という文字が入力されていれば、
`h`を押してから`<C-n>`で勝手に`hello`と補完される。

この状態で`<C-x><C-n>`と押せば、`hello world`まで補完され、
再度`<C-x><C-n>`で`hello world !`までスペース込みで補完できる。

### 補足：`<C-x><C-l>`

もしソースが行なら`<C-x><C-l>`の方が早い。

つまり1行に`hello world !`という文字だけが書いてある状態ならば、
`h`の後`<C-x><C-l>`と打てば一気に`hello world !`まで補完される。


# ノーマルモード

## 数値指定

`5w`や`3j`などのようにコマンドの前の数値がある場合そのコマンドをn回繰り返す...とは限らない。

例えば

* `3$`は`$`を3回押すことと等価でなく、カーソル行含め3行下の末尾へ移動。
* `3Y`は`Y`を3回押すことと等価でなく、カーソル行含め3行分をコピー。

なので厳密には個別に覚える必要があるが、
なんとなく直感的にわかるようになっているはず。

## normalコマンド
特定のノーマルコマンドを実行できる。

例えば行頭に`- `を挿入する場合は`:%s/^/- /`でも良いが`:%normal gI- `でも可能。
この場合`normal`コマンドであれば`.`キーで繰り返し適用することができる。

## 括弧間の移動

対応する括弧は`%`で移動できるが、
入れ子の括弧の場合の移動は`[(`,`])`や`[{`,`]}`を利用する。

例えば`#`にカーソルがある状態で`[(`を2回押せばfirstで始まる括弧に移動できる。

```
first(second(th#rd))
```

ただデフォルトの設定だととても押しにくい。

# フォーマット

## 強制適用

`gq{motion}`で強制的にフォーマットが可能。`gqq`なら現在行が対象。

基本的には`formatoptions`で自動的なフォーマットを利用しているので不要だが、
`textwidth`を変更し、その値を既存部分に適用したい場合などには便利。

## 位置揃え

* `:center [width]`: 中央揃え
* `:right [width]`: 右揃え
* `:left [indent]`: 左揃え

例えばこの状態で

```
insert mode
nomal mode
command mode
```

対象を選択してから`:right 15`を実行すると…

```
    insert mode
     nomal mode
   command mode
```

## `<`による左揃え

上記の通り左揃えは`:left`でも可能だが、
範囲選択した後`<`を利用したほうが視覚的に確認してから左揃え可能なので便利かも。

![leftalign.gif](https://qiita-image-store.s3.amazonaws.com/0/14471/799fb916-f6ab-f4f3-6cdb-2623d81f6bb7.gif)

# 検索

## 件数確認

`n`オプションを付けると実際に置換せず件数だけを表示してくれる。

例えば`:%s/hoge//gn`とすればファイル内の`hoge`の数が分かる。

## 検索メタ文字

### 大文字のメタ文字

特定の文字に一致するメタ文字(`\s`,`\d`,`\w`など)は、
大文字にすると否定の意味に変わる。

例えば…

* `\S`: `\s`の否定なので、スペース以外
* `\D`: `\d`の否定なので、は数値以外
* `\L`: `\l`の否定なので、小文字以外

ちなみに`\L`は小文字以外で大文字ではない。大文字は`\u`。

### メタ文字に行末を含める

行末を含めるにはメタ文字に`_`を加えれば良い。

例えばスペースと行末は`\_s`で表されるので`%s/\_s//`コマンドによる置換をすると…

* 置換前

```
a b c
d e f
```

* 置換後

```
abcdef
```

## `g*`と`g#`

`*`,`#`は完全一致だが、代わりに`g*`,`g#`を利用すると部分一致で検索できる。


## 置換用ショートカット

* `&`: 直前の置換を繰り返す。ただしフラグを保持しないので注意。(`:&&`ならフラグ有効）
* `g&`: `%s//~/&`と等価。直前のフラグで直前の検索ワードを直前の置換文字に置き換える

一行置換して確認後、`g&`で全体に適用するのがクール。

## `:c`による置換

確実に現在行のみ変更したい場合などに利用できるかも。

# コマンドモード

## レジスタをコマンドとして実行

* `:@{0-9a-z".=*+}`: レジスタ`{0-9a-z".=*+}`をコマンドとして実行

例えば`echo "hello"`という文字をヤンクして`:@"`とすれば挨拶を返してくれる。

## コマンドの結合

`:s/a/A/`と`:s/b/B/`は、`:s/a/A/|s/b/B/`とまとめて書ける。

`|`で連結すると、`@:`でも一括実行可能。
つまり任意のコマンドをグループ化できる。

例えば何もない行で`:y|pu=@0+1<CR>99@:`を実行すれば1から100の連番が作成できる。


### 同時検索

`|`でOR検索ができる。

* `/hoge\|piyo`: `hoge`と`piyo`の2つを同時に検索する

検索カテゴリで紹介すべきだが`|`によるコマンド結合と形が似ているのでここで紹介。

### 検索オプション

ちなみ`;`は検索オプションにオフセットを与えるフラグ。

* `/hoge/;/piyo`: `hoge`の後の`piyo`を検索する

`|`によるコマンドの結合に形が似ているから勢いで紹介。


`|`が出たついでにさらに勢いで紹介すると、
ノーマルモードで`|`を利用すると特定のカラムにジャンプできる。

* `20|`: で20カラム目に移動する

# ビジュアルモード

## ノーマルモードとの動きの違い

同じカーソル移動でもノーマルモードとは最終的なカーソル位置が異なる場合がある。

例えばこのようなテキストがある行で…
(`#`はカーソル位置とする)

```
#ogehoge
```

* ノーマルモードで`$Fe`を実行

```
hog#hoge
```

* ビジュアルモードで`$Fe`を実行

```
hogehog#
```

ビジュアルモードでは行末を超えて1つカーソルを進められ、
ノーマルモードと同じ動きをするわけではないために起こる。

## 選択範囲内での移動と切替

* 範囲選択中に`o`: 範囲内の対角線でカーソル移動
* 範囲選択中に`O`: 範囲内の同一行でカーソル移動
* 選択範囲中に`gv`: 最後に選択した範囲と切り替える

`gv`を押すたびに交互に範囲が切り替わる。

![changeselection.gif](https://qiita-image-store.s3.amazonaws.com/0/14471/b29e6f61-bdc6-9263-aae3-403503987ca5.gif)

ちなみにノーマルモードで`gv`を押せば、
最後に選択した範囲が選択された状態でビジュアルモードになる。


## ビジュアルモードでの`<C-a>`

選択範囲内の数値を1増加させる。
連番を作成したい場合には`g<C-a>`が便利。

例えばこの状態で2行目以降を選択して`g<C-a>`を押すと…

```
1
1
1
1
```

連番が作成される。(ちなみにこれはヘルプのサンプルそのまま)

```
1
2
3
4
```


比較的最近実装された機能なのでバージョンによっては動かない。

# マクロ

## @コマンド

`qa`でレジスタ`a`に保管されたマクロは`@a`で実行可能なように、
基本的にはあらゆるレジスタが実行可能。

ただし以下は例外

* レジスタ`:`に限っては直前のコマンドラインを実行する
* レジスタ`%`と`#`は実行できない

### レジスタ`.`の場合

まったく役に立たない例だが、
`ble`と入力後、カーソルキーの左を2回押してから`at`と入力するば`batle`という文字になるが、
この状態でノーマルモードに戻り`@.`を実行すると`battle`という単語ができあがる。

これはvimの [カーソルキーの左、以降しかドットレジスタに記録されない](https://github.com/vim-jp/issues/issues/661) という仕様も利用している。

### レジスタ`=`の場合

その場でマクロ記録と実行が同時に行えるため、
`5@="atest<C-q><ESC>"`とすれば`test`が5回入力される。

あまり使い道はない。

### レジスタ`"`の場合

以下を文字列ヤンクして`@"`とすれば`abc`は`ccc`に置換される。
つまり複数の置換コマンドを記述してからまとめて適用できる。

```
:s/a/b/g
:s/b/c/g
```

#### 補足

上記のように改行を含む場合は環境によってはうまく動かないかもだが、
代わりに`:@"`によりコマンドモードで実行すればうまくいくと思われる。

## 再帰呼び出し

レジスタは再帰的に呼び出すことができる。

例えばレジスタ`q`に`yyp\<c-a>@q`を登録して、数字の上で実行`@q`すると永遠に連番を作成し続ける。
`<C-c>`で止められるはず。

## コマンドの動的編集

`q:`でコマンドウィンドウを開けるが、マクロ実行中は`q`でマクロ記録が止まるため利用できない。
代わりにコマンドラインにて`<C-f>`でもコマンドウィンドウを呼び出せるので、
これを利用するとコマンドの内容を動的に変更できる。

意味のない例だが`:match Error /\%1c/`を実行した後`qq:<C-f>k<C-a><CR>q`でマクロ記録すれば、
`@q`で実行するたびにハイライトするカラム位置が増加していくマクロができあがる。

![movecursor.gif](https://qiita-image-store.s3.amazonaws.com/0/14471/d994c537-44de-c08d-c0c6-326c948e9ffb.gif)

# 変更履歴

## チェンジリスト

変更箇所を順にたどれる

* `g;`: チェンジリストを1つ戻る
* `g,`: チェンジリストを1つ進む

チェンジリストとは直接関係ないが類似の`gi`は良く使う。

* `gi`: 前回のインサートモードに入った位置から修正を再開

## 前回保存状態へアンドゥ

* `:earlier {N}f`: `{N}`回前のファイル保存した状態へ
* `:later {N}f`: `{N}`回後のファイル保存した状態へ

このコマンドでは時間指定も可能だが、
たいてい戻りたいタイミングはファイル保存のタイミングなのでこれで十分。

前回の保存状態に戻したい場合には`:earlier 1f`とすれば、
`u`や`g-`などで1つずつ確認しながら戻る必要がないので意外と便利。


# その他

## 暗号化

`:X`コマンドでファイルを暗号化することができる。

`:X`でパスフレーズを設定すれば通常通りファイル保存するだけで暗号化される。
次回vimで開く際にパスフレーズを求められるので、
正しいパスフレーズを入力すればファイル内容が復号化される。

## 情報表示

* `<C-g>`: ファイル名やカーソル位置などの情報が表示
* `g<C-g>`： ファイル内容に関する情報(カラム位置、行数、単語数、文字数、バイト数)が表示

```
Col 16-12 of 24-17; Line 33 of 50; Word 30 of 67; Char 403 of 599; Byte 843 of 1153
```


## その他

* `set so=999`で常にカーソルをファイルの中央に配置(常に`zz`を押している感じ)
* `:TOhtml`: THMLファイルで出力
* `3gs`: 3秒間スリープ(`<C-c>`でキャンセル)
* `g??`: 現在行を対象にROT13エンコード