coc.nvim + efm-langserver でerbファイルの文法チェックをおこなう

# Vimで.erbファイルを書きたい

Rails7のHotwireを試したくて、（nvimで）何年かぶりにeRubyを書いてみてるのだけど、eRuby向けのLanguage Serverが見当たらなくて泣きそうになった。
せめて文法エラーのチェックくらいはできたら・・・[^1]
[^1]: Ruby自体のLanguage Serverは[solargraph](https://solargraph.org/)というのがあり、だましだましだが[Railsもサポートされている](https://solargraph.org/guides/rails)

そこで、どんなコマンドでもLanguage Serverにしてしまえる `efm-langserver` を使ってみることにした。

https://github.com/mattn/efm-langserver

efm-langserverのREADMEには、

```yaml
lint-command: 'erb -x -T - | ruby -c'
```

と[書いてある](https://github.com/mattn/efm-langserver/tree/78b0d94d80059462cdecc3012e9812925487ad3d#example-for-configyaml)が、これだと以下のようなブロックを含むeRubyのコードを扱えない。

```eruby
<%= simple_form_for(quote, html: { class: "quote form" }) do |f| %>
  <%= f.input :name, input_html: { autofocus: true } %>
  <%= f.submit class: "btn btn--secondary" %>
<% end %>
```

ブロックがあると常に SyntaxError になってしまう。

```shell-session
$ (erb -x -T - | ruby -c) <<'EOF'
> <%= simple_form_for(quote, html: { class: "quote form" }) do |f| %>
  <%= f.input :name, input_html: { autofocus: true } %>
  <%= f.submit class: "btn btn--secondary" %>
<% end %>
> EOF
-:2: syntax error, unexpected ')'
...class: "quote form" }) do |f| ).to_s); _erbout.<< "\n".freeze
-:5: syntax error, unexpected `end', expecting ')'
;  end ; _erbout.<< "\n".freeze
-:6: syntax error, unexpected end-of-input, expecting ')'
; _erbout
```

これはRubyの標準ライブラリの[ERB](https://docs.ruby-lang.org/ja/latest/class/ERB.html)がブロックを含むeRubyをハンドリングしないのが原因。
Railsで使われているeRubyライブラリの[erubi](https://github.com/jeremyevans/erubi)も同様だった。

かわりに使えるものを探してみると、`baby_erubis`というのを見つけた。

https://github.com/kwatch/baby_erubis

もう長らくメンテされていないが、

> (Experimental) Block argument expression supported

と[書いてある](https://github.com/kwatch/baby_erubis#template-syntax)。

こんな感じで試してみると、ブロックの含まれるeRubyタグのハンドリングが期待通りにできた。

```sh
gem install baby_erubis
cat ./app/views/quotes/index.html.erb | ruby -r baby_erubis -e 'puts BabyErubis::Html.new.from_str(STDIN.read).src'
```

そこで、`erb -x -T - | ruby -c` のかわりにためしに使ってみることにした。


# セットアップ

[coc.nvim](https://github.com/neoclide/coc.nvim) は導入済みの前提。

efm-langserver と baby_erubis をいれる。

```sh
brew install efm-langserver
gem install baby_erubis
```



ファイルタイプが`eruby`のときに`efm-langserver`を呼び出すようにする。
（ちなみに、FileTypeが`eruby`のときには`coc-html`も使われるようになっている）

```json:.config/nvim/coc-settings.json
{
  "html.filetypes": ["html", "eruby"],
  "html.format.templating": true,
  "languageserver": {
    "efm": {
      "command": "efm-langserver",
      "args": [],
      "filetypes": ["eruby"]
    }
  }
}
```


以下のRubyスクリプトをパスの通った場所に置いて実行権限をつける。
これが `erb -x -T - | ruby -c` のかわりになる。

```ruby:erbcheck
#!/usr/bin/env ruby

# https://github.com/kwatch/baby_erubis
require "baby_erubis"

begin
  BabyErubis::Html.new.from_str(STDIN.read, '-').src
  puts "Syntax OK"
rescue SyntaxError => se
  STDERR.puts se.message
  exit 1
end
```

`.config/efm-langserver/config.yaml` を作成して、以下の内容にする。
（efm-langserver のREADMEに書いてあるものとほぼ一緒）

```json:.config/efm-langserver/config.yaml
version: 2
tools:
  eruby-erb: &eruby-erb
    lint-debounce: 2s
    lint-command: 'erbcheck'
    lint-stdin: true
    lint-offset: 0
    format-stdin: true
    format-command: htmlbeautifier

languages:
  eruby:
    - <<: *eruby-erb
```

あとはvimでてきとうな`.erb`ファイルを開くと、文法チェックをおこなってくれるようになる。

![スクリーンショット 2022-08-18 4.55.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26038/d88a6764-4fc2-d447-4a20-dab4a8e758f5.png)
![スクリーンショット 2022-08-18 4.55.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26038/f953115b-89bf-e342-3d5f-36aced3ae543.png)

これにて一件落着。


# 今後の課題

文法チェックはできるようになったけど、欲を言えばeRubyのRuby部分の自動補完とかもやってほしいので、solargraphと組み合わせてどうにかできないか試してみたい。