« 2010年08月 | メイン | 2010年10月 »

2010年09月 アーカイブ

2010年09月17日

今、「Emacsテクニックバイブル」を読んでいます(auto-complete.elをインストール)

最近、Emacsテクニックバイブルを読んでいます。
「これは便利!」と思ったelispをインストールしてEmacsの環境を日々整えているところです。
それで、auto-complete.elをインストールしようとして戸惑いました。
インストール方法には、
M-x auto-install-batch auto-complete TAB
と書かれていました。
この本では、「インストールコマンドを設定ファイルのコメントに記述しておいて、『C-c C-e』で実行すると便利」みたいな事が書かれてたので、
;; (auto-install-batch "auto-complete")
と書いたんですが、「C-c C-e」としても動きません。
M-x auto-install-batch
の後にSPCを入れると、補完されて「auto-install-batch-」となってしまいうまくいきません。
「auto-install-batch」はコマンドなので、「『RET』が抜けてるなぁ」と思い、
M-x auto-install-batch RET auto-complete TAB
としてもダメ。
「最後は『TAB』じゃなくて『RET』だよなぁ」と
M-x auto-install-batch RET auto-complete RET
としてもダメ。
正誤表にも載っていません。
「auto-install-batch」を実行後に気付いたのが、
Download from 'http://www.rubyist.net/~rubikitch/archive/auto-install-batch-list.el' successful.
と「*Messages*」に表示されること。
思い出したのが、色々調べている間にGoogle先生がこんな著者のTweetを発掘してくれていたこと。
M-x auto-install-batchを実行するたびにauto-install-batch-listを取得するようにした。これでファイルの変更に追随できる。(install-elisp-from-emacswiki "auto-install.el")
それで、このURLを開いて見た。
なんとなく、「ひとつのキーワードで複数のelispをインストールするための設定」なんじゃないかと推測しました。
この「auto-install-batch-list.el」の中から「auto-complete」の文字を探すと次の用なS式が...。
         ("auto-complete development version" nil nil
          (
           "http://github.com/m2ym/auto-complete/raw/master/popup.el"
           "http://github.com/m2ym/auto-complete/raw/master/fuzzy.el"
           "http://github.com/m2ym/auto-complete/raw/master/auto-complete.el"
           "http://github.com/m2ym/auto-complete/raw/master/auto-complete-config.el"
           ))
「あれ?『auto-complete』じゃなくて『auto-complete development version』なの?」と思った瞬間、気付いたのがインストール方法の最後の「TAB」。
「これって補完の『TAB』じゃない?」と思って色々調べていたら、ありました。
それもさっき見ていた正誤表の中に。
<2010-09-04 土> 本当に申し訳ありません。load-pathの設定を最初にやらないとrequireでエラーが起きます。正しくはこれです。

;; auto-installによってインストールされるEmacs Lispをロードパスに加える
;; デフォルトは ~/.emacs.d/auto-install/
(add-to-list 'load-path "~/.emacs.d/auto-install/")
(require 'auto-install)
;; 起動時にEmacsWikiのページ名を補完候補に加える
(auto-install-update-emacswiki-package-name t)
;; install-elisp.el互換モードにする
(auto-install-compatibility-setup)
;; ediff関連のバッファを1つのフレームにまとめる
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
この中の
;; 起動時にEmacsWikiのページ名を補完候補に加える
(auto-install-update-emacswiki-package-name t)
を「C-c C-e」した後、
M-x auto-install-batch RET auto-complete TAB
とすると、「auto-complete」が補完されて「auto-complete development version」に!
最後に「RET」でelispのダウンロードが開始され、「C-c C-c」でコンパイル。
やっとインストールに成功。
コメントにインストールコマンドを書いて「C-c C-e」で実行して確認。
;; (auto-install-batch "auto-complete development version")
動きました。
時間がかかったけど色々勉強になりました。
苦心の成果は全部GitHubにアップしています。
「Emacsテクニックバイブル」で自分のEmacsの設定が進化していくので楽しいです。
気になった方はこちらをどうぞ。

2010年09月24日

TextMateのsnippetから、YASnippetのsnippetを生成する方法(一部失敗)

Emacsテクニックバイブル(※1)を読んでYASnippetの存在を知る
Java用のsnippetを探すも見つからない
仕方がないので、YASnippetのsnippetの作り方を調べる(※2)
YASnippetのテンプレートの文法はTextMateのものにかなり似ていることを知る(※3)
TextMateのsnippetから、YASnippetのsnippetを生成できるかもと妄想する
TextMateのsnippetの書き方を真剣に調べ、かなり高機能なことに気付く(※4)
YASnippetのsnippetの書き方の英文を、変換方法を考えながらがんばって読む(※5)
もう少しで読み終えると喜んでいたら、snippetの書き方の最後にTextMate形式からの変換方法が書かれているのに気付く(※6) <=今ココ

丸一日かけて変換ツールの構想を練ってたのに...。
これだけ文法が似ていてたら、既に変換ツールがあると考えるべきだった。
※1 この本のおかげで変態的に便利なEmacsの環境が出来上がりつつあります。お勧めです。
※2 全て英語です。
※3 「snippetのテンプレートの文法はシンプルだけどもパワフルで、TextMateのものにとても似ている」と書いています。
※4 正規表現で置換できたり、Shellの実行結果を埋め込めたりできます。
※5 こちらもEmacs-lispの結果を使えたりして高機能です。
※6 しかもツールのダウンロード元は公式サイト。
textmate_import.rbをインストール
やったことは、textmate_import.rbをダウンロードしてヘルプの表示まで。
途中で、plistとchoiceのgemが足りなかったのでインストールしている。
% cd ~/dotfiles/emacs-config/download
% wget http://yasnippet.googlecode.com/svn/trunk/extras/textmate_import.rb
(略)
% ruby textmate_import.rb --help
textmate_import.rb:225: warning: parenthesize argument(s) for future version
textmate_import.rb:226: warning: parenthesize argument(s) for future version
textmate_import.rb:329: warning: parenthesize argument(s) for future version
textmate_import.rb:334: warning: parenthesize argument(s) for future version
/Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- plist (LoadError)
    from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
    from textmate_import.rb:18
% gem install plist
(略)
% ruby textmate_import.rb --help
textmate_import.rb:225: warning: parenthesize argument(s) for future version
textmate_import.rb:226: warning: parenthesize argument(s) for future version
textmate_import.rb:329: warning: parenthesize argument(s) for future version
textmate_import.rb:334: warning: parenthesize argument(s) for future version
/Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- choice (LoadError)
    from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
    from textmate_import.rb:19
% gem install choice
(略)
% ruby textmate_import.rb --help
textmate_import.rb:225: warning: parenthesize argument(s) for future version
textmate_import.rb:226: warning: parenthesize argument(s) for future version
textmate_import.rb:329: warning: parenthesize argument(s) for future version
textmate_import.rb:334: warning: parenthesize argument(s) for future version
Usage: textmate_import.rb [-dofpqbg]

Standard Options:
    -d, --bundle-dir=PATH            Tells the program the directory to find the TextMate bundle directory
    -o, --output-dir=PATH            What directory to write the new YASnippets to
    -f, --file=SNIPPET FILE NAME     A specific snippet that you want to copy or a glob for various files
    -p, --pretty-print               Pretty prints multiple snippets when printing to standard out
    -q, --quiet                      Be quiet.
    -b, --convert-bindings           TextMate "keyEquivalent" keys are translated to YASnippet "# binding :" directives
    -g, --info-plist=PLIST           Specify a plist file derive menu information from defaults to "bundle-dir"/info.plist

Common options: 
        --help                       Show this message
textmate_import.rbを使ってみる
TextMateの公式と思われるGitHubのページには、色々なbundleがupされている。
ここから、Java用のbundleをダウンロード。
java.tmbundleのページの右上の「Download Source」をクリックして、ファイル形式を選択する。
ここでは、「TAR」を選択。
そして解凍。
% tar zxvf textmate-java.tmbundle-83afc50.tar.gz 
(略)
textmate-java.tmbundle-83afc50/Snippets/
(略)
textmate-java.tmbundle-83afc50/info.plist
(略)
変換してみる。
% ruby textmate_import.rb -d textmate-java.tmbundle-83afc50/Snippets -o java-mode -g textmate-java.tmbundle-83afc50/info.plist 
textmate_import.rb:225: warning: parenthesize argument(s) for future version
textmate_import.rb:226: warning: parenthesize argument(s) for future version
textmate_import.rb:329: warning: parenthesize argument(s) for future version
textmate_import.rb:334: warning: parenthesize argument(s) for future version
Will try to convert 40 snippets...
(略)
textmate_import.rb:154:in `main_menu_to_lisp': undefined method `+' for nil:NilClass (NoMethodError)
    from textmate_import.rb:476
なんかエラーでた。
変換前の「.tmSnippet」と「.yasnippet」の数は共に40。
もしかして使えるかもしれないと思い、「java-mode」ディレクトリをYASnippetのsnippetディレクトリ内に移動。
% mv java-mode yasnippet-0.6.1c/snippets/text-mode/cc-mode/
念のため、Emacsを再起動し、javaファイルを開いた後、「cl」と入力し「M-x yas/expand」を実行してみる。
class TM_FILENAME/(.*?)(\..+)/TM_FILENAME/(.*?)(\..+)/// extends Parent implements Interface {
    
    }
うまく行っていない。
「TM_」で始まるのは、TextMateの環境変数のはず。
class.tmSnippetとclass.yasnippetの中身を見てみる。
% cat textmate-java.tmbundle-83afc50/Snippets/class.tmSnippet
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>content</key>
    <string>class ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} ${2:extends ${3:Parent} }${4:implements ${5:Interface} }{
    $0
}</string>
    <key>name</key>
    <string>class</string>
    <key>scope</key>
    <string>source.java</string>
    <key>tabTrigger</key>
    <string>cl</string>
    <key>uuid</key>
    <string>E9ED01EA-E83B-4322-BD9D-39C88FB8C237</string>
