初めてVimプラグインを自作してみた

最近初めてVimプラグインを自作したので、備忘録も兼ねて作り方をまとめておきます。同じようにこれからVimプラグインを作ってみようと思っている人の参考になれば幸いです。

今回はfluentd用にシンタックスハイライトするプラグインを作りました。シンタックスプラグインは簡単なわりに手順がまとまっている記事が少なそうだったので、取り上げるにはちょうど良いかもしれません。シンタックス系でない一般的なVimプラグインの作成については他の記事を参考にしてください。

実際に作ったものはこちらになります。
https://github.com/yuzoiwasaki/fluentd.vim

作ろうと思った理由は一度Vimプラグインを自作してみたかったのと、fluentd用のシンタックスプラグインでスタンダードなものがなさそうだった + 自分のプロジェクトにインストールしてみたがうまくハイライトされなかったからになります。

## syntaxディレクトリ

シンタックスプラグインを作るときは、syntaxディレクトリ配下に `<filetype>.vim` の形式でシンタックスファイルを配置します。

```vim:syntax/fluentd.vim

" Vim syntax file
" Language: Fluentd configuration
" Maintainer: Yuzo Iwasaki <yuzoiwasaki0929@gmail.com>
" Last Change: Apr 7, 2020

if exists("b:current_syntax")
  finish
endif

syn match FluentdComment /#.*/

syn match FluentdDirective "<\/*\(source\|parse\|label\|match\|buffer\|format\)[^>]*>"
syn match FluentdDirective /@include/

syn match CommonPluginParameter /\(@type\|@label\)/
syn keyword CommonPluginParameter pos_file path tag expression
syn keyword CommonPluginParameter format format_firstline format1
syn keyword CommonPluginParameter s3_bucket s3_region s3_object_key_format store_as
syn keyword CommonPluginParameter timekey timekey_wait include_time_key

hi link FluentdComment Comment
hi link FluentdDirective Define
hi link CommonPluginParameter String

let b:current_syntax = "fluentd"
```

以下、一つ一つ説明していきます。

冒頭のコメントはお作法のようです。LanguageやMaintainerを記載します。なくても良さそうですが、記載しているプラグインが多かったのでそれに倣いました。

```vim
" Vim syntax file
" Language: Fluentd configuration
" Maintainer: Yuzo Iwasaki <yuzoiwasaki0929@gmail.com>
" Last Change: Apr 7, 2020
```

こちらもお作法で、同じタイプのファイルを開いた時に重複して読み込まれないようにしています。

```vim
if exists("b:current_syntax")
  finish
endif
...

let b:current_syntax = "fluentd"
```

以下の部分がシンタックスプラグインの本体になります。ざっくり言うとsyntaxコマンドで構文グループを定義し、highlightコマンドで定義した構文グループに色をつけています。

syntaxコマンドはmatchを引数に取ることで正規表現を使用することも可能です。また、同じ構文グループに対して何回も要素を定義することができます。詳しい構文はこちらのドキュメントを参考にしてください。
https://vim-jp.org/vimdoc-ja/syntax.html

```vim
syn match FluentdComment /#.*/

syn match FluentdDirective "<\/*\(source\|parse\|label\|match\|buffer\|format\)[^>]*>"
syn match FluentdDirective /@include/

syn match CommonPluginParameter /\(@type\|@label\)/
syn keyword CommonPluginParameter pos_file path tag expression
syn keyword CommonPluginParameter format format_firstline format1
syn keyword CommonPluginParameter s3_bucket s3_region s3_object_key_format store_as
syn keyword CommonPluginParameter timekey timekey_wait include_time_key

hi link FluentdComment Comment
hi link FluentdDirective Define
hi link CommonPluginParameter String
```

実際に表示される色はカラースキーマによりますが、今回作成したものだとこんな感じになります。
![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105253/3a4e5007-c22c-9063-20cf-751ac3b6f501.png)


## ftdetectディレクトリ

基本的にはsyntaxディレクトリだけで事足りるのですが、指定したファイルタイプを自動的に認識させたい場合、ftdetectディレクトリ以下にもファイルを配置すると便利です。最初私が他のプラグインを試した時にうまく動かなかったのは、ファイルタイプが認識されていなかったからでした:sweat:

```vim:ftdetect/fluentd.vim
autocmd BufRead,BufNewFile fluentd*.conf set ft=fluentd
autocmd BufRead,BufNewFile *fluentd.conf set ft=fluentd
autocmd BufRead,BufNewFile */fluentd/*.conf set ft=fluentd
autocmd BufRead,BufNewFile */fluentd/*.conf.template set ft=fluentd
```

## 最後に

以上、簡単ではありますがVimのシンタックスプラグインの作り方でした。今回私が作ったものは本当に最低限の内容なので、設定値に対してもハイライトする、より具体的な命名でグループ化するなど更なるリファクタリングはできると思います。

極力車輪の再発明はするべきではないと思いつつも、自分のリポジトリが `.vimrc` にあるのは嬉しいものです。みなさんも一度オレオレシンタックスプラグインを作ってみてはいかがでしょうか？