Ruby
Vim

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

More than 1 year has passed since last update.

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

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

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

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を無効化してからシンタックスを読み込みます。

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

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に指定する事で、特定の領域内だけ他言語のシンタックスハイライトを適用できる。

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

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

joker1007/vim-markdown-quote-syntax
screenshot.png

joker1007/vim-ruby-heredoc-syntax

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のヒアドキュメントのシンタックス定義を解読するの辛かった…。

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

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

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