vim 用 Template-Toolkit のシンタックスハイライト
ひさびさに Template Toolkit を触ってて,普通に html のシンタックスハイライトで書いていたんですが,<
とか >
とかの演算子がでてくると,ハイライトがおかしくなるのが煩わしい!
と思ってたら,TT2 用の文法ファイルを書いてくださった方がいらっしゃるんですね。
ということで,以下の先人の知恵をほぼそのままお借りしました。
- TT2 syntax - Syntax Highlight for Template-Toolkit 2.x : vim online
- Template-Toolkit のテンプレートファイルを vim で色付きにする - Craftworks Tech Blog - Branch
- およびコメント欄
シンタックスファイルのインストール
以下は「個人ユーザ」用のインストール方法です。システムワイドな場合の方法はホームディレクトリのかわりに $VIMRUNTIME
以下のディレクトリでやるのかな?よくわかりません。
- TT2 syntax - Syntax Highlight for Template-Toolkit 2.x : vim online からファイル群を落とす。
~/.vim/syntax/
というディレクトリを(なければ)掘る- 落としたアーカイブに含まれる
tt2.vim
とtt2html.vim
というファイルをそのディレクトリにコピーする
シンタックスハイライトを有効にする
んで,インストールしただけだと使えないので,それを autocmd という機能で使えるようにします。
この autocmd をどこに書くかが問題ですが,~/.vimrc
に書いてもたぶん大丈夫かなぁと思いますが,慣例的にftdetect/
というディレクトリにスクリプトを置くみたい。
今回の場合(個人ユーザ向けなので)~/.vim/ftdetect/
というディレクトリを(なければ)掘って,その下にたとえば tt2.vim
などのファイルを作成します。
あとは,そのファイルに TT2 syntax - Syntax Highlight for Template-Toolkit 2.x : vim online にあるように
au BufNewFile,BufRead *.tt2 setf tt2
と記述すると,.tt2
という拡張子のファイルの場合に Template Toolkit なシンタックスハイライトが有効になります。
んが,この tt2
という syntax はあくまで Template Toolkit の文法しか解釈しません。普通 Template Toolkit を使うのは HTML ですよね。なので,HTML と Template Toolkit の文法をどちらもシンタックスハイライトしてくれる syntax も定義されています。それが tt2html
というシンタックスです。たとえば,
au BufNewFile,BufRead *.thtml setf tt2html
のようにすると,.thtml
という拡張子のファイルの場合に,HTML と TT2 両者のシンタックスハイライトが反映されます。
ファイルの内容に応じて tt2
と tt2html
を切り替える
んで,拡張子に応じてファイルタイプを設定するのなら(あるいはモードラインで設定するのなら)以上の設定でいいんですが,同じ .tt2
という拡張子で,HTML の場合には自動的に tt2html
のファイルタイプにしてくれるスクリプトが,配布元(TT2 syntax - Syntax Highlight for Template-Toolkit 2.x : vim online)に記述されています。それが,これ。
au BufNewFile,BufRead *.tt2 \ if ( getline(1) . getline(2) . getline(3) =~ '<\chtml' \ && getline(1) . getline(2) . getline(3) !~ '<[%?]' ) \ || getline(1) =~ '<!DOCTYPE HTML' | \ setf tt2html | \ else | \ setf tt2 | \ endif
なんかめまいがしますが,やっていることはなんとなく想像つきますね。
めまいがする理由は 「\
」 と 「|
」 の氾濫です。vim では,行頭に 「\
」 があると,前の行からの継続行になります。一般的なシェルスクリプトやスクリプト言語だと行末に 「\
」 を置くもんですが,vim だと逆なんですね。それで,「|
」というのが,シェルスクリプトでいうところの「;
」にあたるものです。一行内に複数のコマンドを詰め込むときに使います。
このようにがんばって継続行で定義しなくても,ローカルな関数を定義してそれを呼び出すようにしてあげれば,みやすくはなります。
function! s:FTtt2() if ( getline(1) . getline(2) . getline(3) =~ '<\chtml' && getline(1) . getline(2) . getline(3) !~ '<[%?]' ) || getline(1) =~ '<!DOCTYPE HTML' setf tt2html else setf tt2 endif endfunction autocmd BufNewFile,BufRead *.tt2 call s:FTtt2()
関数名の「s:
」というプリフィックスが,このスクリプトローカルでしか見えない関数の定義です(たしか変数でも同じようなプリフィックスを指定するとスクリプトローカルなスコープを指定できたはず)。それを autocmd
で call
してやればよい,と。これでスクリプトとしては見やすくなりました。
んで,自分の環境だと,先頭に Template Toolkit のコマンド群がだだっと書いてあるテンプレートファイルを扱ったりするんで,3行だけで判断されるとうまく判定できない場合がありました。なので,まったく違うアプローチで自分用に書いてみました。
function! s:FTtt2() let save_cursor = getpos('.') call cursor(1, 1) if search('\<\c\%(html\|head\|body\|div\)', 'cn') > 0 setf tt2html else setf tt2 endif call setpos('.', save_cursor) endfunction au BufNewFile,BufRead *.tt2 call s:FTtt2()
検索機能を使って HTML かどうか判断してます(かなり適当ですが)。でもファイルタイプの判定にこういうことあんまりしないほうがいいのかなぁ。検索バッファに残る?重い?
よくわかりませんが,一応動くのでこれでよしとしています。識者のご指摘を待ちたいところです。
拡張子 .html でも TT2 ハイライトを行いたい
それ
au BufNewFile,BufRead *.html setf tt2html
で,もういいんじゃないかと思ったりしますが,念のために TT2 のコマンドが入っていないファイルは純粋な html のシンタックスハイライトを行ってほしい。
そう思ったので書いてみました。
function! s:FTtt2html() let save_cursor = getpos('.') call cursor(1, 1) if search('\[%', 'cn') > 0 setlocal filetype=tt2html endif call setpos('.', save_cursor) endfunction autocmd BufReadPost *.html call s:FTtt2html()
vim のドキュメントを読む限り,同一のイベント・ファイル名に対して複数の autocmd を指定してもうまくいくはずなのですが,うまくいかなかったので autocmd!
でもともと設定されている内容を消去してます。んで,$VIMRUNTIME/filetype.vim
で定義されてる s:FThtml()
という関数は呼び出せないので(先ほど書いたようにスクリプトローカルなスコープなのであたりまえ),自分なりの関数を書いて呼び出してます。
ここらへんをもっとうまくやる方法があったら知りたい!
(既存の autocmd を生かした方法…… BufEnter
以外で……というか BufEnter
を使った方がいいの?)
2011-06-03: コメントでご指摘の内容に基づき改変済
最後になりますが,真面目?な方は,これまでの内容を if has("autocmd")
で囲んだほうがいいかもしれません。
if has("autocmd") " ここにさきほどまでの設定内容をいれる endif
まぁたいてい autocmd は使えると思いますけど。
TT2 シンタックスファイルの修正
コメントまわりで挙動があれっという部分がありました。
# これはうまく動く(ブロックコメント) [%# this entire directive is ignored no matter how many lines it wraps onto %] # これもうまく動く [% # this us a comment theta = 20 # so is this rho = 30 # <aol>me too!</aol> %] # これがうまく動かない(baz の部分もコメントとみなされてしまう) [% 'foo' # bar %] baz
なので,自分用に tt2.vim
を修正しました。
--- tt2.vim.orig 2009-06-24 09:56:59.000000000 +0900 +++ tt2.vim 2009-06-26 10:21:06.000000000 +0900 @@ -161,7 +161,7 @@ syn match tt2_operator "\(\s\)\@<=_\(\s\)\@=" contained syn match tt2_operator "=>\|," contained syn match tt2_deref "\([[:alnum:]_)\]}]\s*\)\@<=\." contained -syn match tt2_comment +#.*$+ contained extend +syn match tt2_comment +#.\{-}\%(%\]\|$\)\@=+ contained extend syn match tt2_func +\<\I\w*\(\s*(\)\@=+ contained nextgroup=tt2_bracket_r skipempty skipwhite " syn region tt2_bracket_r start=+(+ end=+)+ contained contains=@tt2_statement_cluster keepend extend
一行なので手であてたほうが早いと思いますが。
あと,TT2 の開始・終了タグは [% 〜 %]
で決め打ちにしてます。ほんとは,b:tt2_syn_tags
という変数(カスタム開始終了タグ)が定義されているときは,それに応じた内容にしなきゃいけないんですが,面倒(&自分の環境だとデフォルト)なので。