まくまくVimノート
autocmd で自動コマンドを登録する
2017-09-04
autocmd(自動コマンド)の機能を使用すると、様々なイベントの発生を監視し、そのタイミングで自動的に任意の処理を実行することができます。例えば、ファイルを開くときに、拡張子の種類に応じた設定を行うといったことが実現できます。

はじめに(autocmd の概要)

autocmd コマンドを使って自動コマンドを登録しておくと、ファイルオープン時、ファイル保存時、フォーカス取得時、カーソル移動時など、様々なタイミングで任意の処理を行えるようになります。 例えば、下記のようなことが行えます。

  • プログラミング言語のソースファイルを開いたときに、その言語に適したインデントモードを設定する
  • 圧縮されたテキストファイルを開いたときに、自動的に解凍してテキストを編集できるようにする(保存するときに再び自動で圧縮する)
  • ノーマルモードに戻った時に、IME(日本語入力モード)をオフにする
  • 日記ファイルを開いたときに自動的に今日の日付を挿入する
  • ファイルの種類によって異なる種類のキーワードハイライト設定を有効にする

下記は具体的な autocmd コマンドの使い方のサンプルです。

例: .txt ファイルを編集するときはタブキー入力をスペースに展開する

:autocmd BufEnter *.txt  setlocal expandtab

autocmd コマンドに関する詳細なドキュメントは、Vim から :help autocmd.txt と入力して参照することができます。 下記サイトでも同じ内容のドキュメントを読むことができます。

autocmd は構文が若干複雑なのでとっつきにくいのですが、使いこなせると非常に便利なので、是非ここで使い方をマスターしましょう。

autocmd で自動コマンドを設定する

:autocmd <イベント> <ファイルパターン> <実行コマンド>

という形式で :autocmd を実行すると、<ファイルパターン> に一致するファイルにおいて、<イベント> が発生したときに、<実行コマンド> が実行されるようになります。

例: .html ファイルを読み込んだときに(この設定ファイルと)同じディレクトリにある html.vim を実行する

:autocmd    BufNewFile,BufRead    *.html    source <sfile>:h/html.vim

上記では、分かりやすくするために、<イベント><ファイルパターン><実行コマンド> をそれぞれ大げさに4文字分のスペースで区切ってあります。

イベント

<イベント> の部分に指定できるイベント名は、下記のヘルプに一覧があります。

イベント名はヘルプファイル上では CamelCase の形式で記載されていますが、実際には大文字と小文字の違いは無視されます。 複数のイベントに対して同じ自動コマンドを登録したいときは、イベント名をカンマで並べて指定することができます。 ただし、この場合、カンマの前後にスペースを入れてはいけません(例: BufNewFile,BufRead)。

ファイルパターン

<ファイルパターン> の部分には、対象とするファイルを下記のような感じで指定します。

