ファイルの拡張子によって、vimに自動でインデント幅を変えてもらおう！


pythonとrubyだと、コーディングルールのインデント幅が違います。これを毎回設定するのはわずらわしいので、vimに自動で切り替えてもらいましょう。拡張子で処理を切り分けることができます。

### FileTypeで処理を分ける

vimにはFileTypeというオプションが定義されています。もしFileTypeがpythonの時に実行したい設定がある場合は、`~/.vim/ftplugin/python.vim`を作成します。次の設定だと、ファイルを開いた時に"filetype python"という文字列が画面の下に出力されます。

```vim
echo 'filetype python'
```

上記のファイルを自動実行させるために、開いたファイルの拡張子によって自分でファイルタイプを定義する必要があります。拡張子がpyの時はpython、rbのときはrubyというFileTypeを定義することにしましょう。`setfiletype`で設定するファイルタイプ名は大文字小文字は区別されません。pythonでもPyThoNでも同じです。

このFileTypeを定義する処理は`~/.vimrc`に書いて大丈夫です。実行さえされればいいので。

```vim
autocmd BufRead,BufNewFile *.py setfiletype python
autocmd BufRead,BufNewFile *.rb setfiletype ruby
```

これで拡張子がpyの時は`~/.vim/ftplugin/python`が、rbの時は`~/.vim/ftplugin/ruby`が実行されます。今回は自分でFileTypeを設定しているので好きな文字列を定義することができます。

```vim
autocmd BufRead,BufNewFile *.py setfiletype FoO
```

この場合は拡張子がpyの時に`~/.vim/ftplugin/foo`が実行されます。ftplugin以下のファイル名ですが、_（アンダーバー）以降は無視されます。例えば、FileTypeがpythonときは次のどの名前のものでも実行されます。複数の対象ファイルが同時に存在する時は、私の場合は1つしか実行されませんでした。

* python.vim
* python_150704.vim
* python_main.vim

また、FileTypeはファイル名の接頭辞で判断されるだけでなくディレクトリ名も判断します。`~/.vim/ftplugin/python_main.vim`というのは、`~/.vim/ftplugin/python/main.vim`でも同じ動作をします。

### autocmdとは？

autocmdについてですが、これはvimの特定のイベント時に処理を実行させるコマンドです。使い方は次の通りです。

`autocmd イベント名 ファイル名 実行コマンド`

今回はBufReadとBufNewFileという新規ファイルと既存ファイル読み込み時に起きる2つのイベントを指定しています。これらのイベントが起きてなおかつ拡張子がpyの時に、ファイルタイプを決定するようにしているのです。詳細は[Vim documentation: autocmd](http://vim-jp.org/vimdoc-ja/autocmd.html)でどうぞ。ちなみに、**autocmdはauとも書くことができます。**

イベント名の一覧は[Vim documentation: autocmd](http://vim-jp.org/vimdoc-ja/autocmd.html#autocmd-events)で確認することができます。

### augroupと自動コマンドの重複設定

vimを起動中に`:source ~/.vimrc`を実行すると`.vimrc`をvimを終了せずに再読み込みすることができます。もし`.vimrc`に次の処理が書かれていて再読み込みをします、その後に新しいファイルを開くと、読み込んだ回数分だけhelloと表示されるようになってしまいます。vimを終了した場合は元に戻ります。

```vim
autocmd BufRead,BufNewFile * echo 'hello'
```

この時は`autocmd`の後ろに!（エクステンションマーク）をつけます。これで設定された自動コマンドを削除するので、1回しかコマンドが設定されないことになります。

複数のautocmdは複数のグループに分けて整理することができます。グループに分けることによって、自動コマンドの起動や削除をグループ単位で指定することができます。グループ化には`augroup`を使います。次は2つの`autocmd`をMyGroupというグループに登録しています。

```vim
augroup MyGroup
    autocmd!
    autocmd BufRead,BufNewFile *.py setfiletype python
    autocmd BufRead,BufNewFile *.rb setfiletype ruby
augroup END
```

一番最初の`autocmd!`はMyGroupの自動コマンドを削除するという意味です。これがないと同じコマンドが重複されて設定されてしまいます。

### vimのインデントオプション

vimの設定の仕方がわかったところで、本題に入りましょう。vimには次のようなインデントを設定するオプションがあります。これを使って自動コマンドを設定するだけです。

オプション名      | 補足                          
----------- | ----------------------------
expandtab   | tabキーを押すとスペースが入力される         
tabstop     | 画面上で表示する1つのタブの幅             
softtabstop | いくつの連続した空白を1回で削除できるようにするか   
shiftwidth  | 自動インデントでのインデントの長さ           
autoindent  | 改行した時に自動でインデントします           
smartindent | {があると次の行は自動で1段深く自動インデントしてくれる

smartindentはC言語を知っている人には、ブロックごとのインデントといえばわかりやすいでしょうか。

tabstopは、タブ文字（\t）の表示する際の幅です。1つのタブ文字を何文字分で表示するかという見栄えの変更のみです。すごい長くしても実際のデータとしてはタブは1文字分しか記録されていません。これはexpandtabを有効にしている人にはタブがスペースで展開されているので、見た目に変化はありません。意図的にタブ文字を入力した場合は別ですが。

タブ文字にしておくと、tabstopでいつでも自由に見た目の幅を変更することはできますが、スペースの場合は常に固定ということになります。

私はFileTypeごとに`.vim`ファイルを作るのをやめて、`.vimrc`にすべて記述することにしました。今は拡張子ごとにインデントを変えたいだけなので、設定が多くなってきたらファイルを分けたいと思います。それと`.vimrc`にまとめておけば一度に俯瞰できるので便利です。

```vim
set tabstop=4
set shiftwidth=4
set softtabstop=4
set expandtab
set autoindent
set smartindent

augroup fileTypeIndent
    autocmd!
    autocmd BufNewFile,BufRead *.py setlocal tabstop=4 softtabstop=4 shiftwidth=4
    autocmd BufNewFile,BufRead *.rb setlocal tabstop=2 softtabstop=2 shiftwidth=2
augroup END
```

これで拡張子pyとrbによってタブ幅が自動で変わるにようになりました。それ以外のファイルではデフォルトの4になります。これはグループの外で常に設定しているからです。その上から条件にあったらautocmdで上書きしているわけです。

`set`ではなく`setlocal`を使っている理由は、未設定の拡張子のファイルを開いた場合に自動で開くようにするためです。localというは今開いているファイル（バッファ）のみということです。もし、localにしない場合は次のようになります。

1.  foo.rbを開く
2.  タブ幅は4になる
3.  タブ幅は2に上書きされる
4.  bar.txtを開く
5.  タブ幅は2のまま

localにした場合は次の通りです。

1.  foo.rbを開く
2.  タブ幅は4になる
3.  タブ幅は2に上書きされる（現在のバッファのみ）
4.  bar.txtを開く
5.  2の設定が解除される
6.  タブ幅はデフォルトの4に戻る

これで複数の言語をスムーズに記述できるようになりました。