fcshをラップしてhttpインターフェースを提供するサーバと、それを利用するクライアントがセットになったrubyスクリプトです。Emacs Wiki Flymake + Actionscript のスクリプトを参考に、複数ファイルに対してflymakeモードを使用できるよう作りました。
fcshコマンドでサーバを起動します。
$ ruby fcshwrapper.rb fcsh
Adobe Flex Compiler SHell (fcsh)
Version 4.0.0 build 7219
Copyright (c) 2004-2007 Adobe Systems, Inc. All rights reserved.
(fcsh)
[2009-10-19 21:52:44] INFO WEBrick 1.3.1
[2009-10-19 21:52:44] INFO ruby 1.8.7 (2008-08-11) [i386-cygwin]
[2009-10-19 21:52:44] INFO WEBrick::HTTPServer#start: pid=7128 port=4001
デフォルトホストはlocalhost、ポートは4001です。これらは、--host、--portオプションで変更できます。
サーバではfcshが出力するメッセージのパースを行なっています。そのため、fcshwrapper.rbを使用せずfcshを実行した際にメッセージが日本語で表示される環境では、ruby fcshwrapper.rb --lang=ja fcsh のように--langオプションが必要です。場合によっては、--fcshcオプション等を使用して文字コードを明示する必要があるかもしれません。
fcshwrapper.rbはwebサーバとしても機能します。--dirオプションの指定が無い場合は、カレントワーキングディレクトリがドキュメントルートになります。
$ ruby fcshwrapper.rb help
#<Net::HTTPOK:0x7fde47a0>
List of fcsh commands:
mxmlc arg1 arg2 ... full compilation and optimization; return a target id
compc arg1 arg2 ... full SWC compilation
compile id incremental compilation
clear [id] clear target(s)
info [id] display compile target info
quit quit
(fcsh)
サーバ起動後、helpコマンドを実行した例です。クライアント側は、通常fcshで使用しているコマンドをfcshwrapper.rbの後に続けると、だいたい上手く行くと思います。
以前実行したmxmlcコマンドやcompcコマンドで、既にターゲットIDを取得できているものは、サーバが自動でcompileコマンドに変換してfcshに渡しますので、単に同じコマンドを繰り返すだけでfcshの恩恵にあずかれます。
クライアントは、http://host:port/コマンド?q=引数 の送受信をしているだけですので、他プログラムでも代用が利くと思います。
その他、オプションやコマンド等は--helpオプションで確認できます。
使用例として設定の紹介と簡単な解説をさせていただきます。
(defun flymake-actionscript-init ()
(let* ((source-file-name buffer-file-name))
(if source-file-name
(let* ((temp-source-file-name
(flymake-init-create-temp-buffer-copy
'flymake-create-temp-with-folder-structure)))
(list "aslint.bat"
(list temp-source-file-name))))))
(add-to-list 'flymake-allowed-file-name-masks
'("\\.as\\'"
flymake-actionscript-init
flymake-simple-java-cleanup))
(add-hook 'actionscript-mode-hook
(lambda ()
(setq flymake-err-line-patterns
(cons '("^\\(.*\\)(\\([0-9]+\\)): col: \\([0-9]+\\) \\(.*\\)$" 1 2 3 4)
flymake-err-line-patterns))
(local-set-key "\C-cp" 'flymake-goto-prev-error)
(local-set-key "\C-cn" 'flymake-goto-next-error)
(local-set-key "\C-cd" 'my-flymake-display-err-for-current-line)
(flymake-mode-on)
))
flymake-actionscript-initは、一時ディレクトリに編集ファイルのコピーを作成し、aslint.batを実行する関数です。temp-source-filenameを含むリストで引数を渡せますが、ここでは一時ファイルのみにして残りはbatファイルの中で渡しています。
"/path/to/ruby" /path/to/fcshwrapper.rb mxmlc -load-config+=/path/to/aslint_config.xml %1
mxmlcコマンドのオプションはaslint_config.xmlファイルで渡しています。
<flex-config>
<output>/tmp/foo.swf</output>
<compiler>
<source-path>
<path-element>/path/to/temp/src</path-element>
<path-element>/path/to/include/src/a</path-element>
<path-element>/path/to/include/src/b</path-element>
</source-path>
</compiler>
</flex-config>
swfの出力先が一時ファイルと同じ場合、flymakeが一時ファイルといっしょに作成したディレクトリを自身で消すことができなくなるため、outputで別の場所を指定しています。また、source-pathの先頭で一時ディレクトリを指定して、パッケージシステムのつじつまを合わせています。
$ zcat /usr/share/emacs/23.1/lisp/progmodes/flymake.el.gz | diff -u - /cygdrive/c/Users/cap/bin/emacs-23.1/lisp/progmodes/flymake.el
--- - 2009-10-18 01:00:23.945000000 +0900
+++ /cygdrive/c/Users/cap/bin/emacs-23.1/lisp/progmodes/flymake.el 2009-10-17 11:24:35.721000000 +0900
@@ -1503,8 +1503,8 @@
(defun flymake-delete-temp-directory (dir-name)
"Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error."
(let* ((temp-dir (flymake-get-temp-dir))
- (suffix (substring dir-name (1+ (length temp-dir)))))
-
+ (suffix (substring dir-name (length temp-dir))))
+
(while (> (length suffix) 0)
(setq suffix (directory-file-name suffix))
;;+(flymake-log 0 "suffix=%s" suffix)
emacs23.1時点のflymake.elでは、一時ディレクトリの削除に失敗するため修正しました。ただ、先述のswf出力先の指定とこの修正は、一時ファイルが消えないだけで実害があるわけではないため、気にならないのであれば必要ありません。修正したら、M-x byte-compile-fileをお忘れなく。
(defun my-flymake-display-err-for-current-line ()
"Display errors/warnings 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)))
(err-data (my-flymake-make-err-data line-no line-err-info-list))
(choice nil))
(if err-data
(message err-data)
(message "no errors for line %d" line-no))))
(defun my-flymake-make-err-data (line-no line-err-info-list)
"Make a list with errors/warnings from LINE-ERR-INFO-LIST."
(let* ((err-data nil))
(when line-err-info-list
(let* ((count (length line-err-info-list))
(item-text nil))
(while (> count 0)
(setq item-text
(flymake-ler-text (nth (1- count) 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)))
(line (flymake-ler-line (nth (1- count) line-err-info-list))))
(if file
(setq item-text
(concat item-text " - " file "(" (format "%d" line) ")"))))
(setq err-data
(if err-data (concat err-data "\n" item-text) item-text))
(setq count (1- count)))))
(if err-data
(let*
((title (format "Line %d: %d error(s), %d warning(s)"
line-no
(flymake-get-line-err-count line-err-info-list "e")
(flymake-get-line-err-count line-err-info-list "w"))))
(setq err-data (concat title "\n" err-data)))
nil)))
このコード片は、flymakeがメニューとして表示するエラーや警告をミニバッファに表示でき るようにしたもので、上記actionscript.elの中でC-cdにバインドしています。