flymake-perlをエラーなく実行するためにやっておくべきこと

 ごちゃごちゃしてきたので、別エントリで。

(前回までのあらすじ)
 tramp起動時にflymake-perlが有効になってしまうことに業を煮やした僕が、xなんとか氏g:emacs:id:xcezx)のツッコミを受けながらflymakeのコードをちょっとずつ読んで、ついに原因を特定する。

 flymake.elの623行目でflymake-post-syntax-checkという関数が定義されていて、ここに後処理が書いてあります。flymake-perl時にtrampが有効になってしまうのは、flymake-check-was-interruptedという変数がtrueになってしまい、645行目の

(flymake-report-status nil ""))) ; "STOPPED"

 という処理に飛んでしまうからです。このflymake-report-statusという関数は1287行目で定義されていて、

(defun flymake-report-status (e-w &optional status)
  "Show status in mode line."
  (when e-w
    (setq flymake-mode-line-e-w e-w))
  (when status
    (setq flymake-mode-line-status status))
  (let* ((mode-line " Flymake"))
    (when (> (length flymake-mode-line-e-w) 0)
      (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
    (setq mode-line (concat mode-line flymake-mode-line-status))
    (setq flymake-mode-line mode-line)
    (force-mode-line-update)))

 とまあ、色々設定しなおしたのちにforce-mode-line-update関数を評価しておしまいです。なお、643-4行目にはflymake-check-was-interruptedがnilの時の処理が書いてあって、

(flymake-report-fatal-status "CFGERR"
  (format "Configuration error has occured while running %s" command))

 と、エラー時の処理に飛ぶようになってます。このflymake-report-fatal-statusという関数は1309行目で定義されていて、

(defun flymake-report-fatal-status (status warning)
  "Display a warning and switch flymake mode off."
  (when flymake-gui-warnings-enabled
    (flymake-display-warning (format "Flymake: %s. Flymake will be switched OFF" warning))
    )
  (flymake-mode 0)
  (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s"
               (buffer-name) status warning))

 と、ここでは「(flymake-mode 0)」というのが評価され、flymakeを無効にしていることがわかります。
 ここで、2つの選択肢がでてくると思います。まず何よりの目的は、tramp起動時はflymakeを無効にすることです。ただ、そのための実装方法として

  1. わざわざflymake-check-was-interruptedをtrueにせず、普通にエラー処理させて無効にする
  2. わざわざdefadviceつけてまで処理してるので、大元の設定を書いた人の意思を尊重して、flymake-report-status関数の方を変更する

 前者の方が設定が圧倒的に楽ですが、プロンプトはウザいし、exit-statusが1以上なのにinterruptedがtrueなのは基本的にエラーなのではないかと思うので、僕はあえて後者の方を選択しています。もう一度645行目を見てもらうと分かるように、

(flymake-report-status nil ""))) ; "STOPPED"

 第1引数にはnilが渡っています。検索してみる限り、flymake-report-status関数を呼び出しているところで、第1引数がnilなのはここしかないので、これを利用しない手はないと思います。そこを踏まえて、flymake-report-status関数に以下の処理を追加しました。

(defadvice flymake-report-status (before flymake-quite-report-status (e-w &optional status))
  (if (not e-w)
      (progn
        (flymake-mode 0)
        (flymake-log 0 "switched OFF Flymake mode due to unknown fatal status (maybe tramp is running)"))))
(ad-activate 'flymake-report-status)

 これをid:antipop氏の例の設定の前に書き加えておけば、tramp起動時にもプロンプトは出ず、かつflymakeも無効になります。なお、コメントやmessageに出力する文章は殆ど推敲なしなので、もっといい文言が欲しいです。