Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

flymakeでTemplate::Toolkitによるテンプレートファイルのシンタックスチェックを行う

Template::Toolkitによるテンプレートが複雑化してきて、flymakeによるシンタックスチェックをしたくなったのでやってみました。以下、あんまり整理されてないので、僕以外の環境ですぐに動くようになるというものでもないと思いますが、参考までに掲載しておきます。

実行例は以下の画像の通り。

f:id:antipop:20090218002839p:image

まずは、以下のスクリプトをPATHの通ったところにでも、tt_parse.plとして保存します。

#!/usr/bin/env perl
use strict;
use warnings;
use Path::Class qw(file);
use Template::Parser;

my $file     = file(shift);
my $template = $file->slurp;
my $parser   = Template::Parser->new;
if (!$parser->parse($template)) {
    (my $error = $parser->error) =~ s/\s{2,}/ /g;
    printf 'file:%s %s', $file->absolute, $error;
}

んでもってEmacsの設定ファイルに、以下のようなものを追加。ご覧になればわかる通り、かなり適当です。.htmlの拡張子を持つファイルはデフォルトでxml-lintをかけるような設定がされていて、それを自前のTT用の関数に差し替えたかったのですが、やりかたがわからなかったので、flymake-xml-initでもってTTテンプレートをパースするスクリプトを起動するようにしました。

(require 'flymake)

(setq flymake-tt-err-line-patterns
  '(("file:\\([^ ]+\\) line \\([0-9]+\\): \\(.+\\)" 1 2 nil 3)))

(defconst flymake-allowed-tt-file-name-masks
  '(("\\.html$" flymake-xml-init)
    ("\\.tt$"   flymake-xml-init)))

(defun flymake-xml-init ()
  (let* ((temp-file (flymake-init-create-temp-buffer-copy
                     'flymake-create-temp-inplace))
         (local-file (file-relative-name
                      temp-file
                      (file-name-directory buffer-file-name))))
    (list "perl" (list "tt_parse.pl" local-file))))

(defun flymake-tt-load ()
  (interactive)
  (defadvice flymake-post-syntax-check (before flymake-force-check-was-interrupted)
    (setq flymake-check-was-interrupted t))
  (ad-activate 'flymake-post-syntax-check)
  (setq flymake-allowed-file-name-masks (append flymake-allowed-file-name-masks flymake-allowed-tt-file-name-masks))
  (setq flymake-err-line-patterns flymake-tt-err-line-patterns)
  (flymake-mode t))

;; ここは、僕がhtml-modeを使っているのでこうしてるけど、
;; 他のhtml用モードを使う場合は変更する必要があります
(add-hook 'sgml-mode-hook 'flymake-tt-load)