パスをまとめよう (Emacs Advent Calendar jp: 2011)
この記事は Emacs Advent Calendar jp: 2011 の4日目です。
昨日は @takaxp さんの emacs:org-tree-slide – PastelWiki でした。
明日は kbkbkbkb1 さんの Emacs は外部 elisp がなくても強い です。
楽しみですね!
コードを書き直しました 2012/11/13
本記事で紹介しているパスユーティリティのコードを書き直しました。
新しいコードは defpath.el を書きました « less ~/.emacs.d/init.el で紹介しています。
あわせてお読みください。
.emacs で使うパスを統一的な形にする
いろいろな拡張機能を導入したり、時には自分で Emacs Lisp を書いたりして、emacs をカスタマイズしていくことはとても楽しいのですが、面倒も増えてしまいます。
そのひとつにファイルやディレクトリのパス設定があります。
今回はその辺りについての自分が行っている設定を紹介します。
何が問題なの?
パスの設定は “~/emacs.d/hoge” と直接書いても大抵の場合は大丈夫かもしれませんが、Dropbox や USB メモリなどを使って自分の設定ファイル集を同期したり持ち歩いたりするときには、環境ごとに .emacs.d の位置が変わってしまい厄介です。
また、`expand-file-name’ や `concat’ を使ってパスの展開や連結をするのも面倒です。
簡単な例としてはこんなところでしょうか。
;; ベタ書き (add-to-list 'load-path "~/.emacs.d/lisp") (add-to-list 'load-path "~/.emacs.d/inits") ;; 展開 + 連結 (yas/load-directory (expand-file-name (concat "yasnippet/" "snippets") "~/.emacs.d/lisp"))
まとめる
コピペしたくなるようなコードはあまり好きじゃないのでまとめてしまいましょう。
せっかくまとめるので、気のきいた振る舞いをしてくれるとうれしいですよね!
ということで、自分は設定ファイルに以下のコードを書いています。
(defvar my:path-name-prefix "path/to/") (defvar my:path-name-suffix "") (defun my:concat-path (&rest path-list) (cond ((null (cdr path-list)) (car path-list)) (t (concat (file-name-as-directory (car path-list)) (apply #'my:concat-path (cdr path-list)))))) (defun my:create-path-name (path) (concat my:path-name-prefix path my:path-name-suffix)) (defun my:create-path-var (path &optional val) (eval `(defvar ,(read (my:create-path-name path)) ,val))) (defun my:create-path-func (path) (eval `(defun ,(read (my:create-path-name path)) (&rest arg) (expand-file-name (apply #'my:concat-path (cons ,(read (my:create-path-name path)) arg)))))) (defun my:create-path (path &optional val) "PATHに関する変数と関数を作成します。" (my:create-path-var path val) (my:create-path-func path))
使い方
使い方は簡単です。
例えば .emacs.d であれば、
(my:create-path "emacs.d" "/home/hoge/.emacs.d")
とすれば ok です。
これで、 `path/to/emacs.d’ という変数と関数が用意されます。
あとは出来上がった変数と関数を使うだけです。
これは説明するよりも下を見てもらったほうが早いでしょう。
path/to/emacs.d ; => "/home/hoge/.emacs.d" (path/to/emacs.d) ; => "/home/hoge/.emacs.d" (path/to/emacs.d "lisp" "lib") ; => "/home/hoge/.emacs.d/lisp/lib" (path/to/emacs.d "inits/") ; => "/home/hoge/.emacs.d/inits/" (path/to/emacs.d "..") ; => "/home/hoge"
どうでしょうか、用意された変数には設定したパスが格納されていて、その場所を起点にパスを表現したいときは関数の引数につなげたいパスを与えるだけで展開してくれます。
使い方を統一するという面ではすべて関数呼び出しで使うほうが良さそうですね。
- ちなみに
末尾に “/” が付いているときだけ、 “/” を残すようになっています。
末尾に “/” を期待する拡張機能もこれで大丈夫でしょう。
あと、 `my:create-path’ の2番目の引数はオプションなのでなくても構いません。あまりおすすめはしませんが、あとで `setq’ すれば ok です。
.emacs.d をポータブルに
パスに関する設定が書きやすくなったので(思いのほか長くなってしまいましたが)、今度は設定ファイルの所在をもとに各パスを設定できるようにします。
ファイル自身のディレクトリ名の取得方法は、下記のページを参考にさせてもらいました。
- hazimarino: Emacs設定ファイルのディレクトリを取得し、変数に入れる(ファイル自身のディレクトリ名を取得)
http://hazimarino.blogspot.com/2010/11/emacs.html
.emacs.d のパスを取得、設定する
これは、次のようにすれば ok です。
ただし、 init.el が .emacs.d の中にあると仮定しています。
その辺りは自分の環境に合わせて変更してください。
(my:create-path "emacs.d" (file-name-directory (or (buffer-file-name) load-file-name)))
つぎに、それをもとに次のような感じで設定していきます。
(※これは例です)
(my:create-path "lisp" (path/to/emacs.d "lisp")) (my:create-path "inits" (path/to/emacs.d "inits")) (add-to-list 'load-path path/to/lisp) (add-to-list 'load-path path/to/inits) (yas/load-directory (path/to/lisp "yasnippet" "snippets"))
これで設定は終わりです。
あとは、例えば Dropbox などの同期ソフトを使っていて本来の場所に .emacs.d がない場合は ~/.emacs あたりに Dropbox の中の .emacs.d/init.el を読み込むように書いておいたり、
外部のマシンで自分の設定を使いたくなったら、素の emacs で .emacs.d/init.el を開いて `eval-buffer’ などすれば自分の設定を使えるでしょう。
- おまけ
`user-emacs-directory’ を設定しておくとちょっとだけ幸せになれるかもしれません。(setq user-emacs-directory path/to/emacs.d)
`user-emacs-directory’ は Emacs23 から使えるらしい変数です。
.emacs.d のパスを示す変数で、これをもとにヒストリなどを保存してくれる拡張機能があるので自分は設定しています。
それでは。
これはおもしろいアイデアですねー。
幸い僕は母艦とネットブックの環境がありますが、
シンボリックリンクなどでパスは共通になるようにしています。
コメントありがとうございます。
Emacsの設定はEmacs内で完結させたかったので、僕はこのように設定しています。
でも、シンボリックリンクを使った方法のほうがメジャーなようですね。