vimでmarkdownのクォート内をシンタックスハイライトする方法とプラグイン

以下の記事に触発されて、vimでmarkdownのクォートの中を上手くシンタックスハイライトさせる方法は無いか調べてみました。

- [RubyMineのシンタックスハイライトがすごかった件について - くりにっき](http://sue445.hatenablog.com/entry/2013/05/25/223623 "RubyMineのシンタックスハイライトがすごかった件について - くりにっき")
- [Vim でコンテキストによって filetype を自動的に切り換えるプラグインをつくっている - C++でゲームプログラミング](http://d.hatena.ne.jp/osyo-manga/20130612/1371046408 "Vim でコンテキストによって filetype を自動的に切り換えるプラグインをつくっている - C++でゲームプログラミング")

vim-preciousでも良さそうなのですが、最初からハイライトされてる方が自分好みだったので。
Vim Advent Calendarとして書けば良かったかもしれない。

## 別言語のシンタックス設定を読み込む

```vim
function! MarkdownQuoteSyntaxGroup(filetype)
  let ft = toupper(a:filetype)
  return 'markdownCodeGroup'.ft
endfunction

function! IncludeOtherSyntax(filetype)
  let group = MarkdownQuoteSyntaxGroup(a:filetype)

  " syntax save
  if exists('b:current_syntax')
    let s:current_syntax = b:current_syntax
    unlet b:current_syntax
  endif

  execute 'syntax include @'.group.' syntax/'.a:filetype.'.vim'

  " syntax restore
  if exists('s:current_syntax')
    let b:current_syntax=s:current_syntax
  else
    unlet b:current_syntax
  endif

  return group
endfunction
```

`syntax include @groupName syntax/javascript.vim`で他のシンタックスファイルを読み込み名前付ける事ができる。
ただし、シンタックスファイルは`b:current_syntax`が存在すると読み込みをストップするようになってます。
なので、一時的に`b:current_syntax`を無効化してからシンタックスを読み込みます。

## シンタックス設定を利用するパターンを指定する

```vim
function! MarkdownQuoteSyntaxRegion(filetype)
  let ft = toupper(a:filetype)
  return 'markdownCodeRegion'.ft
endfunction

function! EnableMarkdownQuoteSyntax(filetype, start)
  let group = MarkdownQuoteSyntaxGroup(a:filetype)
  let region = MarkdownQuoteSyntaxRegion(a:filetype)

  let regexp_start = "^\\s*```".a:start."$"
  let regexp_end = "^\\s*```\\ze\\s*$"

  execute 'syntax region '.region.'
  \ matchgroup=markdownCodeDelimiter
  \ start="'.regexp_start.'" end="'.regexp_end.'"
  \ keepend contains=@'.group
endfunction
```

`syntax region`を使うと指定のパターンに囲まれた部分に対してシンタックス設定を適用できる。
それと合わせて`contains`オプションを指定する事でregionの内側で使うシンタックス設定を設定できる。
さっき読み込んで名前を付けたシンタックス設定をcontainsに指定する事で、特定の領域内だけ他言語のシンタックスハイライトを適用できる。

```vim
call IncludeOtherSyntax("javascript")
call EnableMarkdownQuoteSyntax("javascript", "\\%(javascript\\|js\\)")
```

で、せっかくなのでプラギンにしてみました。

[joker1007/vim-markdown-quote-syntax](https://github.com/joker1007/vim-markdown-quote-syntax "joker1007/vim-markdown-quote-syntax")
![screenshot.png](https://github.com/joker1007/vim-markdown-quote-syntax/raw/master/screenshot.png)

[joker1007/vim-ruby-heredoc-syntax](https://github.com/joker1007/vim-ruby-heredoc-syntax "joker1007/vim-ruby-heredoc-syntax")

![screenshot.png](https://github.com/joker1007/vim-ruby-heredoc-syntax/raw/master/screenshot.png)

これでvimのシンタックスハイライトは大したことないとか言わせねえ！

まだドキュメントとか全然書いてないので対応言語が分かりづらいですが、現在デフォルトで対応しているのは以下の通りです。

- vim-markdown-quote-syntax
  - vim
  - diff
  - c
  - cpp
  - java
  - ruby
  - haskell
  - python
  - perl
  - javascript
  - html
  - sh
  - sql
  - ocaml
  - erlang

- vim-ruby-heredoc-syntax
  - javascript
  - coffeescript
  - sql
  - html

デフォルトの設定は適当に目についた言語とrubyのヒアドキュメントで書く事の多そうな言語です。


Rubyのヒアドキュメントのシンタックス定義を解読するの辛かった…。

```vim
let regexp1 = "\\%(\\%(class\\s*\\|\\%([]})\"'.]\\|::\\)\\)\\_s*\\|\\w\\)\\@<!<<-\\=\\zs".a:start

let regexp2 = "\\%(\\%(class\\|::\\)\\_s*\\|\\%([]}).]\\)\\s\\|\\w\\)\\@<!<<-\\=\\z(".a:start."\\)\\ze\\%(.*<<-\\=['`\"]\\=\\h\\)\\@!"
```

書いたプラグインのコードの一部ですが、もう意味分かりませんw