2011年7月31日日曜日

構文チェックツールのFlymakeを、Haskell用に設定する方法


Emacsでは、Flymakeを使うことで、コードを書くと随時文法チェックが行われ、エラーのある行がバッファ上に表示されるようになる。

Haskell用にFlymakeを設定したので、その設定を書いておく。.emacsを編集するだけでOKだ。

Flymakeでは、基本的にコードと同じディレクトリにあるMakefileを使って文法チェックを行う形になっているが、いちいちMakefileを用意するのは煩わしいので、Makefileなしでも動作するようにした。特定のパラメータが必要な場合などは、Makefileを用意すれば自動的にそちらを使って文法チェックが行われるようにしてある。

.emacsの設定


以下のelispを.emacsに追加するだけでOK。

※Emacs21以前の場合は、flymake.elが標準で付属していないので、自分でインストールする必要がある。Emacs22以降であれば、標準で付属している。
;; Flymake Haskell

(require 'flymake)

(defun flymake-haskell-make-command (temp-file)
  (list "make"
        (flymake-haskell-make-parameters temp-file)))

(defun flymake-haskell-make-parameters (temp-file)
  (list "-s"
        "-C"
        "."
        (concat "CHK_SOURCES=" temp-file)
        "SYNTAX_CHECK_MODE=1"
        "check-syntax"))

(defun flymake-haskell-default-ghc-command (local-file)
  (list "ghc"
        (flymake-haskell-default-ghc-parameters
          (file-name-nondirectory local-file))))

(defun flymake-haskell-default-ghc-parameters (local-file)
  (list "-fno-code" local-file))

(defun makefile-exists-p (path)
  (file-exists-p (concat path "Makefile")))

(defun flymake-haskell-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))))
    (if (makefile-exists-p (file-name-directory buffer-file-name))
        (flymake-haskell-make-command temp-file)
        (flymake-haskell-default-ghc-command local-file))))

(push '(".+\\hs$" flymake-haskell-init) flymake-allowed-file-name-masks)
(push '(".+\\lhs$" flymake-haskell-init) flymake-allowed-file-name-masks)
(push '("^\\(\.+\.hs\\|\.lhs\\):\\([0-9]+\\):\\([0-9]+\\):\\(\.+\\)" 1 2 3 4)
      flymake-err-line-patterns)

(add-hook 'haskell-mode-hook
    '(lambda ()
       (if (not (null buffer-file-name))
           (flymake-mode))))

説明


flymakeの有効化
add-hookによって、haskell-modeに入ったときに(flymake-mode)が実行される。

拡張子の対応付け、エラーメッセージの正規表現の定義
add-hookの上でpushしているのは、Haskellの.hsファイル、.lhsファイルとflymakeの初期化関数との紐付け、及び、ghcの出力から行番号やエラーメッセージを抽出するための正規表現である。

flymake haskellの初期化
flymake-modeに入ると、flymake-haskell-initが実行される。flymake-haskell-initでは、構文チェック用にコードをコピーし、そのコードを構文チェックするためのコマンドをflymake本体に返している。このとき、チェック対象のコードと同じディレクトリにMakefileがあるかどうかでコマンドを変えている。

チェック対象のコードと同じディレクトリにMakefileがある場合
この場合、構文チェックのコマンドはflymake-haskell-make-command関数によって生成される。flymakeがデフォルトで使用するmakeコマンドと同じものを生成している。

チェック対象のコードと同じディレクトリにMakefileがない場合
一方、この場合は、Makefileなしで構文チェックを行うよう、GHCを使ったコマンドを、flymake-haskell-default-ghc-command関数で生成している。生成するコマンドの形式は、
("ghc" ("-fno-code" 構文チェック用ファイルの名前))
となる。外側のリストのcarがghcコマンド、cadrがghcコマンドに渡すパラメータのリストである。これがflymakeに渡され、実行される。

補足


flymakeではエラーメッセージも表示してくれるのだが、ghcが複数行にわたるエラーメッセージを返す場合にはうまく処理できない。

flymakeは、それだけで完全にコンパイルをとおすためではなく、コードを書くときのタイポ回避程度に位置づけると良いだろう。

参考


http://www.emacswiki.org/emacs/FlymakeHaskell




--

0 件のコメント: