header

2014年2月22日土曜日

EmacsでJavaの設定

Clojureを勉強しようとおもって、まずはJavaからとおもいEmacsでJavaの設定
をととのえた。でもJavaについてはまだよくわかっていないので変なことをし
ているかもしれない。


できるようになったこと


  • emacs-eclim を利用しauto-completeのコード補完
  • popupでeclimのエラーを表示
  • quickrunでコードの実行

eclim?

説明が前後してしまったけどeclim自体はeclipseをvimから使うプロジェクト
です。これのおかげでeclipse並のコード補完が実現できてるらしい。
(eclipseは10秒くらい起動してすぐ閉じてしまったのでほとんど知らない…)

なぜ僕がemacsから使えるかというと、emacsからもeclim使えるようにする
emacs-eclimという拡張を利用しました。(これより以下のeclimという用語は
emacs-eclimを指しています)
eclipse自体の機能を把握してないのでアレですが、projectの作成やリファク
タリングなどeclimから実行できるようです。


環境構築方法

多分日本語では、あまり情報がなさそうなので自分がやったことなどを書いて
おきます。
英語ですが、このサイト が一番参考になりました。(Installationの項が詳し
く書いてあります)


eclipseのダウンロード

僕はubuntu 12.04を利用していますが、apt-getからのインストールでは
うまくeclimをビルドできなかったので、参考サイトのように
ここの download linkからダウンロードしました。
参考(OSを確認してインストールしてください):

INSTALL_DIR=/opt/local
mkdir -p $INSTALL_DIR
cd $INSTALL_DIR
curl -o eclipse.tar.gz http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/juno/SR1/eclipse-java-juno-SR1-linux-gtk-x86_64.tar.gz
tar xvzf ./eclipse.tar.gz

eclim

続いてeclimのインストール(上の続きから)

git clone git://github.com/ervandew/eclim.git
cd eclim
ant clean deploy -Declipse.home=$INSTALL_DIR/eclipse

これでeclipseのあるディレクトリにeclimdが置かれるようになります。


emacs-eclim

これはEmacsに慣れてる人なら特にインストールの説明は必要ないとおもうの
ですが、、、
M-x list-package で確認したらemacs-eclimとあったので、MELPAから手軽に
インストールできると思います。
僕はel-getからインストールしました。


Emacsの設定

僕はinit_というprefixをつけて設定をわけています。
使えそうなところだけ抜きだす使いかたでもいいと思います。

init_java.el:

(defun my/java-init ()
(cond
((and
(not (string-match "^\\*Org Src .*\\*" (buffer-name)))
(string-match "/src/.*\\.java$" buffer-file-truename)
(my/boot-eclim)
(eclim--project-name))
(eclim-mode)
(ac-emacs-eclim-config))
(t
(require 'init_flymake-java)
(flymake-mode t))))

(add-hook 'java-mode-hook 'my/java-init)

project管理しているディレクトリの場合は、eclimdを起動する設定
そうでなければ、flymakeで利用するだけ
(もっとましなチェック方法がありそう。。。)

init_eclim.el:

(with-no-warnings (require 'eclim))
;; ECLIPSE_HOMEはeclipseのあるディレクトリを設定してください
(setq eclim-eclipse-dirs `(,(getenv "ECLIPSE_HOME"))
eclim-executable (eclim-executable-find))

(defconst eclimd-executable (format "%s/eclimd" (getenv "ECLIPSE_HOME")))
(require 'eclimd)

(defun my/boot-eclim ()
(let* ((boot-p (zerop (shell-command "pgrep eclimd")))
(answer (and (not boot-p) (y-or-n-p "Use eclim? "))))
(when answer
(call-interactively 'start-eclimd))
answer))

;; auto-completeにeclimの補完を表示
(require 'ac-emacs-eclim-source)
;; C-M-iを無効化
(define-key eclim-mode-map (kbd "C-M-i") nil)

(defadvice eclim-problems-highlight
(around avoid-this activate)
(when (eq 'java-mode major-mode)
ad-do-it))

eclim用の設定、eclimを利用するとeclipseの起動の重さがそのまま反映され
るデメリットもあるので起動するか尋ねるようにした。

init_flymake-java.el:

(require 'flymake)

(defun flymake-simple-generic-init (cmd &optional opts)
"Syntax check function for without Makefile.
CMD means command and OPTS means options."
(let* ((create-tempfile
(lambda ()
(let* ((temp-file
(flymake-init-create-temp-buffer-copy
(case major-mode
(java-mode 'flymake-create-temp-with-folder-structure)
(t 'flymake-create-temp-inplace))))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(if (file-exists-p local-file)
(expand-file-name local-file)))))
(file+opts (push (funcall create-tempfile) opts)))
`(,cmd ,file+opts)))

(defun flymake-simple-make-or-generic-init (command &optional options)
"Do syntax check function.
If makefile is exists, then do `flymake-simple-make-init'.
Otherwise, do `flymake-simple-generic-init' function with COMMAND and OPTIONS."
(if (or (file-exists-p "Makefile") (file-exists-p "makefile"))
(flymake-simple-make-init)
(flymake-simple-generic-init command options)))

(add-hook 'java-mode-hook
(lambda ()
;; TODO: add flymake-simple-ant-java-init?
(defun flymake-simple-make-java-init ()
(flymake-simple-make-or-generic-init "javac" '("-Xlint")))))

eclimを利用しない場合はflymakeでエラーチェックするようにしている。
冗長な書き方をしているのは、c/c++でflymakeを利用する時用。
(今の時代はflycheckがありますが、もったいなくてなんか消せない…)

init_quickrun.el:

(require 'quickrun)
;; override Java
(quickrun-add-command
"java"
'((:compile-only . "javac -source 1.6 -target 1.6 -Werror %o %s")
(:exec . ("javac -source 1.6 -target 1.6 %o %s" "%c %N %a")))
:override t)

設定しなくてもquickrunでJavaのコード実行できる人は必要ない設定です。
javacとjavaのバージョンがちがくて実行ができない場合、上の1.6と書いてあ
る部分を変えて設定してみてください。


eclimのエラーチェックをpopupで

emacs-eclim標準でエラーチェックをやってくれるのですが、
表示方法が別バッファ表示のようなので、僕はあんまりすきな感じでなかったので
flycheck-tip というflycheckのエラーをpopup.elのツールチップで表示する
拡張にねじこみました。
MELPAからインストールできます。

僕は mykie.el というEmacsのキーバインドを登録するのを便利にする拡張を利
用しているので設定はこんな感じになっています(mykie.elのステマ):

(require 'mykie)
(require 'error-tip)

(setq mykie:prefix-arg-conditions
(append mykie:prefix-arg-conditions
'((:C-u&error . (error-tip-error-p)))))

(mykie:set-keys nil
"C-l"
:default (recenter-top-bottom)
:C-u&error (mykie:do-while
"n" (error-tip-cycle-dwim)
"p" (error-tip-cycle-dwim-reverse)))

上のコードの意味は、C-u C-lを押したときにエラーが出ていれば
そのエラーをpopup.elのツールチップで表示します。
他のエラーをみたければ 'n' または 'p' キーを押すことで、
移動後エラーを表示します。それ以外のキーを押すと通常の入力モードに戻り
ます。
エラーが出てなければ、通常どおりrecenter-top-bottomを行います。

ちなみにerror-tip-cycle-dwim関数は、flycheck-modeならflycheck-tip,
eclim-modeならeclim用のエラー表示、flymakeを利用してたらflymakeのエラー
表示をする便利関数です。(いずれもpopupでエラー表示します)


eclimのメリット、デメリット

コード補完とエラーチェックは便利だと思うけど、eclimdを起動するのは
eclipseを起動するのと同じくらい時間がかかるので好みがわかれる気がしま
す。
僕はrevert-bufferをbuffer移動するときに実行していたんですが、
eclimを使うようにするとなんか重くなる感じがするんですよね。。。
git-gutter+の情報の更新のためだったので、git-gutter+-refleshで
なんとかなりましたが、、、
普段revert-bufferを頻繁に利用している人は注意が必要かもしれません。


注意事項


  1. 自分の設定をサルベージして書いたものなので、もしかしたらそのままでは動
    かない可能性もあります。。。
  2. auto-completeは有名なパッケージなので設定は書きませんでした。
  3. flycheck-tip/error-tipはflycheckとeclimの同時起動は想定していません
    のでどちらかはoffにしてください。

その他メモ

今回は入れてないけど、drip, flycheck-java, java-lookup
とかもあるらしい。(flycheck-javaはeclimがあればいらないと思うけど)
そういえば、malabar-modeとかどうなんだろう。。。


おわり

ほかにも便利な設定などあればコメントいただけるとうれしいです:)


2014年2月8日土曜日

mykie.el v0.2.1リリースし(て)ました。

mykie-v0.2.1リリースしました。というかしてましたというか、野放しというか。。。
英語のREADME.mdのほうはなおしてたのですが、日本語の情報はとくになにも
してなかったので紹介記事を書きたいとおもいます。


mykie.elとは

カーソルのポイントやflycheckのエラーの状態などに応じて
呼び出す関数を柔軟に変えることができるEmacs用の拡張です。
またユーザーの独自の条件も簡単に追加できます。


0.1.x系から変わったところ


  • キーを登録するときのクオートがいらなくなりました
  • 括弧つきの記法ができるようになりました
  • :C-u! :fileキーワードがつかえるようになりました
  • lazy order -> fuzzy orderになまえがかわりました
  • デフォルトでfuzzy orderを利用するようになりました
  • デフォルトキーワードとして"t"を利用できるようになりました。
  • multiple-cursors.elからmykieを利用できない問題があったのですが、
    mykie.elをロード前のキーバインドを利用するようにしました
  • helm-show-mykie-keywordsでmykieで利用できるキーワードがみれるように
    なりました
  • キーワードを追加するときの方法がかわりました

キーを登録するときのクオートがいらなくなりました。

以下は例ですが、mykie:set-keysでwith-self-keyを利用する場合も
クオートがいらなくなっているので注意してください。

;; 旧バージョン
(mykie:global-set-key "C-j" :default '(message "クオート書いちゃダメ絶対"))
;; 新バージョン
(mykie:global-set-key "C-j" :default (message "hello"))
(mykie:set-keys with-self-key ; <- これもクオートいらなくなりました
"a" :C-u (message "pushed a after pushed C-u"))

括弧つきの記法ができるようになりました。

prognを指定したくないときに便利かもしれません。

(mykie:global-set-key "C-j"
(:default (message "default")
(message "default2行目"))
(:C-u (message "default")))

追加されたキーワード:C-u! And :file


  • :C-u!は:C-uとおなじですが、関数を呼び出す前にcurrent-prefix-arg変数を
    nilに設定します。移動系関数でcurrent-prefix-argの数値によって挙動を変える
    関数の場合設定すると便利かもしれません。
  • :fileは`ffap-file-at-point'関数を呼び出します。
    結果はmykie:current-file変数に保存されます。

lazy orderからfuzzy orderに名前がかわりました

適当に名前考えてあとからちょっと違うなと思って変えました。
どういう機能かというと、以下のような設定で

(mykie:global-set-key "C-j"
:default (message "default")
:C-u&url (message "ポイントがURLだったらよばれる")
:C-u&eolp (message "ポイントがend of lineだったらよばれる")
:C-u (message "default"))

:C-u&urlと:C-u&eolpが同時に条件をみたしていた場合、上にあるキーワードを
優先して実行する機能です。(ユーザーが設定するまでどちらを優先するかわ
からないのでfuzzyとしました)
旧バージョンでは、C-u*2がしたの方に設定されていると呼ばれないなどのめ
んどくさい仕様だったのですが、現在は:C-u&somethingより:C-u*2や:M-3など
のcurrent-prefix-argの数字を意図的に変えたものを優先するようにしている
のでとくに意識しなくても意図したものがよばれないなどの不具合は出ないの
ではと思います。


デフォルトでfuzzy orderを利用するようになりました

上記のとおりそこそこ便利に設定できる機能だと思うので、デフォルトでこの
機能がオンとなるようにしました。
もし無効化したい場合はmykie:use-fuzzy-order変数にnilを設定してください。


:defaultキーワードとして"t"を利用できるようになりました。

case or cond文のようにすべての条件にマッチしなかった場合は、
:defaultのかわりにtを設定できるようにしました。

(mykie:global-set-key "C-j"
t (message "default"))

multiple-cursors.elからmykieを利用できない問題について

これは解決したわけではないのですが、mykieをロードする前のキーバインド
を利用するようにしました。(pull-requestはウェルカムです)


helm-show-mykie-keywordsでmykieで利用できるキーワードがみれるようになりました

helmがロードできる状態であれば利用できます。


キーワードを追加するときの方法がかわりました。

もしmykieの過去のバージョンを使っている場合は、そのままでは利用できません。
すいません。ただ新しい設定方法のほうがEmacsっぽいので気に入っていただ
けるのではと思います。。。
以下はいくつかの条件(キーワード)を追加する例ですが追加するのがひとつの
場合はpush関数を利用してもいいと思います。

(setq mykie:normal-conditions
(append mykie:normal-conditions
'((:org-src . (or (org-in-src-block-p)
(org-src-edit-buffer-p)
(string-match "^\\*Org Src .*\\*" (buffer-name))))
(:org-mobile . (org-mobile-dir-p))
(:org-header . (and (eq 'org-mode major-mode)
(org-on-heading-p)))
("^:skk-\\(on\\|active\\)$" . (mykie:get-skk-state)))))

例の一番下の:skk…の部分だけ異質ですが、このmykie:get-skk-stateという
関数は条件をみたしていた場合、:skk-onか:skk-activeというキーワードをか
えします。
条件をチェックして複数のキーワードを返す可能性がある場合に利用してください。
(mykie.elの中ではmajor-mode変数にあわせてキーワードを作ったりしています)

追加できる条件変数には

  • mykie:region-conditions
  • mykie:prefix-arg-conditions*
  • mykie:prefix-arg-conditions
  • mykie:normal-conditions

があります。region-conditionsに新たに追加する場合は、use-region-pなど
のリージョンがアクティブかどうかを確認する条件を含める必要はありません。
同様にprefix-arg-conditionsの方もcurrent-prefix-argがnilでないことを確
認する条件を追加する必要はありません。
(上の変数に応じてチェックする条件が決まっています)

余談ですが、上記の変数のリストを含むmykie:group-conidtions変数が新たに
追加されたのですが、このなかの変数の順番で条件を評価します。
なのでこの変数のなかの順番を変更することでC-u*2などの優先度を変更できます。


インストール、その他の機能(過去記事のほぼコピー)


インストール

MELPA に登録したのでM-x package-install RET mykieでインストールできる
と思います。もし MELPA をpackage-archivesに登録してなければ以下を
スクラッチバッファなどで評価してから試してください。

(add-to-list 'package-archives
'("melpa" . "http://melpa.milkbox.net/packages/"))
(package-initialize)

el-getをつかっているなら以下のコードを評価して、M-x el-get-install RET
mykie でインストールできると思います。

(push '(:name mykie-el
:type git
:url "https://github.com/yuutayamada/mykie-el.git"
:load-path ("./lisp"))
el-get-sources)

使い方

インストールができたら、init.el などで設定します。
下は簡単な設定例

(require 'mykie) ; <- これはmykie.elを読み込む必須の設定
;; major-modeのキーをglobal-mapのmykieの同じキーで上書きするかどうか
;; の設定。上書きしますが元のメジャーモードキーは:default用の関数に
;; 登録されるのでそのまま使用できます。
;; defaultではnilとなっています。
(setq mykie:use-major-mode-key-override t)
;; 上のメジャーモードの上書き設定の変更や条件の変更をおこなった場合は
;; ↓これを呼び出してください。
(mykie:initialize)
;; mykie:set-keysの第一引数にnilを指定するとグローバルマップに登録され
;; ます。emacs-lisp-mode-mapと指定して特定のメジャーモードを指定することも
;; できます。
(mykie:set-keys nil
"C-a"
:default (beginning-of-line)
:C-u mark-whole-buffer
"C-e"
:default (end-of-line)
:C-u (message "Hello")
;; ... You can add more keybinds
)

上の例はC-a, C-eキーにC-uを押した時の設定を追加します。

関数の指定方法についてですが、上の例のようにリスト形式で渡す方法のほかに
query-replace-regexpのようにシンボルで渡すこともできます。
この場合そのシンボルがインタラクティブだった場合、call-interactively
関数からそのシンボルを呼び出します。(コマンドとして実行する)


指定できるキーワード引数

以下は現在の指定できるキーワード引数です。
最新の情報は GitHubのmykieのページ に書くつもりなので、そのうち情報が古
くなるかもしれません。
helmが利用できればhelm-show-mykie-keywords関数がつかえるので現在利用で
きるキーワードをみることができます。

KEYWORDDESCRIPTION
:defaultデフォルトで呼ばれる
:C-uC-uをそのキーを押す前に押すと呼ばれる
:C-u!C-uと同じだけど、current-prefix-argをnilにする
:C-u*NC-uをN回押したとき呼ばれる
:M-Nメタ(alt)キー + [0-9] の数字を押した時に呼ばれる
:regionリージョン選択中に呼ばれる
:region&C-u:regionと:C-u条件をみたすとよばれる
:repeat同じコマンドを同じポイントで行うと呼ばれる
:bolpbeginning of line で呼ばれる
:eolpend of line で呼ばれる
:bobpbeginning of buffer でよばれる
:eobpend of buffer で呼ばれる
:C-u&bolp:C-uと:bolpの条件をみたすとよばれる
:C-u&eolp:C-uと:eolpの条件をみたすとよばれる
:C-u&bobp:C-uと:bobpの条件をみたすとよばれる
:C-u&eobp:C-uと:eobpの条件をみたすとよばれる
:email現在のポイントが e-mail だと呼ばれる
:C-u&email:C-uと:emailの条件をみたすとよばれる
:url現在のポイントが URL だと呼ばれる
:C-u&url:C-uと:urlの条件をみたすとよばれる
:MAJOR-MODEemacs-lisp-mode などの 現在の major-modeに マッチ
:C-u&MAJOR-MODE:C-uと:MAJOR-MODEの条件をみたすとよばれる
:region&MAJOR-MODE:regionと:MAJOR-MODEの条件をみたすとよばれる
:progプログラミングモードに関連したバッファだと呼ばれる
:C-u&prog:C-uと:progの条件をみたすとよばれる
:region&prog:regionと:progの条件をみたすとよばれる
:errflymakeかflycheckのエラーがあるときよばれる
:C-u&err:C-uと:errの条件をみたすとよばれる
:region&err:regionと:errの条件をみたすとよばれる
:minibuffミニバッファでよばれる
:readonlyread only だとよばれる
:commentコメントか文字列だとよばれる

以下は関数の指定ではなく、違う効果を持ったキーワード引数

KEYWORDvalueDESCRIPTION
 (example)<30>
:cloneKEY as stringClone mykie's functions to other KEY. this function is convenient if you use Emacs either situation terminal and GUI. Because terminal Emacs can't use partial keybind such as C-;, this keyword can clone same functions to another key without :default function. For example: :clone ";" (<- if you want to clone origin key to ";")
 "a" 
:deactivate-regionsymboldeactivate selecting region after mykie executed command. You can specify this t, 'region, 'region&C-u.
 t 
:region-handle-flagsymbolDo copying or killing before command executing. This function is convenience if you want to use kill-ring's variable. But there is mykie:region-str variable that always store region's strings.
 'copy or 'kill 

:cloneはself-insert-commandに:default以外のコマンドを引き継ぐ設定です。
どういう時に便利かというと、ターミナルではC-;は使えないので";"キーで
リージョンに指定した関数を使いたいというときに便利です。
ユーザー側からすると同じキーバインドが使えてると錯覚できます。
(:defaultの設定は使えないですが)

(mykie:set-keys nil
"C-;"
:default 'newline-and-indent
:region 'comment-dwim
:clone ";")

その他の例

mykie.el のページにキーワードを使った例がありますのでそちらを参考にして
ください


メジャーモードのキーの上書き

最近のmykie.elに実装された機能ですので不具合があるかもしれません。

(setq mykie:use-major-mode-key-override t)
(mykie:initialize)

のようにしないと設定されないので、つかいたくなければ上記の設定をしない
でください。

mykie:use-major-mode-key-overrideには 'both, 'global, 'self or t が設
定できます。'bothはself-insert-commandとglobal-mapのC-jなどのprefix付
きのコマンド両方、'globalは C-j などのprefix付きのglobal-mapのコマンド、
'self と t は self-insert-command(a-z0-9など) を意味します。

目的: major-modeのキーバインドにmykieのglobal-mapのキーを埋め込もうというの
が目的です。

;; You can specify 'both or 'global 'self or t to
;; mykie:use-major-mode-key-override.
;; 'both means use overriding major-mode keys both case.
;; 'global means use overriding major-mode keys by global-map's keys
;; without self-insert-command keys.
;; 'self means use overriding major-mode keys by self-insert-command keys.
;; if you set nil, then don't overriding major-mode key.
;; `mykie:use-major-mode-key-override' is nil by default.
(setq mykie:use-major-mode-key-override 'both)
(mykie:initialize)
(mykie:set-keys nil ; <- nil means registering global-map
"C-w" :default 'tetris :C-u (message "C-u+C-w"))

;; self-insert-commandはこの方法で登録する
(mykie:set-keys with-self-key
"1" :region sort-lines
"2" :region align
"3" :region query-replace
"c" :C-u (message "C-u+c"))

この機能を使うとき、self-insert-commandとそれ以外を意識する必要があります。
a-zや0-9などがself-insert-commandです。
それ以外というのは、global-mapのC-jやC-wなどprefix付きのコマンドです。
上の例はどちらの場合でも上書きする例です。

-Magitなど一部のパッケージでは、自動で上書きしてくれません。
僕のコードがバグってました。最新のmykie.elではmagitでも上書きしてくれ
ます。ごめんなさい

もしそういう場合どうしても上書きしたい場合、以下のようにしてください。
シンボル名でモード名を指定してください。

個別のモードごとに上書きの設定をしたい場合:

;; specify major-mode name as symbol.
(mykie:attach-mykie-func-to 'emacs-lisp-mode)

逆に MagitのようにC-uを押すと動作を変えるので上書きしてほしくない場合
以下のようにできます。

(setq mykie:major-mode-ignore-list '(magit-status-mode))

特定のキーだけに指定したい場合以下の指定方法もあります。

;; You can use below configuration. This way can specify specific keybind
;; only. you enjoy playing tetris.
(mykie:set-keys nil ; <- nil means registering global-map
"C-t"
:default tetris
:C-u (message "C-u+C-t")
:ignore-major-modes (emacs-lisp-mode)
:ignore-major-modes (diff-minor-mode))

おわり

region系の関数を開いてるキーにいれるだけでもまぁまぁ便利なのでよかった
らつかってください。


Popular Posts

Blogger templates

Blogger news