*               --- すべてのファイル
*.html          --- 拡張子 .html を持つファイル
*.txt,*.info    --- 拡張子 .txt あるいは .info を持つファイル(カンマの前後にスペースを入れてはいけません)
*/tests/*.java  --- ファイルパスのどこかに tests ディレクトリを含む *.java ファイル
~/.vimrc        --- ホームディレクトリ内の .vimrc ファイル

ディレクトリセパレータは、Windows の場合でもスラッシュ (/) を使用することに注意してください。 バックスラッシュ (\) は特殊な意味を持つため、ディレクトリセパレータとしては使用できません。

ファイルパターンの指定には、*.txt のような指定だけではなく、*/doc/*.txt というワイルドカードの組み合わせも指定できます。 この場合、任意のパスにある doc/ ディレクトリ以下の *.txt ファイルにマッチするようになります。 例えば、あるプロジェクト内のソースコードだけ、特殊なインデントで編集したい場合などに利用できます。

例: mysite ディレクトリ以下の .md ファイルのみタブのスペース数を 2 に設定する

:autocmd BufEnter */mysite/*.md setl expandtab tabstop=2 shiftwidth=2 softtabstop=2 shiftround

アスタリスク (*) は、ディレクトリセパレータを含む任意のパスにマッチするので、上記の指定は、/Users/maku/mysite/aaa/bbb/ccc.md といった深い階層にあるファイルにもマッチします。

<イベント>FileType を指定した場合(ファイルタイプの変更イベントを監視)は、ファイル名のパターンの代わりに c,cppjava のようなファイルタイプ名を指定することができます。

例: C/C++ と Java のソースコードのインデント方法を設定する

:autocmd FileType c,cpp,java setl cindent expandtab tabstop=4 shiftwidth=4 softtabstop=4 shiftround

現在登録されている autocmd の一覧を表示する

autocmd コマンドをパラメータなしで実行すると、現在登録されている自動コマンド (autocommands) の一覧を表示することができます。

:autocmd

イベント名を指定すると、そのイベント用に登録されている自動コマンドのみを列挙することができます。

FileType イベント用に登録されている autocmd を列挙する

:autocmd FileType

.vimrc で autocmd 設定するときは前回の設定をクリアするイディオムを使用する

autocmd は実行するたびに自動コマンドを追加していきます。 つまり、.vimrcautocmd の定義が書かれている場合に、その .vimrc を何度も source で読み込んでいると、同じ自動コマンドが重複して登録されていきます。 このような自動コマンドの重複登録を避けるには、autocmd による自動コマンドの登録前に、前回登録した自動コマンドをクリアするようにします。 Vim のヘルプ (:help autocmd.txt) には、下記のようにグループ単位で自動コマンドの登録をクリアする方法が示されています。

~/.vimrc

augroup vimrc
  autocmd!      " Remove all vimrc autocommands
  au BufNewFile,BufRead *.html so <sfile>:h/html.vim
augroup END

この例のように、augroup vimrcaugroud END のブロック内に処理を記述すると、autocmd! による自動コマンドのクリアや、autocmd による自動コマンドの登録が vimrc という自動コマンドグループに対して作用するようになります。 vimrc というグループ名の部分は、任意の名前を付けることができますが、endEND はグループブロックの終了を表すキーワードとして使用されるため、グループ名としては使用できません。 より明確に言うと、augroup END という宣言は、それ以降の autocmd 対象グループをデフォルトグループに変更するという意味を持っています。

結果として、上記の例のように記述しておくと、最初にすべての自動コマンドをクリアし、改めて autocmd で自動コマンドを登録し直していくという動作になります。 これにより、.vimrc ファイルをリロード (:source ~/.vimrc) したときに、自動コマンドが重複登録されるのを防ぐことができます。

ちなみに、自動コマンドの登録を上記のようにグルーピングしておくことで、登録されている自動コマンドの一覧をそのグループに絞って確認することができるようになります。

例: vimrc グループに登録された自動コマンドの一覧を表示する

:autocmd vimrc

いろいろな autocmd の例

" C++ のソースコードの編集するときは、タブキーをスペースを用いたインデント用に使用する
:autocmd FileType cpp  setlocal expandtab

" Makefile を編集するときは、タブキーをタブ文字の入力に使用する
:autocmd FileType make  setlocal noexpandtab

" ~/.vimrc を保存したときにリロードする(source コマンドで変更を反映する)
:autocmd BufWritePost  ~/.vimrc  so ~/.vimrc

" 拡張子 .cpp のファイルを開いたバッファに入るとき、~/.vimrc_cpp を実行する
:autocmd BufEnter  *.cpp  so ~/.vimrc_cpp

" C 言語のソースコードを編集し始めるときに、カーソルを最初の関数に合わせる
:autocmd BufRead  *.c,*.h  1;/^{

" 新規に .java ファイルを作成する場合にテンプレートファイルを使用する(:e new.java や :tabnew new.java としたとき)
:autocmd BufNewFile  *.java  0r ~/vim/skeleton.java

" 新規に .hello ファイルを作成する場合に Hello というテキストを挿入する
:autocmd BufNewFile  *.hello  put='Hello'
2017-09-04