use-package 20170319.12(in MELPA)
A use-package declaration for simplifying your .emacs

概要

use-package マクロは、emacsのパッケージ設定を
劇的に簡潔にして読みやすくするマクロです。

<2014-12-12 Fri>更新: @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-modeace-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になるだけです。

本サイト内の関連パッケージ


本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。