- use-package 20170710.1234(in MELPA)
- A use-package declaration for simplifying your .emacs
概要
use-package マクロは、emacsのパッケージ設定を
劇的に簡潔にして読みやすくするマクロです。
@kai2nenobuさんも詳しい記事をお書きになりました。
以下の定番の記述がすごいすっきり書けるようになります。
- load-path
- キー割り当て
- autoload
- auto-mode-alist
- interpreter-mode-alist
- パッケージ読み込み前に行う処理
- パッケージ読み込み後に行う処理
- Emacsがアイドル状態に行う処理
- 一時的な設定の無効化
特にキー割り当てに関しては bind-key.el により
とてもすっきり記述できます。
作者はEmacs界の重鎮John Wiegley氏であり
彼は様々なプロジェクトに関わっています。
- EmacsWiki
- magit
- eshell (標準添付)
- org-mode (標準添付)
- pcomplete.el (標準添付)
- align.el (標準添付)
- remember.el (標準添付)
- isearchb.el (標準添付)
などなど、有名どころが多いです。
彼の名前が出てきたら安心してしまう僕がいるようです(笑)
インストール
パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。
(package-initialize) (setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/") ("melpa" . "http://melpa.org/packages/") ("org" . "http://orgmode.org/elpa/")))
初めてuse-packageを使う方は
以下のコマンドを実行します。
M-x package-install use-package
アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。
M-x package-install package-utils (初めてアップグレードする場合のみ) M-x package-utils-upgrade-by-name use-package
使い方
README.mdにいろいろ書いてあるのですが、
マクロなので、説明を読むよりも macroexpand で
展開結果を読む方が理解しやすいです。
(package-initialize) (require 'use-package) (use-package パッケージ名 キーワード 引数 キーワード 引数 ...)
requireの代わりにする
use-packageの一番シンプルな使い方は、
そのままrequireの代わりにすることです。
(use-package ruby-mode)
macroexpandすると…
(macroexpand '(use-package ruby-mode)) ↓ (progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'ruby-mode nil t)))) (if (and t t) (use-package-with-elapsed-timer "Loading package ruby-mode" (if (not (require 'ruby-mode nil t)) (message "Could not load package %s" "ruby-mode") nil nil nil t))))
progn の方を見てください。
eval-when-compile のくだりは、init.elをバイトコンパイルするときに
ruby-modeをrequireすることで正しくコンパイルされるための記述です。
実行時には関係ないので無視してください。
(require 'ruby-mode nil t)
は読み込みが失敗したらnilを返します。
よって、読み込みに失敗したときにメッセージが出るようになります。
複数のマシンでinit.elを共有していて、
インストールされていないパッケージがあったら
そのままその設定は使われないだけです。
:load-path: load-pathを指定する
パッケージ管轄外のEmacs Lispを使う際は
load-path を設定する必要がありますが、
:load-path キーワードを使えば一発です。
~/.emacs.d/ ( user-emacs-directory ) からの相対パスが指定できます。
(use-package ess-site :load-path "site-lisp/ess/lisp/"))
↓
(progn nil (add-to-list 'load-path "/r/.emacs.d/site-lisp/ess/lisp/") (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'ess-site nil t)))) (if (and t t) (use-package-with-elapsed-timer "Loading package ess-site" (if (not (require 'ess-site nil t)) (message "Could not load package %s" "ess-site") nil nil nil t))))
:bind : コマンドをglobal-mapに割り当てる
use-package.elは bind-key.el を内部で使っていて、
キー割り当てを簡単に記述できるようになっています。
たとえば、 ace-jump-mode と ace-jump-line-mode を
キーに割り当てる設定はこうです。
(use-package ace-jump-mode :bind (("C-." . ace-jump-mode) ("C-," . ace-jump-line-mode)))
これをmacroexpandすると…
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'ace-jump-mode nil t)))) (when t nil (autoload #'ace-jump-mode "ace-jump-mode" nil t) (autoload #'ace-jump-line-mode "ace-jump-mode" nil t) (progn nil (bind-key "C-." 'ace-jump-mode) (bind-key "C-," 'ace-jump-line-mode)) nil t))
ここでやってることは、 autoload の設定と
bind-key によるキー割り当ての設定です。
このようにbindで設定されたコマンドはすべてautoloadされます。
つまりC-.やC-,が押されるまで ace-jump-mode.el が
読み込まれないので起動が早くなります。
しかも、煩わしいautoloadの記述とは無縁になります!
なお、メジャーモードやマイナーモードのキーマップを設定するための
専用の記法は現在のところ用意されていないようです。
:config と bind-keys で指定してください。
:commands : キーに割り当てないコマンドもautoloadする
:bind で設定したコマンドはautoloadされますが、
キーに割り当てないコマンドは:commandsでautoload設定します。
(use-package ace-jump-mode
:commands (ace-jump-mode ace-jump-line-mode))
↓
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'ace-jump-mode nil t)))) (when t nil (autoload #'ace-jump-line-mode "ace-jump-mode" nil t) (autoload #'ace-jump-mode "ace-jump-mode" nil t) nil nil t))
:init : パッケージが読み込まれる前に設定を行う
:initキーワードを使えば、パッケージが読み込まれる前にコードを実行します。
(use-package ace-jump-mode :commands ace-jump-mode :init (progn (bind-key "C-." 'ace-jump-mode)))
上の設定ではprognは不要ですが、
複文を指定するときに必要になるので
わざと入れています。
これをmacroexpandすると
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'ace-jump-mode nil t)))) (when t nil (autoload #'ace-jump-mode "ace-jump-mode" nil t) (progn (bind-key "C-." 'ace-jump-mode)) nil t))
あらゆる記述が:init を使って書けることがわかります。
:config : パッケージが読み込まれた後に設定を行う
:configは:initと似ていますが、
パッケージが読み込まれた後にコードを実行します。
(use-package ace-jump-mode :bind ("C-." . ace-jump-mode) :config (progn (message "Yay, ace-jump-mode was actually loaded!")))
↓
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'ace-jump-mode nil t)))) (when t nil (autoload #'ace-jump-mode "ace-jump-mode" nil t) (progn nil (bind-key "C-." 'ace-jump-mode)) (eval-after-load 'ace-jump-mode `(,(lambda nil (if t (use-package-with-elapsed-timer "Configuring package ace-jump-mode" (progn (message "Yay, ace-jump-mode was actually loaded!"))))))) t))
その証拠に eval-after-load が使われています。
なお、 use-package-with-elapsed-timer は一定時間(デフォルト0.01秒)以上
ロードに時間がかかったときかつ変数 use-package-verbose がtのときに
メッセージを表示するマクロです。
:initと:configは共存できます。
(use-package haskell-mode :commands haskell-mode :init (add-to-list 'auto-mode-alist '("\\.l?hs$" . haskell-mode)) :config (progn (use-package inf-haskell) (use-package hs-lint)))
↓
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'haskell-mode nil t)))) (when t nil (autoload #'haskell-mode "haskell-mode" nil t) (add-to-list 'auto-mode-alist '("\\.l?hs$" . haskell-mode)) (eval-after-load 'haskell-mode `(,(lambda nil (if t (use-package-with-elapsed-timer "Configuring package haskell-mode" (progn (use-package inf-haskell) (use-package hs-lint))))))) t))
add-to-listの後にeval-after-load→use-packageが
続いていることからも明らかです。
:mode, :interpreter : auto-mode-alistとinterpreter-mode-alistの設定を行う
:modeでファイル名の正規表現を指定すれば
auto-mode-alist へ登録されます。
:interpreterでインタプリタ名を指定すれば
interpreter-mode-alist へ登録されます。
(use-package ruby-mode :mode "\\.rb\\'" :interpreter "ruby")
↓
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'ruby-mode nil t)))) (when t nil (autoload #'ruby-mode "ruby-mode" nil t) (autoload #'ruby-mode "ruby-mode" nil t) (progn (progn nil (add-to-list 'auto-mode-alist '("\\.rb\\'" . ruby-mode))) (add-to-list 'interpreter-mode-alist '("ruby" . ruby-mode))) nil t))
ruby-mode.elはメジャーモード名とファイル名が一致していたので
上記のように簡単な記述になりましたが、必ずしもそうではありません。
python-modeはpython.elにて登録されているので、
pythonにおける設定はこうなります。
(use-package python :mode ("\\.py\\'" . python-mode) :interpreter ("python" . python-mode))
↓
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'python nil t)))) (when t nil (autoload #'python-mode "python" nil t) (autoload #'python-mode "python" nil t) (progn (progn nil (add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))) (add-to-list 'interpreter-mode-alist '("python" . python-mode))) nil t))
メジャーモードのキーを設定する
メジャーモードのキーを設定するには、
use-package使用時にすでに使えるマクロ
bind-keys を使えば簡潔です。
C-c C-iにimenu、C-c M-sにxmpを割り当てる例です。
(use-package ruby-mode :config (bind-keys :map ruby-mode-map ("C-c C-i" . imenu) ("C-c M-s" . xmp)))
:idle : Emacsが暇なときに実行させる
:idleは:initや:configと似ていますが、
Emacsがアイドル状態になったときに実行されます。
とはいえ、:idleで指定されたコードにエラーが起きた際、
問題解決が困難になるのでおすすめはしません。
(use-package pabbrev :commands global-pabbrev-mode :idle (global-pabbrev-mode) :idle-priority 3)
↓
(progn nil (eval-when-compile (when (bound-and-true-p byte-compile-current-file) (with-demoted-errors (require 'pabbrev nil t)))) (when t nil (autoload #'global-pabbrev-mode "pabbrev" nil t) (progn (require 'use-package) (use-package-init-on-idle (lambda nil (global-pabbrev-mode)) 3) nil) nil t))
:disabled: 設定を一時的に無効にする
:disbledを指定すれば、この設定は無効化されます。
(use-package ess-site :disabled t :commands REST)
macroexpandしてもnilになるだけです。
本サイト内の関連パッケージ
本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。