改良Flymake for OCaml
問題
Eclipse などの統合開発環境には構文エラーがあると、その場でエラー箇所やメッセージを表示してくれる機能がある。
Emacs で同じ機能を実現するには、Flymake を使用するのが一番手っ取り早い。
詳しくは EmacsWiki の [Flymake の項を参考に。
しかし Flymake は列番号の出力に対応していないので、OCaml のような関数型言語で型エラーが発生すると、どの部分でエラーが起きているのか非常にわかりにくい。
対策
そこで、Flymake OCaml を改良して列番号をメッセージとして表示するようにしてみた。
すると、エラーと表示メッセージは次のようになる。
- エラー
- メッセージ
変更した ocaml_flycheck.pl は次の通り。
#!/usr/bin/env perl # ocaml_flycheck.pl use strict; use warnings; ### Please rewrite the following 2 variables ### ($ocamlc, @ocamlc_options) my $ocamlc = 'ocamlc'; # where is ocamlc my @ocamlc_options = ('-c -thread unix.cma threads.cma graphics.cma'); # e.g. ('-fglasgow-exts'); my @ocamlc_packages = (); ### the following should not been edited ### use File::Temp qw /tempfile tempdir/; File::Temp->safe_level( File::Temp::HIGH ); my ($source, $base_dir) = @ARGV; my @command = ($ocamlc); while (@ocamlc_options) { push(@command, shift @ocamlc_options); } push (@command, $source); while (@ocamlc_packages) { push(@command, '-package'); push(@command, shift @ocamlc_packages); } my $dir = tempdir( CLEANUP => 1 ); my ($fh, $filename) = tempfile( DIR => $dir ); system("@command >$filename 2>&1"); open(MESSAGE, $filename); my $column = ""; while (<MESSAGE>) { # example message {File "robocupenv.ml", line 133, characters 6-10: if (/^File "(\S+\.ml[yilp]?)", line (\d+), characters (\d+)-(\d+):\s?(.*)/) { print $column; my $error = (<MESSAGE>); # get the next line chomp $error; print "\n"; print "$1:$2:$3:"; $column = " [$3-$4]"; if ($error =~ /Warning(.*)/) { print "$error"; } else { print "$error "; } next; } if (/\s+(.*)/) { my $rest = $1; chomp $rest; print $rest; print " "; next; } } close($fh); print "$column\n";
ちなみに列番号の出力を最後にしてるのは、Flymake の仕様上
- 列番号の出力フォーマットが用意されていない
- メッセージの先頭が Warning であれば警告、そうでなければエラーと判別するためメッセージの先頭部分は変更できない
という理由による。