ほんじゃらねっと

ダイエット中プログラマのブログ

Pymacsを使ってPythonでEmacs拡張

NTEmacsを使い始めたので、Pymacsを入れて簡単なプラグインを作ってみた。
EmacsVimと比べるとまだまだ不満がいっぱいだが、色々プラグイン
作ってVimの快適さに近づけていきたい。


苦労したのでメモ。

Pymacsのインストール

Python2.5環境で試した。


あらかじめ、python-modeを入れておく


SourceForge.net: python-mode.el for Emacs and XEmacs
http://sourceforge.net/projects/python-mode/


下記のURLからPymacsをダウンロード


README file for Pymacs
http://pymacs.progiciels-bpi.ca/index.html


解凍すると色々ファイルがある中にsetup.pyがあるので、コマンドプロンプト

python setup.py install

を実行してPython側環境をインストール。


Emacs側は、解答したフォルダに入っているpymacs.elをsite-lisp内に
作ったPymacsフォルダあたりに入れる。


また、site-lispとは別にPymacs用のpythonファイルを入れておく
pymacs-elispフォルダを作った。


このあたりは本家サイトのドキュメントを参考にした。


Pymacs version 0.24-beta1
http://pymacs.progiciels-bpi.ca/pymacs.html


.emacsには下記のような設定を入れておく

;; Pymacs
(autoload 'pymacs-apply "pymacs")
(autoload 'pymacs-call "pymacs")
(autoload 'pymacs-eval "pymacs" nil t)
(autoload 'pymacs-exec "pymacs" nil t)
(autoload 'pymacs-load "pymacs" nil t)
(eval-after-load "pymacs"
'(add-to-list 'pymacs-load-path "~/app/emacs/pymacs-elisp"))

この設定の下にpython-mode用の設定を入れておく。

;; python-mode
(autoload 'python-mode "python-mode" nil t)
(autoload 'py-shell "python-mode" "Python shell" t)
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-hook 'python-mode-hook
'(lambda()
(require 'pycomplete)
(setq indent-tabs-mode nil)))

python-modeに付属のpycomplete.pyはpymacs-elispフォルダの
方に入れておくと認識してくれた。

Pymacsで日本語が通るようにする

下記のサイトを参考にした。


Pymacs で日本語文字列を無理矢理通す
http://d.hatena.ne.jp/amt/20061219/PymacsDeNihonngoWoToosuP2E


emacs初心者なので理解できる範囲をかなり超えていたが、
どうやらページの中ほどに記載されている、

  1. ustr.pyをpymacs-elispフォルダに配置し、
  2. pymacs-ustr.elをsite-lisp/Pymacsに配置したら

うまく動作するようだ。


python関連の設定は上記のみのはず。
最終的にpython関連のファイルは下記のようなフォルダ構成になった

~/
.emacs
app/emacs/
site-lisp/
Pymacs/
pymacs.el
pymacs-ustr.el
python-mode-1.0/
doctest-mode.el
pycomplete.el
python-mode.el
pymacs-elisp/
ustr.py
pycomplete.py

動作テスト

これで準備ができたはずなので、簡単なプラグインでテストしてみる。

まずは下記のようなpythonファイルを作ってpymacs-elispフォルダに保存する。


helloworld.py

# -*- coding: utf-8 -*-
from Pymacs import lisp
from ustr import *
def hello():
lisp.py_insert(ustring2bytes(u"こんにちは Hello from Python!"))

これでpython側の日本語がemacs側で使えることを確認する。

方法としては、

  1. *scratch*バッファあたりの適当なバッファに移動
  2. M-x pymacs-load
  3. ロードするモジュールを聞かれるので、ファイル名"helloworld"を入力
  4. プレフィックスはデフォルトの"helloworld-"で良い
  5. これでhelloworld.pyの中の関数が(helloworld-関数名)で呼び出せるはず
  6. *scratch*上で(helloworld-hello)と記入し、行を選択して"C-j"で実行し、日本語で"こんにちは"が読めたら成功 (後ろに返り値の"nil"が入るけど気にしない)


続いて、emacsから入力した日本語をpython側で受け取れることを確認する

下記のようなpythonファイルを作ってpymacs-elispに保存する。


filetest.py

# -*- coding: utf-8 -*-
from Pymacs import lisp
from ustr import *
def writefile(b):
text = bytes2ustring(b)
f = open("c:/test/output.txt", "w")
f.write(text)
f.close()

出力先は適当に存在するフォルダを指定する。

上記のhelloworld.pyと同様にロードして実行するのだが、渡す文字列を
バイト配列に変換してやる必要がある。

  1. M-x pymacs-load
  2. "filetest"と入力
  3. プレフィックスはそのままで
  4. M-x load-libraryを実行
  5. pymacs-ustrをロード
  6. *scratch*に(filetest-writefile (py-string-to-unicode-vector "やっほー"))と記入し、行を選択して"C-j"で実行
  7. output.txtに"やっほー"が日本語で出力されていたら成功

(py-string-to-unicode-vector "文字列")でemacs側から文字列を渡し、
python側でbytes2ustringで戻せば日本語が通るようだ。

サンプル

最後に、以前vim用のプラグインとして作った1行メモプラグイン
移植したものを作ってみたので、公開してみる。


以前作ったもの


[vim][python] Pythonで1行メモVimスクリプト
http://d.hatena.ne.jp/piro_suke/20080215/1203087230


site-lisp/pymemo.el

(require 'pymacs)
(require 'pymacs-ustr)
(pymacs-load "pymemo")
(defun pymemo-add (msg)
(interactive
(list (read-from-minibuffer "memo: ")))
(pymemo-add-memo (py-string-to-unicode-vector msg)))
(provide 'pymemo)


pymacs-elisp/pymemo.py

# -*- coding: utf-8 -*-
import sys
import codecs
import os
import re
import datetime
from Pymacs import lisp
from ustr import *
LINE_HEADER= "*"
DATE_TEMPLATE = "[%Y-%m-%d %H:%M]"
ENCODING="Shift_JIS"
FILE_PATH = "C:/test/data/memo/pymemo.txt"
def add_memo(b):
msg = bytes2ustring(b)
msg = msg.encode(ENCODING)
day = datetime.datetime.now().strftime(DATE_TEMPLATE)
f = open(FILE_PATH, "a+")
f.write("%s %s %s\n" % (LINE_HEADER, msg, day))
f.close()

.emacs(Pymacsのロード処理以降に)

;; Pymemo
(require 'pymemo)


これで、

M-x pymemo-add

を実行すると"memo:"と表示されるので、1行メモを入力すると
FILE_PATHで指定したファイルに追記される。


これを応用すれば、WEB-APIとの連携もできるだろう。
Vimと共有可能なライブラリができれば良いのだけど。