以前にtrampのデバッグでちょろっとだけ触ったきりのelispですが、emacsユーザである以上いつまでも避けては通れなさそうです。とりあえず触りだけ覚えておくことにしました。ただ今のところelispの習得度がpythonやperl並みになることは考えにくいので、elispから外部コマンドを叩いて出力を受け取るというところまでをメモしておきます。
実行は*scratch*バッファでC-jかM-x ielmで起動するelisp用の対話シェルで行いますが、ielemはタブで関数名などの候補を補完してくれますのでオススメです。早速Hello Worldを書いてみます。
(message "hello elisp world")
簡単ですね。次にこれをユーザ定義関数にしてみましょう。defunでhello関数を定義しています。定義後は(hello)として呼び出せます。
(defun hello () ; 定義 (message "hello elisp world")) (hello) ; 呼び出し
defunで関数を定義すればM-xからemacsコマンドとしても実行できると思っていたのですが、実際はできなくてちょっとハマりました。調べてみるとinteractiveを利用してemacsコマンドとして登録する必要がありまして、以下が正解になります。これで無事にM-x helloが使えるようになります。無事にelispの1歩目を踏み出せましたね。
(defun hello () (interactive) ; コマンド登録 (message "hello elisp world"))
次は外部コマンドの実行ですが、call-processという関数を使います。
(call-process command infile destination display ...)
少しややこしいですが、例えばgrep error /var/log/system.logを実行して、現在のバッファのカーソル位置に出力を受け取るには以下のようにします。
(call-process "grep" nil t nil "error" "/var/log/system.log")
以上でelispから外部コマンドを叩くelispコマンドを作成できるようになりました。これでpythonなりperlなりで書いておいたやりたい処理をelispから叩けますね。
例として「emacsで開いているファイルをXcodeで開く」というelispとpythonスクリプトの合わせ技が以下になります。
elisp部
(defun open-in-xcode () (interactive) (setq filename (buffer-file-name (current-buffer))) (setq offset (format "%d" (point))) (call-process "open_in_xcode.py" nil t nil filename offset)) ;; open_in_xcode.pyを叩く
pythonスクリプト部(open_in_xcode.py)
#!/usr/bin/python # -*- coding: utf-8 -*- import sys from appscript import * if len(sys.argv) == 3: filepath = sys.argv[1].replace('/', ':')[1:] filerange = int(sys.argv[2]) else: print "Usage: open_in_xcode filepath file_selected_range" sys.exit(0) xcode = app("Xcode") xcode.activate() target = xcode.open(filepath) target.selected_character_range.set([filerange,filerange])
これでM-x open-in-xcodeでEmacsのカレントバッファで開いているファイルをXcodeで開けます。割と便利なんじゃないかと思いますけどどうでしょうか。これからelisp + αなちょい技を少しずつ貯めていこうと思います。

