Flymakeはソースコードの文法エラーを,編集中にリアルタイムでチェックしてくれる機能である.
これを用いれば,例えばC言語で行末にセミコロンを忘れてコンパイラに怒られるといった凡ミスはなくなる.
設定
とりあえず,以下のコードを使用すればC/C++で文法チェックができる.
(require 'flymake nil t) (defun flymake-get-make-cmdline (source base-dir) "redefinition to remove 'check-syntax' target" (list "make" (list "-s" "-C" base-dir (concat "CHK_SOURCES=" source) "SYNTAX_CHECK_MODE=1" ))) (defun flymake-simple-make-or-generic-init (cmd &optional opts) "force to check syntax of C/C++ without Makefile" (if (file-exists-p "Makefile") (flymake-simple-make-init) ;; flymake built-in (flymake-simple-generic-init cmd opts))) (defun flymake-simple-generic-init (cmd &optional opts) "Makefileがないときのコードチェック用関数" (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 cmd (append opts (list local-file))))) ;; syntax checkが異常終了しても無視する (defadvice flymake-post-syntax-check (before flymake-force-check-was-interrupted activate) (setq flymake-check-was-interrupted t)) ;; C (defun flymake-c-init () (flymake-simple-make-or-generic-init "gcc" '("-Wall" "-Wextra" "-pedantic" "-fsyntax-only" "$CPPFLAGS"))) ;; C++ (defun flymake-cc-init () (flymake-simple-make-or-generic-init "g++" '("-Wall" "-Wextra" "-pedantic" "-fsyntax-only" "$CPPFLAGS"))) (push '("\\.[cCh]\\'" flymake-c-init) flymake-allowed-file-name-masks) (push '("\\.\\(?:cc\|cpp\|CC\|CPP\\)\\'" flymake-cc-init) flymake-allowed-file-name-masks) (add-hook 'c-mode-common-hook '(lambda () (flymake-mode t)))
エラー表示
さて,エラーチェックした結果をいかにうまく表示させるかというのが問題になってくる.
記事としてはid:syohex氏の
が参考になる.
ミニバッファに表示させるには以下の関数を用いるとよい.私のオリジナルではない.
(defun flymake-display-err-minibuf () "Displays the error/warning for the current line in the minibuffer" (interactive) (let* ((line-no (flymake-current-line-no)) (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no))) (count (length line-err-info-list))) (while (> count 0) (when line-err-info-list (let* ((file (flymake-ler-file (nth (1- count) line-err-info-list))) (full-file (flymake-ler-full-file (nth (1- count) line-err-info-list))) (text (flymake-ler-text (nth (1- count) line-err-info-list))) (line (flymake-ler-line (nth (1- count) line-err-info-list)))) (message "[%s] %s" line text))) (setq count (1- count)))))
popup.elを用いる方法については,id:syohex氏の記事に以下の関数が紹介されていた.
(defun flymake-display-err-menu-for-current-line () (interactive) (let* ((line-no (flymake-current-line-no)) (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no)))) (when line-err-info-list (let* ((count (length line-err-info-list)) (menu-item-text nil)) (while (> count 0) (setq menu-item-text (flymake-ler-text (nth (1- count) line-err-info-list))) (let* ((file (flymake-ler-file (nth (1- count) line-err-info-list))) (line (flymake-ler-line (nth (1- count) line-err-info-list)))) (if file (setq menu-item-text (concat menu-item-text " - " file "(" (format "%d" line) ")")))) (setq count (1- count)) (if (> count 0) (setq menu-item-text (concat menu-item-text "\n"))) ) (popup-tip menu-item-text)))))
上記の関数を使用してみたが,ソースコードのとある1行にエラーが複数個含まれる場合でも,1個分しか表示されなかった.
そこで私は以下のように修正を試みた.
(defun flymake-display-err-menu-for-current-line () "Displays the error/warning for the current line via popup-tip" (interactive) (let* ((line-no (flymake-current-line-no)) (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no)))) (when line-err-info-list (let* ((count (length line-err-info-list)) (menu-item-text "") (menu-item-text-tmp "")) (while (> count 0) (setq menu-item-text-tmp (flymake-ler-text (nth (1- count) line-err-info-list))) (let* ((file (flymake-ler-file (nth (1- count) line-err-info-list))) (line (flymake-ler-line (nth (1- count) line-err-info-list)))) (if file (setq menu-item-text-tmp (concat menu-item-text-tmp " - " file "(" (format "%d" line) ")")))) (cond ((> count 1) (setq menu-item-text (concat menu-item-text menu-item-text-tmp "\n"))) (t (setq menu-item-text (concat menu-item-text menu-item-text-tmp)))) (setq count (1- count))) (popup-tip menu-item-text)))))
これで少なくとも私は複数個のエラーを表示できるようになった.
…が,実はここまで複雑なコードを書く必要はない.以下の簡潔なコードで事足りるのだった.
(defun my-flymake-display-err-menu-for-current-line () "Displays the error/warning for the current line via popup-tip" (interactive) (let* ((line-no (flymake-current-line-no)) (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no))) (menu-data (flymake-make-err-menu-data line-no line-err-info-list))) (if menu-data (popup-tip (mapconcat #'(lambda (err) (nth 0 err)) (nth 1 menu-data) "\n")))))
エラー表示する関数や,次のエラー箇所へジャンプする関数は是非押しやすいキーにバインドされたい.
作業効率がさぞ改善することだろう.
参考記事
偉大な先人達はすでに記事にしていらっしゃるので,そちらを参照されるのもよい.
- Flymake を使って編集中にシンタックスエラーを検出する — ありえるえりあ
- flymake でリアルタイム文法チェック - とりあえず暇だったし何となく始めたブログ
- flymake-mode / マスタカの ChangeLog メモ
- Emacs で文法チェック
- flymake (いままでこれ無しでどうやってプログラム書いてたんだろう) - にゃあさんの戯言日記
- Emacs flymakeでC++ソース編集中にコンパイルエラーを検出
- Story of Your Life » Blog Archive » Emacsで開発環境を整える
- Flymakeのススメ(PHP版 , JS版) — ディノオープンラボラトリ
- EmacsでPerl開発する上で必須な設定 #2 - flymake - delirious thoughts
- EmacsでPythonの設定 | おいぬま日報
- ghc-modのflymakeエラーをミニバッファに表示する - ぼくのぬまち 出張版
- PHP + flymake - tototoshiの日記
- Flymake で Makefile の存在に加えて check-syntax ターゲットの有無をチェックする - キーボードをたたくとき
- EmacsのFlymakeでJavascriptとHTMLの構文チェックしてみる - 牌語備忘録 - pygo
原理的には,きちんと設定を書きさえすればさまざまな言語に対応できる.