CoffeeScript + Guard::CoffeeScript + Emacs + Flymakeで「Errno::ENOENT: No such file or directory」が出ないように
最近、GuardでTitanium+CoffeeScriptの開発を快適に – ひげろぐを参考にGuard::CoffeeScriptを入れ、coffeescriptでflymakeする - Kentaro Kuribayashi's blogのFlymakeの設定を入れてCoffeeScriptでTitaniumでのアプリ作成を試してます。
Guard::CoffeeScriptでファイル変更の監視・コンパイルをしてると
ERROR: Guard::CoffeeScript failed to achieve its <run_on_change>, exception was: Errno::ENOENT: No such file or directory - coffee/app_flymake.coffee
というエラーが発生して頻繁にGuardが落ちる。
Flymake用の一時ファイルをGuardが検知し、コンパイルしようとするが、すぐに削除されるのでエラーになっているようだ。
そのまま参考になるruby-modeのflymakeでguardが誤動作しないようにする - むしゃくしゃしてやったを参考に、 flymake-create-temp-inplace を flymake-create-temp-with-folder-structure に変更し、同一ディレクトリ内でなく、tempディレクトリにflymake用のファイルを作成するようにした。
以下、diff
(setq flymake-coffeescript-err-line-patterns '(("\\(Error: In \\([^,]+\\), .+ on line \\([0-9]+\\).*\\)" 2 3 nil 1))) (defconst flymake-allowed-coffeescript-file-name-masks '(("\\.coffee$" flymake-coffeescript-init))) (defun flymake-coffeescript-init () (let* ((temp-file (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-with-folder-structure)) - 'flymake-create-temp-inplace)) (local-file (file-relative-name temp-file (file-name-directory buffer-file-name)))) (list "coffee" (list local-file)))) (defun flymake-coffeescript-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-coffeescript-file-name-masks)) (setq flymake-err-line-patterns flymake-coffeescript-err-line-patterns) (flymake-mode t)) (add-hook 'coffee-mode-hook 'flymake-coffeescript-load)
メモ
例えば/Users/foo/local/app/titanium/example/coffee/app.coffeeでエラーがある場合、エラー表示は以下のようになる。
[3] Error: In ../../../../../../../private/var/folders/OQ/OQ*************************/-Tmp-/Users/foo/local/app/titanium/example/coffee/app.coffee, Parse error on line 3: Unexpected 'TERMINATOR'
この/private/var/folders/..というのは何だろう?と見てみると、自分の環境では環境変数TMPDIR, TMP, TEMPを見ているようでmacではこうなってるみたい。
;; flymake.el -> flymake-create-temp-with-folder-structure (defun flymake-create-temp-with-folder-structure (file-name prefix) (unless (stringp file-name) (error "Invalid file-name")) (let* ((dir (file-name-directory file-name)) ;; Not sure what this slash-pos is all about, but I guess it's just ;; trying to remove the leading / of absolute file names. (slash-pos (string-match "/" dir)) (temp-dir (expand-file-name (substring dir (1+ slash-pos)) (flymake-get-temp-dir)))) (file-truename (expand-file-name (file-name-nondirectory file-name) temp-dir)))) ;; flymake.el -> flymake-get-temp-dir (defalias 'flymake-get-temp-dir (if (fboundp 'temp-directory) 'temp-directory (lambda () temporary-file-directory))) ;; files.el -> temporary-file-directory (defcustom temporary-file-directory (file-name-as-directory (cond ((memq system-type '(ms-dos windows-nt)) (or (getenv "TEMP") (getenv "TMPDIR") (getenv "TMP") "c:/temp")) (t (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "/tmp")))) "The directory for writing temporary files." :group 'files :initialize 'custom-initialize-delay :type 'directory)