Emacs Lispを書くときのyasnippetやauto-completeの設定など(もしくは関西Emacs勉強会の続き)

またまた時間が経ってしまいましたが、第5回関西Emacs勉強会の記事の続きです。
プレゼンでEmacs Lispを書くときにこんな風にyasnippet.elとauto-complete.elを使ってますとの紹介をしましたが、詳しい設定はブログでと言ったままでした。
ようやく公開です。

Emacs勉強会を見ていない人のために要点をまとめると

問題

yasnippet便利!!でも…
1. 何を登録したのか忘れる

  • 似たもの (defun defvar)
  • 環境 (会社 or 自宅)

2. どの省略形で発動するかを忘れる

  • 短いほうがうれしいけど
  • 展開後と大きく違うと忘れる
  • 括弧は不要?必要?
    • (不要なのにつけると)括弧が二重に展開
    • (必要なのにつけないと)括弧がない
解決策

auto-completeで対応

  • 省略形は元のシンボル名(忘れない)
  • 途中まで打てば候補が出る(思い出せる)
  • 括弧がないときだけ括弧を挿入(悩まない)

という方針です。

yasnippetとauto-completeの設定

.emacsあたりに以下の設定を追加します。

;; add syntaxes for lisp function
(add-to-list 'yas/key-syntaxes "(w_.)" t)

;; save position before yasnippet execution
(defun yas/my-save-marker ()
  (setq yas/my-pre-marker (point-marker))
  (setq yas/my-post-marker (set-marker (make-marker) (1+ (point)))))

(add-hook 'yas/before-expand-snippet-hook 'yas/my-save-marker)

;; swap ac-source-yasnippet and ac-source-functions
(defun ac-emacs-lisp-mode-setup ()
  (setq ac-sources (append '(ac-source-features ac-source-yasnippet ac-source-functions ac-source-variables ac-source-symbols) ac-sources)))

1つめの設定(yas/key-syntaxes)は(付きでも展開できるようにするための設定です。
2〜3つめの設定(yas/before-expand-snippet-hook) は挿入前後の位置に()があるかどうかを判断するためにマーカを仕込んでます。
4つめの設定(ac-emacs-lisp-mode-setup)はauto-completeでシンボル名とyasnippetの短縮形が重複するとシンボル名の補完が優先されてしまうので、優先順位を逆転させてます。ただ、これだと逆にシンボル名での補完ができなくなる問題があったりします。
(Eclipseみたいに)略語展開系とシンボルの補完は両方出てくれた方が嬉しい気がするので、[twitter:@m2ym]さんに要望をだしてみようかなと。

yasnippetスニペット

yasnippetスニペットはこんな感じです。最初の行と最後の行で空気を読んで括弧を入れたり入れなかったりします。

# -*- mode: snippet -*-
#name : function template
#contributor : Yuuki Arisawa
# --
`(if (eq ?\( (char-after (1- yas/my-pre-marker)))
     (delete-char 2) (delete-char 1))`
(defun $1 (${2:args})
  "Return
${2:$(mapconcat 'upcase (split-string (replace-regexp-in-string "&[a-z]+" "" yas/text)) " is\n")}"
  (interactive)
  $0
  )
`(if (eq ?\) (char-after (1- yas/my-post-marker)))
     (progn (forward-line -1) (delete-char -2)))`

id:kiwanamiさんの記事
yasnippet や emacs lisp の小ネタなど - 技術日記@kiwanami
を参考に引数の文字列からdocstringを生成するようにしてます。
後から引数の変更をした時にも追従したいけど、うまいやり方はあるのかな?知っている人はどなたか教えて下さい(なければeldocあたりを使って作ろうかな…)