Posted at

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

More than 3 years have passed since last update.

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


FileTypeで処理を分ける

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

echo 'filetype python'

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

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

autocmd BufRead,BufNewFile *.py setfiletype python

autocmd BufRead,BufNewFile *.rb setfiletype ruby

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

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でどうぞ。ちなみに、autocmdはauとも書くことができます。

イベント名の一覧はVim documentation: autocmdで確認することができます。


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

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

autocmd BufRead,BufNewFile * echo 'hello'

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

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

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にまとめておけば一度に俯瞰できるので便利です。

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に戻る

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