</dict>
</plist>
% cat yasnippet-0.6.1c/snippets/text-mode/cc-mode/java-mode/class.yasnippet
# -*- mode: snippet -*-
# uuid: E9ED01EA-E83B-4322-BD9D-39C88FB8C237
# key: cl
# contributor: Translated from textmate snippet by PROGRAM_NAME
# name: class
## condition: "
# --
class ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} ${2:extends ${3:Parent} }${4:implements ${5:Interface} }{
    $0
}% 
ファイル名の取得処理方法と、ファイル名から拡張子を外して既定値にする正規表現による変換処理方法が、TextMateの形式のままだった。
TM_FILENAMEは何ヵ所あるのかと調べてみたら、3ヵ所だけ。
% grep TM_FILENAME yasnippet-0.6.1c/snippets/text-mode/cc-mode/java-mode/*
yasnippet-0.6.1c/snippets/text-mode/cc-mode/java-mode/class.yasnippet:class ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} ${2:extends ${3:Parent} }${4:implements ${5:Interface} }{
yasnippet-0.6.1c/snippets/text-mode/cc-mode/java-mode/interface.yasnippet:interface ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} ${2:extends ${3:Parent} }{
yasnippet-0.6.1c/snippets/text-mode/cc-mode/java-mode/test case.yasnippet:public class ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} extends ${2:TestCase} {
他の変数の変換はどうなっているのかと元のbundle内を調べてみたら同じく3ヵ所。
% grep TM textmate-java.tmbundle-83afc50/Snippets/*
textmate-java.tmbundle-83afc50/Snippets/class.tmSnippet:    <string>class ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} ${2:extends ${3:Parent} }${4:implements ${5:Interface} }{
textmate-java.tmbundle-83afc50/Snippets/interface.tmSnippet:    <string>interface ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} ${2:extends ${3:Parent} }{
textmate-java.tmbundle-83afc50/Snippets/test case.tmSnippet:    <string>public class ${1:${TM_FILENAME/(.*?)(\..+)/$1/}} extends ${2:TestCase} {
全然変換できてない。
環境変数には全く対応していないのかと思ったけど、codeの中には「TM_」の文字がいくつか見つかった。
それでも、正規表現にも対応していないのは結構致命的かも...。
elispの正規表現は独特な方言らしいし...。

ゼロからツールを作ろうにも、AppleのBundleの仕様を調べるのも大変だから、textmate_import.rbを読んで改造していくのが良いのかなぁ...。
Google

タグ クラウド