初稿: 2018-08-04 Sat 04:45
最終更新日: 2018-12-14 Fri 20:44
ホーム | 文書トップ | 目次

use-package.el
use-packageでモダンな.emacs設定を行う!

目次

1 use-packageとは

use-packagejwiegley氏が作成されたパッケージ設定用マクロです。

「コードを作成できるコード」であるlispの特徴を最大限に生かして、 簡潔に、パッケージの設定を記述することができます。

2 インストール

melpaからできます。

M-x package-install use-package

3 キーワード

3.1 キーワードなし

キーワードなしでuse-packageを呼んだ場合、require文のみが展開されます。

(macroexpand '(use-package a))
(progn
  (defvar use-package--warning170
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'a keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (if
          (not
           (require 'a nil t))
          (display-warning 'use-package
                           (format "Cannot load %s" 'a)
                           :error))
    (error
     (funcall use-package--warning170 :catch err))))

3.2 :after キーワード

パッケージ b に依存しているパッケージ a はパッケージ b が読み込まれた後に読み込みたいです。

伝統的には eval-ater-load を利用して設定しますが、 after キーワードにより設定できます。

(macroexpand '(use-package a
                :after b))
(progn
  (defvar use-package--warning171
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'a keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (eval-after-load 'b
        '(if
             (not
              (require 'a nil t))
             (display-warning 'use-package
                              (format "Cannot load %s" 'a)
                              :error)))
    (error
     (funcall use-package--warning171 :catch err))))

次の例は :after (:any (:all a b) (:all c d)) を与えており、 foo パッケージは ab が2つとも読み込まれる、または cd が2つとも読み込まれた後に読み込まれます。

展開例を見ると分かる通り、 use-package により一時変数が展開されます。

なお、 :after (foo bar):after (:all foo bar) と指定した結果と同等になります。

(macroexpand '(use-package foo
                :after (:any (:all a b) (:all c d))))
(progn
  (defvar use-package--warning172
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'foo keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (defvar use-package--loaded172 nil)
        (defvar use-package--result172 nil)
        (defvar use-package--next172
          #'(lambda nil
              (if use-package--loaded172 use-package--result172
                (setq use-package--loaded172 t use-package--result172
                      (if
                          (not
                           (require 'foo nil t))
                          (display-warning 'use-package
                                           (format "Cannot load %s" 'foo)
                                           :error))))))
        (eval-after-load 'b
          '(eval-after-load 'a
             '(funcall use-package--next172)))
        (eval-after-load 'd
          '(eval-after-load 'c
             '(funcall use-package--next172))))
    (error
     (funcall use-package--warning172 :catch err))))

3.3 :bind, :bind* キーワード

キーバインドの設定を行います。

伝統的には define-keyglobal-set-key などが使われており、 kbd と組み合わせたり 組み合わせなかったり、混乱が見られました。

use-package はキーバインドの設定をラップし、分かりやすく簡潔な記法を提供します。

なお、 autoload で展開されるので、起動時にはキーバインドの設定のみ行われ、 実際にパッケージが読み込まれるのはキーバインドが実行されたときです。

(macroexpand '(use-package helm
                :bind (("M-x" . helm-M-x))))
(progn
  (defvar use-package--warning173
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'helm keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'helm-M-x)
          (autoload #'helm-M-x "helm" nil t))
        (bind-keys :package helm
                   ("M-x" . helm-M-x)))
    (error
     (funcall use-package--warning173 :catch err))))

以前はグローバルキーマップのみサポートされていましたが、 マイナーモードのキーマップ割り当ても bind キーワードで出来るようになりました。

次の例では helm-M-xhelm-find-files がグローバルマップに割り当てられ、 helm-occurhelm-command-map に、 helm-execute-persistent-actionhelm-select-actionhelm-map に割り当てられます。

マップの指定は次のマップ指定が現れるまで有効です。

(macroexpand '(use-package helm
                :bind (("M-x"     . helm-M-x)
                       ("C-x C-f" . helm-find-files)
                       :map helm-command-map
                       ("o"       . helm-occur)
                       :map helm-map
                       ("<tab>"   . helm-execute-persistent-action)
                       ("C-z"     . helm-select-action))))
(progn
  (defvar use-package--warning174
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'helm keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'helm-M-x)
          (autoload #'helm-M-x "helm" nil t))
        (unless
            (fboundp 'helm-find-files)
          (autoload #'helm-find-files "helm" nil t))
        (unless
            (fboundp 'helm-occur)
          (autoload #'helm-occur "helm" nil t))
        (unless
            (fboundp 'helm-execute-persistent-action)
          (autoload #'helm-execute-persistent-action "helm" nil t))
        (unless
            (fboundp 'helm-select-action)
          (autoload #'helm-select-action "helm" nil t))
        (bind-keys :package helm
                   ("M-x" . helm-M-x)
                   ("C-x C-f" . helm-find-files)
                   :map helm-command-map
                   ("o" . helm-occur)
                   :map helm-map
                   ("<tab>" . helm-execute-persistent-action)
                   ("C-z" . helm-select-action)))
    (error
     (funcall use-package--warning174 :catch err))))

メジャーモードのキーマップの方が、グローバルキーマップより優先されるため、 モードによっては bind で指定したキーバインドが動かない場合があります。

しかし、Emacsにはメジャーモードよりマイナーモードのキーマップのほうが優先されるという仕様があるので、 伝統的にはキーバインドのみを指定したマイナーモードを定義したりと、とても複雑な設定をすることを求められました。

しかし use-package はその記法をうまくラップし、 bind キーワードを bind* キーワードに変更するだけで、 上記の作業を行ってくれます。 つまり、すべてのキーマップより優先されるマイナーモードを作り、そのマイナーモードにキーバインドを定義します。 ( use-package がというより、 bind-keys にぶん投げてますが。。)

bind* においても bind と同じように :map キーワードを使用できます。

(macroexpand '(use-package other-window-or-split
                :init (el-get-bundle conao/other-window-or-split)
                :bind* (("C-t"   . ws-other-window-or-split)
                        ("C-c j" . ws-adjust-windows-size))))
(progn
  (defvar use-package--warning175
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'other-window-or-split keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ws-other-window-or-split)
          (autoload #'ws-other-window-or-split "other-window-or-split" nil t))
        (unless
            (fboundp 'ws-adjust-windows-size)
          (autoload #'ws-adjust-windows-size "other-window-or-split" nil t))
        (condition-case-unless-debug err
            (el-get-bundle conao/other-window-or-split)
          (error
           (funcall use-package--warning175 :init err)))
        (bind-keys* :package other-window-or-split
                    ("C-t" . ws-other-window-or-split)
                    ("C-c j" . ws-adjust-windows-size)))
    (error
     (funcall use-package--warning175 :catch err))))

3.4 :bind-keymap, :bind-keymap* キーワード

bind-keymap はキーマップをキーストロークにバインドします。 つまり、バインドされたキーストロークはprefixキーとして動作するようになります。

bind キーワードではキーバインドと同時に autoload により遅延ロードを設定しますが、 キーマップの場合、キーマップ自身を実行することはありません。

そのため、 autoload を行わない bind キーワードとして bind-keymap が用意されています。 bind-keymapbind-keymap* の関係性および、設定方法は bind と変わりません。

(macroexpand '(use-package org2blog
                :init
                (defvar org2blog-map nil "org2blog-prefix-map")
                (define-prefix-command 'org2blog-map)

                :bind-keymap (("C-c n" . org2blog-map))
                :bind (:map org2blog-map
                            ("n" . org2blog/wp-new-entry)
                            ("i" . org2blog/wp-login)
                            ("o" . org2blog/wp-logout)
                            ("p" . org2blog/wp-post-buffer-and-publish)
                            ("l" . org2blog/wp-insert-post-or-page-link))))
(progn
  (defvar use-package--warning176
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'org2blog keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'org2blog/wp-new-entry)
          (autoload #'org2blog/wp-new-entry "org2blog" nil t))
        (unless
            (fboundp 'org2blog/wp-login)
          (autoload #'org2blog/wp-login "org2blog" nil t))
        (unless
            (fboundp 'org2blog/wp-logout)
          (autoload #'org2blog/wp-logout "org2blog" nil t))
        (unless
            (fboundp 'org2blog/wp-post-buffer-and-publish)
          (autoload #'org2blog/wp-post-buffer-and-publish "org2blog" nil t))
        (unless
            (fboundp 'org2blog/wp-insert-post-or-page-link)
          (autoload #'org2blog/wp-insert-post-or-page-link "org2blog" nil t))
        (condition-case-unless-debug err
            (progn
              (defvar org2blog-map nil "org2blog-prefix-map")
              (define-prefix-command 'org2blog-map))
          (error
           (funcall use-package--warning176 :init err)))
        (bind-key "C-c n"
                  #'(lambda nil
                      (interactive)
                      (use-package-autoload-keymap 'org2blog-map 'org2blog nil)))
        (bind-keys :package org2blog :map org2blog-map
                   ("n" . org2blog/wp-new-entry)
                   ("i" . org2blog/wp-login)
                   ("o" . org2blog/wp-logout)
                   ("p" . org2blog/wp-post-buffer-and-publish)
                   ("l" . org2blog/wp-insert-post-or-page-link)))
    (error
     (funcall use-package--warning176 :catch err))))

3.5 :commands キーワード

autoload 設定されていないコマンドに対して autoload を設定します。

melpaで配布されているパッケージ等は @autoload というマジックキーワードをlispパッケージ内に入れることで package.el がインストールする際に autoload 用のファイルを自動生成しています。 そのためほとんどのパッケージでは使うことはないのですが、作成者が autoload の設定をし忘れていたり、 そもそもそんな風潮のなかった頃の古いパッケージを使用する場合などに使用できます。

commands キーワードが設定されると、 use-packageautoload 設定を展開し、 commands キーワードで設定されたコマンドを実行するときにパッケージ全体を読み込みます。

(macroexpand '(use-package auto-install
                :commands (auto-install-from-buffer
                           auto-install-from-url
                           auto-install-from-emacswiki)))
(progn
  (defvar use-package--warning177
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'auto-install keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'auto-install-from-buffer)
          (autoload #'auto-install-from-buffer "auto-install" nil t))
        (unless
            (fboundp 'auto-install-from-url)
          (autoload #'auto-install-from-url "auto-install" nil t))
        (unless
            (fboundp 'auto-install-from-emacswiki)
          (autoload #'auto-install-from-emacswiki "auto-install" nil t)))
    (error
     (funcall use-package--warning177 :catch err))))

3.6 :preface, :init, :config キーワード

これらのキーワードは配下のS式を実行する順番を定義します。 :preface -> :init -> (require 'foo) -> :config の順番です。

これらのキーワードは展開時に暗黙のprognによって囲まれます。 そのため、いちいち(progn …)で囲って一文のようにしなくても、大丈夫です。

暗黙のprognの範囲は他のキーワードが出現するまでです。

基本的には require 後の処理を行う :config のみで大丈夫ですが、パッケージの設計により、 require 前に setq しないといけない場面があります。 そういう場合に :init を使用しますし、別のパッケージ管理ソフト el-get などのインストール 作業を記述する場合もあります。(package を使用する場合は :ensure t でインストールできます)

(macroexpand '(use-package example
                ;; Note that errors are never trapped in the preface, since doing so would
                ;; hide definitions from the byte-compiler.
                :preface (message "I'm here at byte-compile and load time.")
                :init (message "I'm always here at startup")
                :config
                (message "I'm always here after the package is loaded")
                (error "oops")
                ;; Don't try to (require 'example), this is just an example!
                :no-require t
                :catch (lambda (keyword err)
                         (message (error-message-string err)))))
(progn
  (eval-and-compile
    (message "I'm here at byte-compile and load time."))
  (defvar use-package--warning178
    (lambda
      (keyword err)
      (message
       (error-message-string err))))
  (condition-case-unless-debug err
      (progn
        (condition-case-unless-debug err
            (message "I'm always here at startup")
          (error
           (funcall use-package--warning178 :init err)))
        (condition-case-unless-debug err
            (progn
              (message "I'm always here after the package is loaded")
              (error "oops")
              t)
          (error
           (funcall use-package--warning178 :config err))))
    (error
     (funcall use-package--warning178 :catch err))))

3.7 :custom キーワード

defcustom で宣言された変数に関しては custom-set-variables で設定したほうが良い という議論があったり、なかったりします。

この議論は画一的に結論を決めようとしているので、混乱しているのであり、実際のところ、 どちらを使うべきかはパッケージ毎に異なると思っています。

defcustom変数定義を参照し、 :set が定義されている場合、 custom-set-variables が良いでしょうし、 定義されていなかった場合、 setq で代入してしまいます。

とりあえず use-package:custom キーワードのみ定義されており、 setq キーワードがないとこを見ると、 custom-set-variables 派なのかもしれません。

3番目の値はドキュメント文章が設定できますが、別になくても構いません。

(macroexpand '(use-package elscreen
                :custom ((elscreen-prefix-key (kbd "C-c e"))
                         (elscreen-tab-display-kill-screen nil "hide [<->] mark"))
                :config
                (setq elscreen-display-screen-number nil)
                (elscreen-start)))
(progn
  (defvar use-package--warning179
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'elscreen keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (customize-set-variable 'elscreen-prefix-key
                                (kbd "C-c e")
                                "Customized with use-package elscreen")
        (customize-set-variable 'elscreen-tab-display-kill-screen nil "hide [<->] mark")
        (if
            (not
             (require 'elscreen nil t))
            (display-warning 'use-package
                             (format "Cannot load %s" 'elscreen)
                             :error)
          (condition-case-unless-debug err
              (progn
                (setq elscreen-display-screen-number nil)
                (elscreen-start)
                t)
            (error
             (funcall use-package--warning179 :config err)))))
    (error
     (funcall use-package--warning179 :catch err))))

3.8 :custom-face キーワード

フェイスの設定を記述できます。 ポイントの文字がどんなフェイスが設定されているかは、調べたい文字にポインタを持っていって、 M-x describe-char を実行することで、faceを調べることができます。

設定方法は custom-set-faces を調べていただければと思います。

(macroexpand '(use-package eruby-mode
                :custom-face
                (eruby-standard-face ((t (:slant italic))))))
(progn
  (defvar use-package--warning180
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'eruby-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (custom-set-faces
         '(eruby-standard-face
           ((t
             (:slant italic)))))
        (if
            (not
             (require 'eruby-mode nil t))
            (display-warning 'use-package
                             (format "Cannot load %s" 'eruby-mode)
                             :error)))
    (error
     (funcall use-package--warning180 :catch err))))

3.9 :defer, :demand キーワード

遅延ロードの設定を行います。 :deferautoload による遅延ロードを実行し、 :demand は即時ロード(デフォルトの動作)します。

これらのキーワードはキーワードを置くだけで効力を発揮しますが、引数を一つとってもいいことになっています。 そのため、筆者はみやすさの観点から t を与えています。 (と思ったら、 :defer nil とすると、 :demand t の展開がされました。 逆に :demand nil:defer t と同じ展開結果になりませんでした。 真偽値を与えられることはドキュメントで言及されてないので、 統一性を考えて与えるときは t のみにしたほうが良いと思います。)

(macroexpand '(use-package helm :defer :config (setq a b)))
(progn
  (defvar use-package--warning181
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'helm keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (eval-after-load 'helm
        '(condition-case-unless-debug err
             (progn
               (setq a b)
               t)
           (error
            (funcall use-package--warning181 :config err))))
    (error
     (funcall use-package--warning181 :catch err))))
(macroexpand '(use-package helm :defer t :config (setq foo 'a)))
(progn
  (defvar use-package--warning182
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'helm keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (eval-after-load 'helm
        '(condition-case-unless-debug err
             (progn
               (setq foo 'a)
               t)
           (error
            (funcall use-package--warning182 :config err))))
    (error
     (funcall use-package--warning182 :catch err))))

autoload による遅延ロード関数の設定は package.el などが自動で生成しています。 特に指定する必要がある場合は、 :commands キーワードなどで自分で指定します。

しかし、 :commands で遅延ロードを設定するということは、もちろん遅延ロードするということなので、 :defer キーワードを指定しなくても遅延ロード用の式が展開されます。 :bind キーワードを指定したときも暗黙的に defer を指定したとして、遅延ロード用の式が展開されます。

(macroexpand '(use-package auto-install
                :commands (auto-install-from-buffer)))
(progn
  (defvar use-package--warning183
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'auto-install keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (unless
          (fboundp 'auto-install-from-buffer)
        (autoload #'auto-install-from-buffer "auto-install" nil t))
    (error
     (funcall use-package--warning183 :catch err))))
(macroexpand '(use-package auto-install :defer t
                :commands (auto-install-from-buffer)))
(progn
  (defvar use-package--warning184
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'auto-install keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (unless
          (fboundp 'auto-install-from-buffer)
        (autoload #'auto-install-from-buffer "auto-install" nil t))
    (error
     (funcall use-package--warning184 :catch err))))

3.10 :defines, :functions キーワード

バイトコンパイル時にunknown~系のwarningが出ることを抑制します。

.emacsをバイトコンパイルしている方は便利だと思います。 バイトコンパイル時に展開されるので、 macroexpand では変化がわかりません。

(macroexpand '(use-package texinfo
                :defines texinfo-section-list
                :commands texinfo-mode
                :init
                (add-to-list 'auto-mode-alist '("\\.texi$" . texinfo-mode))))
(progn
  (defvar use-package--warning185
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'texinfo keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'texinfo-mode)
          (autoload #'texinfo-mode "texinfo" nil t))
        (condition-case-unless-debug err
            (add-to-list 'auto-mode-alist
                         '("\\.texi$" . texinfo-mode))
          (error
           (funcall use-package--warning185 :init err))))
    (error
     (funcall use-package--warning185 :catch err))))
(macroexpand '(use-package ruby-mode
                :mode "\\.rb\\'"
                :interpreter "ruby"
                :functions inf-ruby-keys
                :config
                (defun my-ruby-mode-hook ()
                  (require 'inf-ruby)
                  (inf-ruby-keys))

                (add-hook 'ruby-mode-hook 'my-ruby-mode-hook)))
(progn
  (defvar use-package--warning186
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ruby-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ruby-mode)
          (autoload #'ruby-mode "ruby-mode" nil t))
        (eval-after-load 'ruby-mode
          '(condition-case-unless-debug err
               (progn
                 (defun my-ruby-mode-hook nil
                   (require 'inf-ruby)
                   (inf-ruby-keys))
                 (add-hook 'ruby-mode-hook 'my-ruby-mode-hook)
                 t)
             (error
              (funcall use-package--warning186 :config err))))
        (add-to-list 'auto-mode-alist
                     '("\\.rb\\'" . ruby-mode))
        (add-to-list 'interpreter-mode-alist
                     '("ruby" . ruby-mode)))
    (error
     (funcall use-package--warning186 :catch err))))

3.11 :diminish, :delight キーワード

マイナーモードの表示を隠したり、変更したりする、diminish.eldelight.elの糖衣構文を提供します。 使用するにはこのキーワードを使用する前に、対応するelを require しておく必要があります。

diminish.eldelight.el の違いがわからなかったので、例では diminish.el のみ使用します。

:diminish キーワードは引数がなかった場合、 use-package の引数からマイナーモードの名前を予想します。 たいていのパッケージの場合、 パッケージ名-mode のマイナーモードが提供されますが、 明示的に与えることもできます。

コンスセルのcdr部を与えなかった場合、完全に消去します。

(macroexpand '(use-package hideshow :diminish hs-minor-mode))
(progn
  (defvar use-package--warning187
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'hideshow keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (if
          (not
           (require 'hideshow nil t))
          (display-warning 'use-package
                           (format "Cannot load %s" 'hideshow)
                           :error)
        (if
            (fboundp 'diminish)
            (diminish 'hs-minor-mode)))
    (error
     (funcall use-package--warning187 :catch err))))

cdr部を与えた場合、その文字列が表示されるようにします。 リストを与えることもでき、次の場合、 abbrev-mode は" Abb"で表示され、 a-mode は(有効になっても)表示されません。

(macroexpand '(use-package abbrev :diminish ((abbrev-mode . " Abb") a-mode)))
(progn
  (defvar use-package--warning188
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'abbrev keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (if
          (not
           (require 'abbrev nil t))
          (display-warning 'use-package
                           (format "Cannot load %s" 'abbrev)
                           :error)
        (if
            (fboundp 'diminish)
            (diminish 'abbrev-mode " Abb"))
        (if
            (fboundp 'diminish)
            (diminish 'a-mode)))
    (error
     (funcall use-package--warning188 :catch err))))

readmeにはdelightの例として :eval キーワードを使った例がありました。

;; Remove the mode name for projectile-mode, but show the project name.
(macroexpand '(use-package projectile
  :delight '(:eval (concat " " (projectile-project-name)))))
(progn
  (defvar use-package--warning189
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'projectile keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (if
          (not
           (require 'projectile nil t))
          (display-warning 'use-package
                           (format "Cannot load %s" 'projectile)
                           :error)
        (if
            (fboundp 'delight)
            (delight
             '((projectile-mode
                (:eval
                 (concat " "
                         (projectile-project-name)))
                projectile)))))
    (error
     (funcall use-package--warning189 :catch err))))

3.12 :disabled キーワード

指定された use-package 式全体を無効化します。 仕様は難しそうですが、結局、何を与えても単に nil になるだけです。

:defer キーワードと同じように :disabled キーワードも指定しただけで効力があります。 しかし、筆者はわかりやすさを重視して t を与えています。

真偽値はハンドルされていないので、 :disabled nil としても有効化されるわけではありません。

(macroexpand (use-package flycheck :ensure t :disabled t
               :config
               (use-package flycheck-pos-tip :ensure t)
               (setq flycheck-disabled-checkers '(emacs-lisp emacs-lisp-checkdoc))
               (global-flycheck-mode)
               (custom-set-variables
                '(flycheck-keymap-prefix (kbd "C-c f"))
                '(flycheck-display-errors-function #'flycheck-pos-tip-error-messages))
               (smartrep-define-key
                   global-map "M-g" '(("M-n" . 'flymake-goto-next-error)
                                      ("M-p" . 'flymake-goto-prev-error)))))
nil

3.13 :ensure, :pin キーワード

パッケージの require をする前にダウンロードする処理を記述できます。

引数を何も与えない場合や、 t を与えた場合、 use-package に指定したパッケージと同じ名前のパッケージをダウンロードしようとします。 明示的に与えた場合、その名前のパッケージをダウンロードします。

(macroexpand '(use-package magit :ensure t))
(progn
  (use-package-ensure-elpa 'magit
                           '(t)
                           'nil)
  (defvar use-package--warning190
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'magit keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (if
          (not
           (require 'magit nil t))
          (display-warning 'use-package
                           (format "Cannot load %s" 'magit)
                           :error))
    (error
     (funcall use-package--warning190 :catch err))))
(macroexpand '(use-package tex :ensure auctex))
(progn
  (use-package-ensure-elpa 'tex
                           '(auctex)
                           'nil)
  (defvar use-package--warning191
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'tex keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (if
          (not
           (require 'tex nil t))
          (display-warning 'use-package
                           (format "Cannot load %s" 'tex)
                           :error))
    (error
     (funcall use-package--warning191 :catch err))))

:pin キーワードを指定しない場合、 package.el はmelpaからダウンロードしようとします。 :pin キーワードの引数には malpa, malpa-stable, gnu, manual の値が指定できます。

:pin にデフォルト値を設定したい場合、 use-package-always-pin を利用することができます。

:pin キーワードはEmacs 24.4以前のバージョンで無視されます。

;; ignore org-mode from upstream and use a manually installed version
(macroexpand '(use-package org
  :ensure t  
  :pin manual))
(progn
  (use-package-pin-package 'org "manual")
  (use-package-ensure-elpa 'org
                           '(t)
                           'nil)
  (defvar use-package--warning192
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'org keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (if
          (not
           (require 'org nil t))
          (display-warning 'use-package
                           (format "Cannot load %s" 'org)
                           :error))
    (error
     (funcall use-package--warning192 :catch err))))

3.14 :hook キーワード

hookを設定するための糖衣構文を提供します。

伝統的には add-hook による設定が利用されていました。

:hook には -mode というsuffixを消したシンボル名を指定します。 リストを指定でき、コンスセルのcdr部を省略した場合、 use-package に指定されたパッケージ名を設定します。

(macroexpand '(use-package ace-jump-mode :hook prog-mode))
(progn
  (defvar use-package--warning193
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ace-jump-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ace-jump-mode)
          (autoload #'ace-jump-mode "ace-jump-mode" nil t))
        (add-hook 'prog-mode-hook #'ace-jump-mode))
    (error
     (funcall use-package--warning193 :catch err))))

リストを与えた場合、与えたリスト全てに対してhookを指定します。

(macroexpand '(use-package ace-jump-mode :hook (prog-mode text-mode)))
(progn
  (defvar use-package--warning194
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ace-jump-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ace-jump-mode)
          (autoload #'ace-jump-mode "ace-jump-mode" nil t))
        (add-hook 'prog-mode-hook #'ace-jump-mode)
        (add-hook 'text-mode-hook #'ace-jump-mode))
    (error
     (funcall use-package--warning194 :catch err))))

cdrを明示的に指定することで、設定されるモードを指定することができます。

(macroexpand '(use-package ace-jump-mode
                :hook ((prog-mode text-mode) . ace-jump-mode)))
(progn
  (defvar use-package--warning195
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ace-jump-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ace-jump-mode)
          (autoload #'ace-jump-mode "ace-jump-mode" nil t))
        (add-hook 'prog-mode-hook #'ace-jump-mode)
        (add-hook 'text-mode-hook #'ace-jump-mode))
    (error
     (funcall use-package--warning195 :catch err))))

複数のモードを登録するときは、コンスセルをリストにして渡します。

(macroexpand '(use-package ace-jump-mode
                :hook (((prog-mode text-mode) . ace-jump-mode)
                       ((prog-mode text-mode) . ace-mode))))
(progn
  (defvar use-package--warning196
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ace-jump-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ace-jump-mode)
          (autoload #'ace-jump-mode "ace-jump-mode" nil t))
        (unless
            (fboundp 'ace-mode)
          (autoload #'ace-mode "ace-jump-mode" nil t))
        (add-hook 'prog-mode-hook #'ace-jump-mode)
        (add-hook 'text-mode-hook #'ace-jump-mode)
        (add-hook 'prog-mode-hook #'ace-mode)
        (add-hook 'text-mode-hook #'ace-mode))
    (error
     (funcall use-package--warning196 :catch err))))

3.15 :if, :when, :unless キーワード

use-package 設定を有効にする条件を設定できます。

しかし、単に展開結果が指定したキーワードの条件分で囲まれるだけです。

else 文を取れないので、 :if:when と変わりません。 :unless foo:if (not foo) と同等です。

(macroexpand '(use-package migemo
                 :if (executable-find "cmigemo")
                 :config (migemo-init)))
(if
    (executable-find "cmigemo")
    (progn
      (defvar use-package--warning197
        #'(lambda
            (keyword err)
            (let
                ((msg
                  (format "%s/%s: %s" 'migemo keyword
                          (error-message-string err))))
              (display-warning 'use-package msg :error))))
      (condition-case-unless-debug err
          (if
              (not
               (require 'migemo nil t))
              (display-warning 'use-package
                               (format "Cannot load %s" 'migemo)
                               :error)
            (condition-case-unless-debug err
                (progn
                  (migemo-init)
                  t)
              (error
               (funcall use-package--warning197 :config err))))
        (error
         (funcall use-package--warning197 :catch err)))))

複数の条件を取りたい場合は、 :if キーワードなどがリストを受け取れないので、キーワードを複数設定します。

指定したキーワードはすべて and で結合されて if に渡されます。 :if, :when, :unless キーワードが混在していても構いません。

(macroexpand '(use-package migemo
                :if (executable-find "cmigemo")
                :if (executable-find "cccccmigemo")                
                :config (migemo-init)))
(if
    (and
     (executable-find "cmigemo")
     (executable-find "cccccmigemo"))
    (progn
      (defvar use-package--warning198
        #'(lambda
            (keyword err)
            (let
                ((msg
                  (format "%s/%s: %s" 'migemo keyword
                          (error-message-string err))))
              (display-warning 'use-package msg :error))))
      (condition-case-unless-debug err
          (if
              (not
               (require 'migemo nil t))
              (display-warning 'use-package
                               (format "Cannot load %s" 'migemo)
                               :error)
            (condition-case-unless-debug err
                (progn
                  (migemo-init)
                  t)
              (error
               (funcall use-package--warning198 :config err))))
        (error
         (funcall use-package--warning198 :catch err)))))

3.16 :load-path キーワード

パッケージの require 前に load-path の設定を行います。

スラッシュから指定すると、絶対パスとして、 ディレクトリ名から指定すると、 user-emacs-direcroty からの相対パスが指定されます。

(macroexpand '(use-package ess-site
                :load-path "site-lisp/ess/lisp/"
                :commands R
                :config (setq as as)))
(progn
  (eval-and-compile
    (add-to-list 'load-path "/Users/conao/.emacs.d/local/26.1/site-lisp/ess/lisp/"))
  (defvar use-package--warning199
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ess-site keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'R)
          (autoload #'R "ess-site" nil t))
        (eval-after-load 'ess-site
          '(condition-case-unless-debug err
               (progn
                 (setq as as)
                 t)
             (error
              (funcall use-package--warning199 :config err)))))
    (error
     (funcall use-package--warning199 :catch err))))

リストを与えて、複数の load-path の設定を一括で行うこともできます。

(macroexpand '(use-package ess-site
                :load-path ("site-lisp/ess/lisp/" "site-lisp/ess/llisp/" "/Users/shared/site-lisp")
                :commands R
                :config (setq as as)))
(progn
  (eval-and-compile
    (add-to-list 'load-path "/Users/conao/.emacs.d/local/26.1/site-lisp/ess/lisp/"))
  (eval-and-compile
    (add-to-list 'load-path "/Users/conao/.emacs.d/local/26.1/site-lisp/ess/llisp/"))
  (eval-and-compile
    (add-to-list 'load-path "/Users/shared/site-lisp"))
  (defvar use-package--warning200
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ess-site keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'R)
          (autoload #'R "ess-site" nil t))
        (eval-after-load 'ess-site
          '(condition-case-unless-debug err
               (progn
                 (setq as as)
                 t)
             (error
              (funcall use-package--warning200 :config err)))))
    (error
     (funcall use-package--warning200 :catch err))))

3.17 :mode, :interpreter キーワード

ファイル拡張子にフックされるメジャーモードの設定と、 シバンにフックされるメジャーモードの設定を行います。

コンスセルのcdr部が省略された場合は use-package に渡された シンボル-modeauto-mode-alistinterpreter-mode-alist に設定します。

(macroexpand '(use-package ruby-mode
                :mode "\\.rb\\'"
                :interpreter "ruby"))
(progn
  (defvar use-package--warning201
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ruby-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ruby-mode)
          (autoload #'ruby-mode "ruby-mode" nil t))
        (add-to-list 'auto-mode-alist
                     '("\\.rb\\'" . ruby-mode))
        (add-to-list 'interpreter-mode-alist
                     '("ruby" . ruby-mode)))
    (error
     (funcall use-package--warning201 :catch err))))

リストを渡すことができます。cdr部で設定するモード名を指定できます。

(macroexpand '(use-package ruby-mode
                :mode ("\\.rb\\" ("\\.ruby\\" . ruby-interaction-mode))
                :interpreter ("ruby" . my-ruby-mode)))
(progn
  (defvar use-package--warning202
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'ruby-mode keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'ruby-mode)
          (autoload #'ruby-mode "ruby-mode" nil t))
        (unless
            (fboundp 'ruby-interaction-mode)
          (autoload #'ruby-interaction-mode "ruby-mode" nil t))
        (unless
            (fboundp 'my-ruby-mode)
          (autoload #'my-ruby-mode "ruby-mode" nil t))
        (add-to-list 'auto-mode-alist
                     '("\\.rb\\" . ruby-mode))
        (add-to-list 'auto-mode-alist
                     '("\\.ruby\\" . ruby-interaction-mode))
        (add-to-list 'interpreter-mode-alist
                     '("ruby" . my-ruby-mode)))
    (error
     (funcall use-package--warning202 :catch err))))

3.18 :magic, :magic-fallback キーワード

(macroexpand '(use-package pdf-tools
                :load-path "site-lisp/pdf-tools/lisp"
                :magic ("%PDF" . pdf-view-mode)
                :magic-fallback ("#pdf" . pdf-view-mode)
                :config (pdf-tools-install)))
(progn
  (eval-and-compile
    (add-to-list 'load-path "/Users/conao/.emacs.d/local/26.1/site-lisp/pdf-tools/lisp"))
  (defvar use-package--warning203
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'pdf-tools keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn
        (unless
            (fboundp 'pdf-view-mode)
          (autoload #'pdf-view-mode "pdf-tools" nil t))
        (eval-after-load 'pdf-tools
          '(condition-case-unless-debug err
               (progn
                 (pdf-tools-install)
                 t)
             (error
              (funcall use-package--warning203 :config err))))
        (add-to-list 'magic-fallback-mode-alist
                     '("#pdf" . pdf-view-mode))
        (add-to-list 'magic-mode-alist
                     '("%PDF" . pdf-view-mode)))
    (error
     (funcall use-package--warning203 :catch err))))

日付: 2018-08-04 Sat 04:45

著者: conao

Created: 2018-12-14 Fri 21:04

Validate