From 14dd0ea9e47f31563f4b4deebb2596ddad9c5054 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 24 May 2015 17:47:34 +0900 Subject: upgrade to use-package.el version 2.0 --- .emacs.d/init-haskell.el | 42 +- .emacs.d/init.el | 745 ++++++++++---------- .emacs.d/site-lisp/bind-key.el | 199 +++--- .emacs.d/site-lisp/use-package.el | 1359 +++++++++++++++++++++++++++---------- 4 files changed, 1513 insertions(+), 832 deletions(-) diff --git a/.emacs.d/init-haskell.el b/.emacs.d/init-haskell.el index 1bc2bf91..abc2aa40 100644 --- a/.emacs.d/init-haskell.el +++ b/.emacs.d/init-haskell.el @@ -31,12 +31,15 @@ :mode (("\\.hs\\'" . haskell-mode) ("\\.cabal\\'" . haskell-cabal-mode) ("\\.hcr\\'" . haskell-core-mode)) + + :config + ;; Start up all my usual minor modes and bindings. - :init (progn - (add-hook 'haskell-mode-hook 'spw/haskell-mode-hook) - (add-hook 'after-save-hook 'spw/haskell-cabal-mode-save-hook)) - :config (setq haskell-tags-on-save t - haskell-process-suggest-remove-import-lines t)) + (add-hook 'haskell-mode-hook 'spw/haskell-mode-hook) + (add-hook 'after-save-hook 'spw/haskell-cabal-mode-save-hook) + + (setq haskell-tags-on-save t + haskell-process-suggest-remove-import-lines t)) ;; load haskell-flycheck only once haskell-mode is loaded @@ -135,20 +138,21 @@ (use-package hi2 :ensure :diminish hi2-mode - :init (progn (setq hi2-layout-offset 4 - hi2-left-offset 4 - hi2-show-indentations nil) - - (defun spw/hi2-pipe () - "Newline, pipe char and indent" - (interactive) - (hi2-newline-and-indent) - (insert "|") - (indent-for-tab-command) - (insert " ")) - - (add-hook 'haskell-mode-hook 'turn-on-hi2) - (bind-key "C-c |" 'spw/hi2-pipe hi2-mode-map))) + :config + (setq hi2-layout-offset 4 + hi2-left-offset 4 + hi2-show-indentations nil) + + (defun spw/hi2-pipe () + "Newline, pipe char and indent" + (interactive) + (hi2-newline-and-indent) + (insert "|") + (indent-for-tab-command) + (insert " ")) + + (add-hook 'haskell-mode-hook 'turn-on-hi2) + (bind-key "C-c |" 'spw/hi2-pipe hi2-mode-map)) (use-package shm :disabled t diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 058a1b43..c2a570f9 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -17,9 +17,7 @@ ("melpa-stable" . "http://stable.melpa.org/packages/") ;; ("marmalade" . "http://marmalade-repo.org/packages/") ("org" . "http://orgmode.org/elpa/") - ("gnu" . "http://elpa.gnu.org/packages/")) - package-pinned-packages - '((org-plus-contrib . "org"))) + ("gnu" . "http://elpa.gnu.org/packages/"))) (package-initialize) (unless package-archive-contents @@ -127,15 +125,15 @@ (use-package smart-mode-line :ensure - :init (progn - (use-package powerline :ensure) - (use-package smart-mode-line-powerline-theme :ensure) - (sml/setup) - (sml/apply-theme 'powerline) - (setq sml/shorten-directory nil - sml/shorten-modes t - sml/mode-width 'right - sml/vc-mode-show-backend t))) + :init + (use-package powerline :ensure) + (use-package smart-mode-line-powerline-theme :ensure) + (sml/setup) + (sml/apply-theme 'powerline) + (setq sml/shorten-directory nil + sml/shorten-modes t + sml/mode-width 'right + sml/vc-mode-show-backend t)) ;;; I'm in Korea @@ -165,31 +163,32 @@ (use-package expand-region :ensure :bind ("M-i" . er/expand-region) - :init (progn - (setq expand-region-contract-fast-key (kbd "o")) - ;; fill out the region to the beginning and ends of the - ;; lines at either end of it when we're not using - ;; expand-region but we've activated the mark (but only do - ;; this once) - (defadvice er/expand-region (around fill-out-region activate) - (if (or (not (region-active-p)) - (eq last-command 'er/expand-region)) - ad-do-it - (if (< (point) (mark)) - (let ((beg (point))) - (goto-char (mark)) - (end-of-line) - (forward-char 1) - (push-mark) - (goto-char beg) - (beginning-of-line)) - (let ((end (point))) - (goto-char (mark)) - (beginning-of-line) - (push-mark) - (goto-char end) - (end-of-line) - (forward-char 1))))))) + :init + (setq expand-region-contract-fast-key (kbd "o")) + + ;; fill out the region to the beginning and ends of the + ;; lines at either end of it when we're not using + ;; expand-region but we've activated the mark (but only do + ;; this once) + (defadvice er/expand-region (around fill-out-region activate) + (if (or (not (region-active-p)) + (eq last-command 'er/expand-region)) + ad-do-it + (if (< (point) (mark)) + (let ((beg (point))) + (goto-char (mark)) + (end-of-line) + (forward-char 1) + (push-mark) + (goto-char beg) + (beginning-of-line)) + (let ((end (point))) + (goto-char (mark)) + (beginning-of-line) + (push-mark) + (goto-char end) + (end-of-line) + (forward-char 1)))))) ;;; keep parentheses under control: modern replacement for the mighty paredit @@ -200,123 +199,123 @@ ;; for when I use Emacs via PuTTY ("M-" . sp-forward-slurp-sexp) ("M-" . sp-forward-barf-sexp)) - :commands (smartparens-strict-mode smartparens-mode show-smartparens-global-mode) - :init (dolist (hook '(emacs-lisp-mode-hook - lisp-mode-hook - lisp-interaction-mode-hook - ielm-mode-hook - scheme-mode-hook - inferior-scheme-mode-hook - python-mode-hook - minibuffer-setup-hook - haskell-mode-hook)) - (add-hook hook - (lambda () - (smartparens-strict-mode)))) - :idle (progn - (show-smartparens-global-mode) - - ;; non-strict mode the default, and strict mode in some - ;; programming language major modes - ;; (smartparens-global-mode) - ) - :config (progn - (require 'smartparens-config) - (setq sp-navigate-consider-symbols t) - - ;; global smartparens bindings - (sp-use-smartparens-bindings) - (bind-key "C-w" 'sp-backward-kill-word emacs-lisp-mode-map) - (bind-key "C-k" 'sp-kill-hybrid-sexp emacs-lisp-mode-map) - (bind-key "M-" 'sp-raise-sexp smartparens-mode-map) - - ;; and now undo some of that in particular major modes - (add-hook 'org-mode-hook (lambda () - (crowding/local-set-minor-mode-key - 'smartparens-mode (kbd "M-") nil))) - - ;; override smartparens binding for C-k outside of lisp, - ;; since sp-kill-hybrid-sexp isn't very smart in comint - ;; and I like using C-u C-k - ;; (define-key smartparens-strict-mode-map [remap kill-line] 'kill-line) - ;; (bind-key "C-k" 'sp-kill-hybrid-sexp - ;; emacs-lisp-mode-map) - - (defadvice sp-backward-kill-word (after sp-backward-kill-word-fix-punctuation activate) - ;; when killing the first word of a sentence, leave the - ;; two spaces after the previous sentence's terminal - ;; period - (save-excursion - (backward-char 2) - (if (and - (or - (looking-at "\\. ") - (looking-at "! ") - (looking-at "\\? ")) - (not (looking-back "^[1-9]+"))) - (progn - (forward-char 1) - (insert " "))))) - - ;; fix cursor position after M-d at the beginning of a line - (defadvice sp-kill-word (after sp-kill-word-beg-of-line-fix activate) - (if (looking-back "^[[:space:]]") - (backward-char 1))) - - (defadvice sp-backward-delete-char (around sp-backward-delete-char-remove-indentation activate) - ;; when after whitespace at the beginning of a line or - ;; an Org bullet or heading, delete it all - (if (and - ;; do it if we're not at the beginning of the line, - ;; and there's whitespace: if we're at the - ;; beginning of the line we should always delete - (not (equal (point) (line-beginning-position))) - (or - (looking-back "^[[:space:]]+") - (looking-back "^[[:space:]]*- ") - (looking-back "^[*]+ "))) - (kill-line 0) - ;; if not after whitespace at the beginning of the - ;; line, just call as usual - ad-do-it)) - - (defadvice sp-backward-kill-word (around sp-backward-delete-word-remove-indentation activate) - ;; when after whitespace at the beginning of a line or - ;; an Org bullet or heading, delete it all. This is - ;; more intuitive when C-w is one's main way to delete - ;; stuff - (if (and - ;; do it if we're not at the beginning of the line, - ;; and there's whitespace: if we're at the - ;; beginning of the line we should always delete - (not (equal (point) (line-beginning-position))) - (or - (looking-back "^[[:space:]]+") - (looking-back "^[[:space:]]*- ") - (looking-back "^[*]+ "))) - (kill-line 0) - ;; if not after whitespace at the beginning of the - ;; line, just call as usual - ad-do-it)) - - ;; define some additional pairings for Org-mode - (sp-local-pair 'org-mode "=" "=") ; verbatim - ;; (sp-local-pair 'org-mode "*" "*") - ;; (sp-local-pair 'org-mode "/" "/") - ;; (sp-local-pair 'org-mode "~" "~") ; code - ;; (sp-local-pair 'org-mode "+" "+") - ;; (sp-local-pair 'org-mode "_" "_") - - (defadvice sp--cleanup-after-kill (after haskell-sp-unindent activate) - (when hi2-mode - (hi2-indent-backwards))) - - )) + :commands (smartparens-strict-mode + smartparens-mode + show-smartparens-global-mode) + :defer 5 + :init + + (dolist (hook '(emacs-lisp-mode-hook + lisp-mode-hook + lisp-interaction-mode-hook + ielm-mode-hook + scheme-mode-hook + inferior-scheme-mode-hook + python-mode-hook + minibuffer-setup-hook + haskell-mode-hook)) + (add-hook hook + (lambda () + (smartparens-strict-mode 1)))) + + :config + + (require 'smartparens-config) + (setq sp-navigate-consider-symbols t) + + ;; global smartparens bindings + (sp-use-smartparens-bindings) + (bind-key "C-w" 'sp-backward-kill-word emacs-lisp-mode-map) + (bind-key "C-k" 'sp-kill-hybrid-sexp emacs-lisp-mode-map) + (bind-key "M-" 'sp-raise-sexp smartparens-mode-map) + + ;; and now undo some of that in particular major modes + (add-hook 'org-mode-hook (lambda () + (crowding/local-set-minor-mode-key + 'smartparens-mode (kbd "M-") nil))) + + ;; override smartparens binding for C-k outside of lisp, + ;; since sp-kill-hybrid-sexp isn't very smart in comint + ;; and I like using C-u C-k + ;; (define-key smartparens-strict-mode-map [remap kill-line] 'kill-line) + ;; (bind-key "C-k" 'sp-kill-hybrid-sexp + ;; emacs-lisp-mode-map) + + (defadvice sp-backward-kill-word (after sp-backward-kill-word-fix-punctuation activate) + ;; when killing the first word of a sentence, leave the + ;; two spaces after the previous sentence's terminal + ;; period + (save-excursion + (backward-char 2) + (if (and + (or + (looking-at "\\. ") + (looking-at "! ") + (looking-at "\\? ")) + (not (looking-back "^[1-9]+"))) + (progn + (forward-char 1) + (insert " "))))) + + ;; fix cursor position after M-d at the beginning of a line + (defadvice sp-kill-word (after sp-kill-word-beg-of-line-fix activate) + (if (looking-back "^[[:space:]]") + (backward-char 1))) + + (defadvice sp-backward-delete-char (around sp-backward-delete-char-remove-indentation activate) + ;; when after whitespace at the beginning of a line or + ;; an Org bullet or heading, delete it all + (if (and + ;; do it if we're not at the beginning of the line, + ;; and there's whitespace: if we're at the + ;; beginning of the line we should always delete + (not (equal (point) (line-beginning-position))) + (or + (looking-back "^[[:space:]]+") + (looking-back "^[[:space:]]*- ") + (looking-back "^[*]+ "))) + (kill-line 0) + ;; if not after whitespace at the beginning of the + ;; line, just call as usual + ad-do-it)) + + (defadvice sp-backward-kill-word (around sp-backward-delete-word-remove-indentation activate) + ;; when after whitespace at the beginning of a line or + ;; an Org bullet or heading, delete it all. This is + ;; more intuitive when C-w is one's main way to delete + ;; stuff + (if (and + ;; do it if we're not at the beginning of the line, + ;; and there's whitespace: if we're at the + ;; beginning of the line we should always delete + (not (equal (point) (line-beginning-position))) + (or + (looking-back "^[[:space:]]+") + (looking-back "^[[:space:]]*- ") + (looking-back "^[*]+ "))) + (kill-line 0) + ;; if not after whitespace at the beginning of the + ;; line, just call as usual + ad-do-it)) + + ;; define some additional pairings for Org-mode + (sp-local-pair 'org-mode "=" "=") ; verbatim + ;; (sp-local-pair 'org-mode "*" "*") + ;; (sp-local-pair 'org-mode "/" "/") + ;; (sp-local-pair 'org-mode "~" "~") ; code + ;; (sp-local-pair 'org-mode "+" "+") + ;; (sp-local-pair 'org-mode "_" "_") + + (defadvice sp--cleanup-after-kill (after haskell-sp-unindent activate) + (when hi2-mode + (hi2-indent-backwards))) + (show-smartparens-global-mode 1)) ;;; Org (use-package org :ensure org-plus-contrib + :pin org :mode (("\\.org" . org-mode) ("\\.org_archive" . org-mode)) :commands (org-capture @@ -332,7 +331,8 @@ (use-package popwin :ensure :commands popwin-mode - :idle (popwin-mode 1)) + :defer 5 + :config (popwin-mode 1)) ;;; save my places in buffers; this is all the session management I need @@ -346,10 +346,11 @@ (use-package saveplace :init (setq-default save-place t save-place-file "~/.emacs.d/saveplace") - :idle (progn - (add-hook 'find-file-hook 'save-place-find-file-hook t) - (add-hook 'kill-emacs-hook 'save-place-kill-emacs-hook) - (add-hook 'kill-buffer-hook 'save-place-to-alist))) + :defer 5 + :config + (add-hook 'find-file-hook 'save-place-find-file-hook t) + (add-hook 'kill-emacs-hook 'save-place-kill-emacs-hook) + (add-hook 'kill-buffer-hook 'save-place-to-alist)) ;;; fix up whitespace around kill and yanking (package seems to be ;;; unavailable for download) @@ -369,7 +370,9 @@ (use-package openwith :ensure :commands openwith-mode - :idle (openwith-mode t)) + + :demand + :config (openwith-mode 1)) ;; thanks to openwith, the warning for large files can be at a much ;; larger threshold as the chances of hitting it are low (this is @@ -389,23 +392,25 @@ (use-package magit :ensure :diminish magit-auto-revert-mode - :config (progn + :demand + :config + + (setq magit-completing-read-function 'magit-ido-completing-read) - (setq magit-completing-read-function 'magit-ido-completing-read) + ;; C-c C-a to amend without any prompt + (defun magit-just-amend () + (interactive) + (save-window-excursion + (magit-with-refresh + (shell-command "git --no-pager commit --amend --reuse-message=HEAD")))) - ;; C-c C-a to amend without any prompt - (defun magit-just-amend () - (interactive) - (save-window-excursion - (magit-with-refresh - (shell-command "git --no-pager commit --amend --reuse-message=HEAD")))) - (bind-key "C-c C-a" 'magit-just-amend magit-status-mode-map) + (bind-key "C-c C-a" 'magit-just-amend magit-status-mode-map) - (use-package magit-annex :ensure) + (use-package magit-annex :ensure) - (use-package magit-wip - :diminish magit-wip-save-mode - :config (global-magit-wip-save-mode 1)))) + (use-package magit-wip + :diminish magit-wip-save-mode + :config (global-magit-wip-save-mode 1))) ;;; pointback mode: make sure that point is back where I left it when ;;; switching between buffers where at least one buffer is displayed @@ -414,7 +419,9 @@ (use-package pointback :ensure :commands global-pointback-mode - :idle (global-pointback-mode 1)) + :defer 5 + :config + (global-pointback-mode 1)) ;;; colour those parentheses @@ -428,9 +435,9 @@ (use-package rainbow-mode :ensure :commands rainbow-mode - :init (progn - (add-hook 'html-mode-hook 'rainbow-mode) - (add-hook 'css-mode-hook 'rainbow-mode))) + :init + (add-hook 'html-mode-hook 'rainbow-mode) + (add-hook 'css-mode-hook 'rainbow-mode)) ;;; keep reindenting lisp @@ -448,10 +455,9 @@ inferior-scheme-mode-hook)) (add-hook hook (lambda () - (turn-on-eldoc-mode) - ;; (diminish 'eldoc-mode) - (aggressive-indent-mode) - (rainbow-delimiters-mode t)))) + (eldoc-mode 1) + (aggressive-indent-mode 1) + (rainbow-delimiters-mode 1)))) ;;; boxquotes @@ -492,39 +498,40 @@ ;; :bind ("" . company-complete) ;; :idle (global-company-mode) :diminish company-mode - :config (progn - ;;; startup company - - (defun spw/company-prog-setup () - "Setup company mode carefully when its needed, rather than using the brash global-company-mode" - (company-mode 1) - (define-key (current-local-map) (kbd "M-/") 'company-complete) - ) - (add-hook 'prog-mode-hook 'spw/company-prog-setup) - ;; alternative approach: https://github.com/company-mode/company-mode/issues/94#issuecomment-40884387 - - ;; I like my C-w binding so move one of company's bindings - (define-key company-active-map "\C-w" nil) - (bind-key "M-o" 'company-show-location company-active-map) - - ;;; settings - - (setq company-idle-delay nil - company-minimum-prefix-length 0 - company-echo-delay 0) - - (add-to-list 'company-backends 'company-capf) - (add-to-list 'company-transformers 'company-sort-by-occurrence) - - ;;; python code completion - - (use-package anaconda-mode - :disabled t - :ensure - :config (progn - (add-hook 'python-mode-hook 'anaconda-mode) - (add-to-list 'company-backends 'company-anaconda) - (add-hook 'python-mode-hook 'anaconda-eldoc))))) + :config + + ;; startup company + + (defun spw/company-prog-setup () + "Setup company mode carefully when its needed, rather than using the brash global-company-mode" + (company-mode 1) + (define-key (current-local-map) (kbd "M-/") 'company-complete) + ) + (add-hook 'prog-mode-hook 'spw/company-prog-setup) + ;; alternative approach: https://github.com/company-mode/company-mode/issues/94#issuecomment-40884387 + + ;; I like my C-w binding so move one of company's bindings + (define-key company-active-map "\C-w" nil) + (bind-key "M-o" 'company-show-location company-active-map) + + ;; settings + + (setq company-idle-delay nil + company-minimum-prefix-length 0 + company-echo-delay 0) + + (add-to-list 'company-backends 'company-capf) + (add-to-list 'company-transformers 'company-sort-by-occurrence) + + ;; python code completion + + (use-package anaconda-mode + :disabled t + :ensure + :config (progn + (add-hook 'python-mode-hook 'anaconda-mode) + (add-to-list 'company-backends 'company-anaconda) + (add-hook 'python-mode-hook 'anaconda-eldoc)))) ;; C-o during company isearch narrows to stuff matching that search; ;; mnemonic 'occur'. C-M-s while outside of search to do the same ;; thing @@ -538,11 +545,14 @@ (use-package markdown-mode :ensure :mode "\\.md" - :init (progn - (add-hook 'markdown-mode-hook 'turn-on-orgstruct) - (add-hook 'markdown-mode-hook 'turn-on-orgstruct++)) + + :init + (add-hook 'markdown-mode-hook 'turn-on-orgstruct) + (add-hook 'markdown-mode-hook 'turn-on-orgstruct++) + + :config ;; This binding replaces a `markdown-export'. - :config (bind-key "C-c C-c e" 'spw/pandoc-paper-compile markdown-mode-map)) + (bind-key "C-c C-c e" 'spw/pandoc-paper-compile markdown-mode-map)) ;;; PHP mode @@ -552,6 +562,7 @@ (use-package deft :ensure + :commands deft :init (setq deft-extension "org" deft-text-mode 'org-mode deft-directory "~/doc/org/" @@ -560,17 +571,16 @@ deft-incremental-search t ;; don't just strip the leading hash but the whole #+TITLE: deft-strip-title-regexp "\\(?:\\#\\+TITLE\\: \\|\\#\\+FILETAGS\\: \\|^%+\\|^[#* ]+\\|-\\*-[[:alpha:]]+-\\*-\\|#+$\\)") - :config (progn - (bind-key "C-w" 'deft-filter-decrement-word deft-mode-map) - ;; (bind-key "C-h" 'deft-filter-decrement deft-mode-map) + :config + (bind-key "C-w" 'deft-filter-decrement-word deft-mode-map) - (defadvice deft (before persp-deft activate) - (projectile-persp-switch-project "~/doc")) + (defadvice deft (before persp-deft activate) + (projectile-persp-switch-project "~/doc")) - (defadvice deft-new-file (after insert-org-TITLE activate) - (save-excursion - (goto-char (point-min)) - (insert "#+TITLE: "))))) + (defadvice deft-new-file (after insert-org-TITLE activate) + (save-excursion + (goto-char (point-min)) + (insert "#+TITLE: ")))) ;;; The following two python packages seem to be unavailable for ;;; download. Disable them for now. @@ -588,33 +598,36 @@ (use-package flycheck :ensure - :idle (global-flycheck-mode) - ;; disable flymake; having both running at the same time is annoying - :init (setq flymake-allowed-file-name-masks nil)) + :defer 5 + :init + ;; try to disable flymake; having both running at the same time is annoying + (setq flymake-allowed-file-name-masks nil) + :config + (global-flycheck-mode 1)) ;;; TRAMP (use-package tramp - :config (progn - (add-to-list 'tramp-default-user-alist '(nil "sdf" "spw")) - (add-to-list 'tramp-default-user-alist '("sudo" "localhost" "root")) - (add-to-list 'tramp-default-user-alist '(nil nil "swhitton") t) - (add-to-list 'tramp-default-user-alist '(nil "ma" "spw")) - (add-to-list 'tramp-default-user-alist '(nil "sage" "spwhitton")) + :config + (add-to-list 'tramp-default-user-alist '(nil "sdf" "spw")) + (add-to-list 'tramp-default-user-alist '("sudo" "localhost" "root")) + (add-to-list 'tramp-default-user-alist '(nil nil "swhitton") t) + (add-to-list 'tramp-default-user-alist '(nil "ma" "spw")) + (add-to-list 'tramp-default-user-alist '(nil "sage" "spwhitton")) - ;; TRAMP and zsh are not friends so might as well switch - ;; over here - (setenv "SHELL" "/bin/bash"))) + ;; TRAMP and zsh are not friends so might as well switch + ;; over here + (setenv "SHELL" "/bin/bash")) ;;; ebib for editing BiBTeX databases (use-package ebib :ensure :bind ("C-c g e" . ebib) - :init (progn - (defadvice ebib (before spw/persp-ebib activate) - (persp-switch "ebib")) - (setq ebib-preload-bib-files '("~/doc/spw.bib")))) + :init + (defadvice ebib (before spw/persp-ebib activate) + (persp-switch "ebib")) + (setq ebib-preload-bib-files '("~/doc/spw.bib"))) ;;; dired enhancements @@ -637,59 +650,60 @@ (use-package projectile :ensure :commands projectile-vc - :init (projectile-global-mode) - :diminish 'projectile-mode - :config (progn - (setq projectile-switch-project-action 'projectile-dired - projectile-completion-system 'ido) - (diminish 'projectile-mode))) + :demand + :config + (projectile-global-mode 1) + (setq projectile-switch-project-action 'projectile-dired + projectile-completion-system 'ido) + (diminish 'projectile-mode)) (use-package persp-projectile :ensure) (use-package perspective :ensure :commands (persp-toggle persp-switch) - :init (progn - (setq persp-modestring-dividers '("" "" "|")) - - ;; activate persp mode, but don't activate it if it's - ;; already active cos this removes all existing perspectives - ;; which is annoying - (unless persp-mode - (persp-mode)) - - (defun persp-toggle (arg) - (interactive "P") - (if arg (call-interactively 'persp-switch) - (persp-switch (persp-find-some)))) - - ;; save and restore a base window configuration ala - ;; workgroups.el. Designed to handle the perennial Emacs - ;; problem of Emacs totally screwing up your windows in the - ;; middle of your work - (setq persp-basewcs nil) - (defun persp-basewc-save () - (interactive) - (let* ((name (persp-name persp-curr)) - (wc (current-window-configuration)) - (pair (cons name wc))) - (setq persp-basewcs - (remove* name persp-basewcs - :test 'equal :key 'car)) - (add-to-list 'persp-basewcs pair))) - ;; Save when opening a perspective. - (add-hook 'persp-created-hook 'persp-basewc-save) - ;; Also do a save of the basewc after - ;; `projectile-persp-switch-project' (I never use - ;; `projectile-switch-project' directly) switches to dired - ;; as this is a more sensible initial basewc to go back to. - (add-hook 'projectile-switch-project-hook 'persp-basewc-save) - (defun persp-basewc-restore () - (interactive) - (let* ((name (persp-name persp-curr)) - (pair (assoc name persp-basewcs)) - (wc (cdr pair))) - (set-window-configuration wc))))) + :demand + :config + (setq persp-modestring-dividers '("" "" "|")) + + ;; activate persp mode, but don't activate it if it's + ;; already active cos this removes all existing perspectives + ;; which is annoying + (unless persp-mode + (persp-mode)) + + (defun persp-toggle (arg) + (interactive "P") + (if arg (call-interactively 'persp-switch) + (persp-switch (persp-find-some)))) + + ;; save and restore a base window configuration ala + ;; workgroups.el. Designed to handle the perennial Emacs + ;; problem of Emacs totally screwing up your windows in the + ;; middle of your work + (setq persp-basewcs nil) + (defun persp-basewc-save () + (interactive) + (let* ((name (persp-name persp-curr)) + (wc (current-window-configuration)) + (pair (cons name wc))) + (setq persp-basewcs + (remove* name persp-basewcs + :test 'equal :key 'car)) + (add-to-list 'persp-basewcs pair))) + ;; Save when opening a perspective. + (add-hook 'persp-created-hook 'persp-basewc-save) + ;; Also do a save of the basewc after + ;; `projectile-persp-switch-project' (I never use + ;; `projectile-switch-project' directly) switches to dired + ;; as this is a more sensible initial basewc to go back to. + (add-hook 'projectile-switch-project-hook 'persp-basewc-save) + (defun persp-basewc-restore () + (interactive) + (let* ((name (persp-name persp-curr)) + (pair (assoc name persp-basewcs)) + (wc (cdr pair))) + (set-window-configuration wc)))) ;; completion with ido @@ -723,16 +737,17 @@ (use-package flx-ido :ensure - :init (progn - (flx-ido-mode 1) - (setq ido-enable-flex-matching t - ido-use-faces nil - flx-ido-threshhold 7500 - gc-cons-threshold 20000000))) + :config + (flx-ido-mode 1) + (setq ido-enable-flex-matching t + ido-use-faces nil + flx-ido-threshhold 7500 + gc-cons-threshold 20000000)) (use-package ido-ubiquitous :ensure - :init (ido-ubiquitous-mode 1)) + :config + (ido-ubiquitous-mode 1)) ;; (use-package ido-vertical-mode ;; :ensure @@ -740,7 +755,8 @@ (use-package smex :ensure - ;; TODO: get keyboard macro bindings back + ;; TODO: get keyboard macro bindings, that vanilla emacs has under + ;; the prefix C-x C-m, back :bind ("C-x C-m" . smex)) ;; imenu @@ -751,20 +767,25 @@ (use-package helm :ensure - :init - (progn - (use-package helm-mode - :bind ("M-s o" . helm-occur)) - (use-package helm-descbinds - :ensure - :idle (helm-descbinds-mode)))) + :defer 5 + :config + (use-package helm-mode + :bind ("M-s o" . helm-occur)) + (use-package helm-descbinds + :ensure + :defer 5 + :config + (helm-descbinds-mode))) ;;; snippets (use-package yasnippet :ensure :diminish yas-minor-mode - :idle (yas-global-mode)) + + :defer 5 + :config + (yas-global-mode 1)) ;;; htmlize for Org HTML export/publishing @@ -779,29 +800,33 @@ (use-package highlight-indentation :ensure - :init (progn - (add-hook 'python-mode-hook 'highlight-indentation-current-column-mode) - ;; (add-hook 'haskell-mode-hook 'highlight-indentation-current-column-mode) - )) + :init + (add-hook 'python-mode-hook 'highlight-indentation-current-column-mode)) ;;; jump around what's visible (use-package ace-jump-mode :ensure :bind ("M-o" . ace-jump-mode) + :config + ;; make `ace-jump-mode' respect dired-isearch-filenames ;; from https://www.reddit.com/r/emacs/comments/2x3mke/making_acejump_play_nice_with_dired/ - :config (add-hook 'dired-mode-hook - (lambda () - (setq-local ace-jump-search-filter - (lambda () - (get-text-property (point) 'dired-filename)))))) + ;; (add-hook 'dired-mode-hook + ;; (lambda () + ;; (setq-local ace-jump-search-filter + ;; (lambda () + ;; (get-text-property (point) 'dired-filename))))) + + ) ;;; use ace-jump-mode to move between links in help file (use-package ace-link :ensure - :idle (ace-link-setup-default)) + :defer 5 + :config + (ace-link-setup-default)) ;;; chat on Jabber @@ -885,44 +910,46 @@ (use-package whole-line-or-region :ensure :diminish whole-line-or-region-mode - :idle (whole-line-or-region-mode 1)) + :defer 5 + :config + (whole-line-or-region-mode 1)) (use-package hydra :ensure - :init (progn - (setq hydra-windows-config nil) - (defun spw/maybe-delete-other-windows () - (interactive) - (if (= (count-windows) 1) - (set-window-configuration hydra-windows-config) - (setq hydra-windows-config (current-window-configuration)) - (delete-other-windows))) - (defhydra hydra-windows (global-map "C-x" :color red) - "windows" - ("o" other-window "next" :color red) - ("O" (lambda () (interactive) (other-window -1)) "previous" :color red) - ("S" spw/toggle-window-split "toggle" :color red) - ("0" delete-window "del" :color red) - ("1" spw/maybe-delete-other-windows "max" :color red) - ("2" split-window-below "horiz" :color red) - ("3" split-window-right "vert" :color red)))) + :config + (setq hydra-windows-config nil) + (defun spw/maybe-delete-other-windows () + (interactive) + (if (= (count-windows) 1) + (set-window-configuration hydra-windows-config) + (setq hydra-windows-config (current-window-configuration)) + (delete-other-windows))) + (defhydra hydra-windows (global-map "C-x" :color red) + "windows" + ("o" other-window "next" :color red) + ("O" (lambda () (interactive) (other-window -1)) "previous" :color red) + ("S" spw/toggle-window-split "toggle" :color red) + ("0" delete-window "del" :color red) + ("1" spw/maybe-delete-other-windows "max" :color red) + ("2" split-window-below "horiz" :color red) + ("3" split-window-right "vert" :color red))) ;;; aligning rule for Haskell adapted from Haskell mode wiki (use-package align - :init (progn - (add-to-list 'align-rules-list - '(haskell-defns - (regexp . "\\(\\s-+\\)\\(::\\|∷\\|=\\)\\s-+") - (modes quote (haskell-mode literate-haskell-mode)))) - (add-to-list 'align-rules-list - '(haskell-arrows - (regexp . "^[^:\n]+\\(\\s-+\\)\\(->\\)\\s-+") - (modes quote (haskell-mode literate-haskell-mode)))) - (add-to-list 'align-rules-list - '(haskell-left-arrows - (regexp . "\\(\\s-+\\)\\(<-\\|←\\)\\s-+") - (modes quote (haskell-mode literate-haskell-mode)))))) + :config + (add-to-list 'align-rules-list + '(haskell-defns + (regexp . "\\(\\s-+\\)\\(::\\|∷\\|=\\)\\s-+") + (modes quote (haskell-mode literate-haskell-mode)))) + (add-to-list 'align-rules-list + '(haskell-arrows + (regexp . "^[^:\n]+\\(\\s-+\\)\\(->\\)\\s-+") + (modes quote (haskell-mode literate-haskell-mode)))) + (add-to-list 'align-rules-list + '(haskell-left-arrows + (regexp . "\\(\\s-+\\)\\(<-\\|←\\)\\s-+") + (modes quote (haskell-mode literate-haskell-mode))))) ;;; edit .nix files @@ -942,26 +969,26 @@ (use-package god-mode :ensure - :config (progn - ;; (unless god-global-mode (god-mode)) + :config + ;; (unless god-global-mode (god-mode)) - ;; activate with a key-chord to avoid having to have - ;; capslock bound to both escape and control - (key-chord-define-global "hj" 'god-mode-all) + ;; activate with a key-chord to avoid having to have + ;; capslock bound to both escape and control + (key-chord-define-global "hj" 'god-mode-all) - ;; just a little vi in god-mode - (define-key god-local-mode-map (kbd ".") 'repeat) - (define-key god-local-mode-map (kbd "i") 'god-mode-all) + ;; just a little vi in god-mode + (define-key god-local-mode-map (kbd ".") 'repeat) + (define-key god-local-mode-map (kbd "i") 'god-mode-all) - ;; change a part of the modeline depending on whether in god-mode - (defun spw/god-mode-update-modeline () - (set-face-background 'sml/filename (if god-local-mode - "red" - ;; following from smart-mode-line-powerline-theme.el - (or (face-background 'powerline-active1) "Grey30")))) + ;; change a part of the modeline depending on whether in god-mode + (defun spw/god-mode-update-modeline () + (set-face-background 'sml/filename (if god-local-mode + "red" + ;; following from smart-mode-line-powerline-theme.el + (or (face-background 'powerline-active1) "Grey30")))) - (add-hook 'god-mode-enabled-hook 'spw/god-mode-update-modeline) - (add-hook 'god-mode-disabled-hook 'spw/god-mode-update-modeline))) + (add-hook 'god-mode-enabled-hook 'spw/god-mode-update-modeline) + (add-hook 'god-mode-disabled-hook 'spw/god-mode-update-modeline)) ;; good key chords from ;; via @@ -992,7 +1019,7 @@ (use-package elisp-slime-nav :ensure - :commands turn-on-elisp-slime-nav-mode + :commands (turn-on-elisp-slime-nav-mode elisp-slime-nav-mode) :init (dolist (hook '(emacs-lisp-mode-hook ielm-mode-hook)) (add-hook hook 'elisp-slime-nav-mode))) diff --git a/.emacs.d/site-lisp/bind-key.el b/.emacs.d/site-lisp/bind-key.el index 2ddbae2f..5cace724 100644 --- a/.emacs.d/site-lisp/bind-key.el +++ b/.emacs.d/site-lisp/bind-key.el @@ -1,59 +1,60 @@ ;;; bind-key.el --- A simple way to manage personal keybindings -;; Copyright (C) 2012 John Wiegley +;; Copyright (c) 2012-2015 john wiegley ;; Author: John Wiegley +;; Maintainer: John Wiegley ;; Created: 16 Jun 2012 ;; Version: 1.0 ;; Keywords: keys keybinding config dotemacs ;; URL: https://github.com/jwiegley/use-package ;; This program is free software; you can redistribute it and/or -;; modify it under the terms of the GNU General Public License as -;; published by the Free Software Foundation; either version 2, or (at +;; modify it under the terms of the gnu general public license as +;; published by the free software foundation; either version 2, or (at ;; your option) any later version. ;; This program is distributed in the hope that it will be useful, but -;; WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;; General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; without any warranty; without even the implied warranty of +;; merchantability or fitness for a particular purpose. see the gnu +;; general public license for more details. + +;; You should have received a copy of the gnu general public license +;; along with gnu emacs; see the file copying. if not, write to the +;; free software foundation, inc., 59 temple place - suite 330, +;; boston, ma 02111-1307, usa. ;;; Commentary: ;; If you have lots of keybindings set in your .emacs file, it can be hard to ;; know which ones you haven't set yet, and which may now be overriding some -;; new default in a new Emacs version. This module aims to solve that +;; new default in a new emacs version. This module aims to solve that ;; problem. ;; ;; Bind keys as follows in your .emacs: ;; ;; (require 'bind-key) ;; -;; (bind-key "C-c x" 'my-ctrl-c-x-command) +;; (bind-key "c-c x" 'my-ctrl-c-x-command) ;; ;; If you want the keybinding to override all minor modes that may also bind ;; the same key, use the `bind-key*' form: ;; -;; (bind-key* "" 'other-window) +;; (bind-key* "" 'other-window) ;; -;; If you want to rebind a key only in a particular key, use: +;; If you want to rebind a key only in a particular keymap, use: ;; -;; (bind-key "C-c x" 'my-ctrl-c-x-command some-other-mode-map) +;; (bind-key "c-c x" 'my-ctrl-c-x-command some-other-mode-map) ;; ;; To unbind a key within a keymap (for example, to stop your favorite major ;; mode from changing a binding that you don't want to override everywhere), ;; use `unbind-key': ;; -;; (unbind-key "C-c x" some-other-mode-map) +;; (unbind-key "c-c x" some-other-mode-map) ;; -;; To bind multiple keys at once, or set up a prefix map, a -;; `bind-keys' macro is provided. It accepts keyword arguments, see -;; its documentation for detailed description. +;; To bind multiple keys at once, or set up a prefix map, a `bind-keys' macro +;; is provided. It accepts keyword arguments, please see its documentation +;; for a detailed description. ;; ;; To add keys into a specific map, use :map argument ;; @@ -61,17 +62,25 @@ ;; ("o" . dired-omit-mode) ;; ("a" . some-custom-dired-function)) ;; -;; To set up a prefix map, use :prefix-map and :prefix -;; arguments (both are required) +;; To set up a prefix map, use `:prefix-map' and `:prefix' arguments (both are +;; required) ;; ;; (bind-keys :prefix-map my-customize-prefix-map ;; :prefix "C-c c" ;; ("f" . customize-face) ;; ("v" . customize-variable)) ;; -;; You can combine all the keywords together. -;; Additionally, :prefix-docstring can be specified to set -;; documentation of created :prefix-map variable. +;; You can combine all the keywords together. Additionally, +;; `:prefix-docstring' can be specified to set documentation of created +;; `:prefix-map' variable. +;; +;; To bind multiple keys in a `bind-key*' way (to be sure that your bindings +;; will not be overridden by other modes), you may use `bind-keys*' macro: +;; +;; (bind-keys* +;; ("C-o" . other-window) +;; ("C-M-n" . forward-page) +;; ("C-M-p" . backward-page)) ;; ;; After Emacs loads, you can see a summary of all your personal keybindings ;; currently in effect with this command: @@ -82,6 +91,7 @@ ;; what the default was. Also, it will tell you if the key was rebound after ;; your binding it with `bind-key', and what it was rebound it to. +(require 'cl-lib) (require 'easy-mmode) (defgroup bind-key nil @@ -119,44 +129,55 @@ (add-to-list 'emulation-mode-map-alists `((override-global-mode . ,override-global-map))) -(defvar personal-keybindings nil) +(defvar personal-keybindings nil + "List of bindings performed by `bind-key'. +Elements have the form ((KEY . [MAP]) CMD ORIGINAL-CMD)") + +;;;###autoload (defmacro bind-key (key-name command &optional keymap) "Bind KEY-NAME to COMMAND in KEYMAP (`global-map' if not passed). -KEY-NAME may be a vector, in which case it passed straight to +KEY-NAME may be a vector, in which case it is passed straight to `define-key'. Or it may be a string to be interpreted as spelled-out keystrokes, e.g., \"C-c C-z\". See documentation of `edmacro-mode' for details." (let ((namevar (make-symbol "name")) (keyvar (make-symbol "key")) - (bindingvar (make-symbol "binding")) - (entryvar (make-symbol "entry"))) + (kdescvar (make-symbol "kdesc")) + (bindingvar (make-symbol "binding"))) `(let* ((,namevar ,key-name) (,keyvar (if (vectorp ,namevar) ,namevar (read-kbd-macro ,namevar))) + (,kdescvar (cons (if (stringp ,namevar) ,namevar + (key-description ,namevar)) + (quote ,keymap))) (,bindingvar (lookup-key (or ,keymap global-map) ,keyvar))) - (let ((,entryvar (assoc (cons ,namevar (quote ,keymap)) - personal-keybindings))) - (if ,entryvar - (setq personal-keybindings - (delq ,entryvar personal-keybindings)))) - (setq personal-keybindings - (cons (list (cons ,namevar (quote ,keymap)) - ,command - (unless (numberp ,bindingvar) ,bindingvar)) - personal-keybindings)) + (add-to-list 'personal-keybindings + (list ,kdescvar ,command + (unless (numberp ,bindingvar) ,bindingvar))) (define-key (or ,keymap global-map) ,keyvar ,command)))) +;;;###autoload (defmacro unbind-key (key-name &optional keymap) - `(bind-key ,key-name nil ,keymap)) + `(progn + (bind-key ,key-name nil ,keymap) + (setq personal-keybindings + (cl-delete-if #'(lambda (k) + ,(if keymap + `(and (consp (car k)) + (string= (caar k) ,key-name) + (eq (cdar k) ',keymap)) + `(and (stringp (car k)) + (string= (car k) ,key-name)))) + personal-keybindings)))) +;;;###autoload (defmacro bind-key* (key-name command) - `(progn - (bind-key ,key-name ,command) - (define-key override-global-map ,(read-kbd-macro key-name) ,command))) + `(bind-key ,key-name ,command override-global-map)) +;;;###autoload (defmacro bind-keys (&rest args) "Bind multiple keys at once. @@ -166,33 +187,54 @@ Accepts keyword arguments: these bindings :prefix - prefix key for these bindings :prefix-docstring - docstring for the prefix-map variable +:menu-name - optional menu string for prefix map The rest of the arguments are conses of keybinding string and a function symbol (unquoted)." - (let ((map (plist-get args :map)) - (doc (plist-get args :prefix-docstring)) - (prefix-map (plist-get args :prefix-map)) - (prefix (plist-get args :prefix)) - (key-bindings (progn - (while (keywordp (car args)) - (pop args) - (pop args)) - args))) - (when (or (and prefix-map - (not prefix)) - (and prefix - (not prefix-map))) + (let* ((map (plist-get args :map)) + (maps (if (listp map) map (list map))) + (doc (plist-get args :prefix-docstring)) + (prefix-map (plist-get args :prefix-map)) + (prefix (plist-get args :prefix)) + (menu-name (plist-get args :menu-name)) + (key-bindings (progn + (while (keywordp (car args)) + (pop args) + (pop args)) + args))) + (when (or (and prefix-map (not prefix)) + (and prefix (not prefix-map))) (error "Both :prefix-map and :prefix must be supplied")) - `(progn - ,@(when prefix-map - `((defvar ,prefix-map) - ,@(when doc `((put ',prefix-map 'variable-documentation ,doc))) - (define-prefix-command ',prefix-map) - (bind-key ,prefix ',prefix-map ,map))) - ,@(mapcar (lambda (form) - `(bind-key ,(car form) ',(cdr form) - ,(or prefix-map map))) - key-bindings)))) + (when (and menu-name (not prefix)) + (error "If :menu-name is supplied, :prefix must be too")) + (macroexp-progn + (append + (when prefix-map + `((defvar ,prefix-map) + ,@(when doc `((put ',prefix-map 'variable-documentation ,doc))) + ,@(if menu-name + `((define-prefix-command ',prefix-map nil ,menu-name)) + `((define-prefix-command ',prefix-map))) + ,@(if maps + (mapcar + #'(lambda (m) + `(bind-key ,prefix ',prefix-map ,m)) maps) + `((bind-key ,prefix ',prefix-map))))) + (apply + #'nconc + (mapcar (lambda (form) + (if prefix-map + `((bind-key ,(car form) ',(cdr form) ,prefix-map)) + (if maps + (mapcar + #'(lambda (m) + `(bind-key ,(car form) ',(cdr form) ,m)) maps) + `((bind-key ,(car form) ',(cdr form)))))) + key-bindings)))))) + +;;;###autoload +(defmacro bind-keys* (&rest args) + `(bind-keys :map override-global-map ,@args)) (defun get-binding-description (elem) (cond @@ -212,12 +254,9 @@ function symbol (unquoted)." "#") (t elem))) - ((keymapp elem) - (if (and bind-key-describe-special-forms - (symbolp elem) - (get elem 'variable-documentation)) - (format "%s" (get elem 'variable-documentation)) - "#")) + ;; must be a symbol, non-symbol keymap case covered above + ((and bind-key-describe-special-forms (keymapp elem)) + (get elem 'variable-documentation)) ((symbolp elem) elem) (t @@ -250,11 +289,13 @@ function symbol (unquoted)." (t (cons (string< (caar l) (caar r)) nil))))) +;;;###autoload (defun describe-personal-keybindings () "Display all the personal keybindings defined by `bind-key'." (interactive) (with-output-to-temp-buffer "*Personal Keybindings*" - (princ (format "Key name%s Command%s Comments\n%s %s ---------------------\n" + (princ (format (concat "Key name%s Command%s Comments\n%s %s " + "---------------------\n") (make-string (- (car bind-key-column-widths) 9) ? ) (make-string (- (cdr bind-key-column-widths) 8) ? ) (make-string (1- (car bind-key-column-widths)) ?-) @@ -263,13 +304,14 @@ function symbol (unquoted)." (dolist (binding (setq personal-keybindings (sort personal-keybindings - #'(lambda (l r) - (car (compare-keybindings l r)))))) + (lambda (l r) + (car (compare-keybindings l r)))))) (if (not (eq (cdar last-binding) (cdar binding))) (princ (format "\n\n%s\n%s\n\n" (cdar binding) - (make-string (+ 21 (car bind-key-column-widths) (cdr bind-key-column-widths)) ?-))) + (make-string (+ 21 (car bind-key-column-widths) + (cdr bind-key-column-widths)) ?-))) (if (and last-binding (cdr (compare-keybindings last-binding binding))) (princ "\n"))) @@ -287,7 +329,8 @@ function symbol (unquoted)." ) (let ((line (format - (format "%%-%ds%%-%ds%%s\n" (car bind-key-column-widths) (cdr bind-key-column-widths)) + (format "%%-%ds%%-%ds%%s\n" (car bind-key-column-widths) + (cdr bind-key-column-widths)) key-name (format "`%s\'" command-desc) (if (string= command-desc at-present-desc) (if (or (null was-command) @@ -302,7 +345,9 @@ function symbol (unquoted)." (setq last-binding binding))))) (provide 'bind-key) + ;; Local Variables: ;; indent-tabs-mode: nil ;; End: + ;;; bind-key.el ends here diff --git a/.emacs.d/site-lisp/use-package.el b/.emacs.d/site-lisp/use-package.el index 36e7e0b7..6feb0d84 100644 --- a/.emacs.d/site-lisp/use-package.el +++ b/.emacs.d/site-lisp/use-package.el @@ -3,11 +3,12 @@ ;; Copyright (C) 2012 John Wiegley ;; Author: John Wiegley +;; Maintainer: John Wiegley ;; Created: 17 Jun 2012 -;; Version: 1.0 +;; Version: 2.0 ;; Package-Requires: ((bind-key "1.0") (diminish "0.44")) ;; Keywords: dotemacs startup speed config package -;; X-URL: https://github.com/jwiegley/use-package +;; URL: https://github.com/jwiegley/use-package ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as @@ -23,7 +24,7 @@ ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. - + ;;; Commentary: ;; The `use-package' declaration macro allows you to isolate package @@ -34,418 +35,1022 @@ ;; functionality! ;; ;; Please see README.md from the same repository for documentation. - + ;;; Code: (require 'bind-key) (require 'bytecomp) (require 'diminish nil t) +(require 'bytecomp) +(eval-when-compile (require 'cl)) -(when (fboundp 'declare-function) - (declare-function package-installed-p 'package)) +(declare-function package-installed-p 'package) (defgroup use-package nil "A use-package declaration for simplifying your `.emacs'." :group 'startup) (defcustom use-package-verbose nil - "Whether to report about loading and configuration details." + "Whether to report about loading and configuration details. + +If you customize this, then you should require the `use-package' +feature in files that use `use-package', even if these files only +contain compiled expansions of the macros. If you don't do so, +then the expanded macros do their job silently." :type 'boolean :group 'use-package) -(defcustom use-package-minimum-reported-time 0.01 - "Minimal load time that will be reported" - :type 'number +(defcustom use-package-debug nil + "Whether to display use-package expansions in a *use-package* buffer." + :type 'boolean :group 'use-package) -(defcustom use-package-idle-interval 3 - "Time to wait when using :idle in a `use-package' specification." +(defcustom use-package-always-ensure nil + "Treat every package as though it had specified `:ensure SEXP`." + :type 'sexp + :group 'use-package) + +(defcustom use-package-minimum-reported-time 0.1 + "Minimal load time that will be reported. + +Note that `use-package-verbose' has to be set to t, for anything +to be reported at all. + +If you customize this, then you should require the `use-package' +feature in files that use `use-package', even if these files only +contain compiled expansions of the macros. If you don't do so, +then the expanded macros do their job silently." :type 'number :group 'use-package) -(defmacro use-package-with-elapsed-timer (text &rest body) +(defcustom use-package-inject-hooks nil + "If non-nil, add hooks to the `:init' and `:config' sections. +In particular, for a given package `foo', the following hooks +become available: + + `use-package--foo--pre-init-hook' + `use-package--foo--post-init-hook' + `use-package--foo--pre-config-hook' + `use-package--foo--post-config-hook' + +This way, you can add to these hooks before evalaution of a +`use-package` declaration, and exercise some control over what +happens. + +Note that if either `pre-init' hooks returns a nil value, that +block's user-supplied configuration is not evaluated, so be +certain to return `t' if you only wish to add behavior to what +the user specified." + :type 'boolean + :group 'use-package) + +(defcustom use-package-keywords + '(:disabled + :pin + :ensure + :if + :when + :unless + :requires + :load-path + :preface + :no-require + :bind + :bind* + :bind-keymap + :bind-keymap* + :interpreter + :mode + :commands + :defines + :functions + :defer + :demand + :init + :config + :diminish + :delight) + "Establish which keywords are valid, and the order they are processed in. + +Note that `:disabled' is special, in that it causes nothing at all to happen, +even if the rest of the use-package declaration is incorrect." + :type '(repeat symbol) + :group 'use-package) + +(defcustom use-package-expand-minimally nil + "If non-nil, make the expanded code as minimal as possible. +This disables: + - Printing to the *Messages* buffer of slowly-evaluating forms + - Capture of load errors (normally redisplayed as warnings) + - Conditional loading of packages (load failures become errors) +The only advantage is that, if you know your configuration works, +then your byte-compiled init file is as minimal as possible." + :type 'boolean + :group 'use-package) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Utility functions +;; + +(defun use-package-expand (name label form) + "FORM is a list of forms, so `((foo))' if only `foo' is being called." (declare (indent 1)) - (let ((nowvar (make-symbol "now"))) - `(if use-package-verbose - (let ((,nowvar (current-time))) - (message "%s..." ,text) - (prog1 (progn ,@body) - (let ((elapsed - (float-time (time-subtract (current-time) ,nowvar)))) - (if (> elapsed ,use-package-minimum-reported-time) - (message "%s...done (%.3fs)" ,text elapsed) - (message "%s...done" ,text))))) - ,@body))) - -(put 'use-package-with-elapsed-timer 'lisp-indent-function 1) - -(defvar use-package-idle-timer nil) -(defvar use-package-idle-forms (make-hash-table)) - -(defun use-package-start-idle-timer () - "Ensure that the idle timer is running." - (unless use-package-idle-timer - (setq use-package-idle-timer - (run-with-idle-timer - use-package-idle-interval t - 'use-package-idle-eval)))) - -(defun use-package-init-on-idle (form priority) - "Add a new form to the idle queue." - (use-package-start-idle-timer) - (puthash priority - (append (gethash priority use-package-idle-forms) - (list form)) - use-package-idle-forms)) - -(defun use-package-idle-priorities () - "Get a list of all priorities in the idle queue. -The list is sorted in the order forms should be run." - (let ((priorities nil)) - (maphash (lambda (priority forms) - (setq priorities (cons priority priorities))) - use-package-idle-forms) - (sort priorities '<))) - -(defun use-package-idle-pop () - "Pop the top-priority task from the idle queue. -Return nil when the queue is empty." - (let* ((priority (car (use-package-idle-priorities))) - (forms (gethash priority use-package-idle-forms)) - (first-form (car forms)) - (forms-remaining (cdr forms))) - (if forms-remaining - (puthash priority forms-remaining use-package-idle-forms) - (remhash priority use-package-idle-forms)) - first-form)) - -(defun use-package-idle-eval() - "Start to eval idle-commands from the idle queue." - (let ((next (use-package-idle-pop))) - (if next - (progn - (when use-package-verbose - (message "use-package idle:%s" next)) - - (condition-case e - (funcall next) + (when form + (if use-package-expand-minimally + form + (let ((err (make-symbol "err"))) + (list + `(condition-case-unless-debug ,err + ,(macroexp-progn form) (error - (message - "Failure on use-package idle. Form: %s, Error: %s" - next e))) - ;; recurse after a bit - (when (sit-for use-package-idle-interval) - (use-package-idle-eval))) - ;; finished (so far!) - (cancel-timer use-package-idle-timer) - (setq use-package-idle-timer nil)))) + (ignore + (display-warning 'use-package + (format "%s %s: %s" + ,name ,label (error-message-string ,err)) + :error))))))))) + +(put 'use-package-expand 'lisp-indent-function 'defun) + +(defun use-package-hook-injector (name-string keyword body) + "Wrap pre/post hook injections around a given keyword form. +ARGS is a list of forms, so `((foo))' if only `foo' is being called." + (if (not use-package-inject-hooks) + (use-package-expand name-string (format "%s" keyword) body) + (let ((keyword-name (substring (format "%s" keyword) 1))) + (when body + `((when ,(macroexp-progn + (use-package-expand name-string (format "pre-%s hook" keyword) + `(run-hook-with-args-until-failure + ',(intern (concat "use-package--" name-string + "--pre-" keyword-name "-hook"))))) + ,(macroexp-progn + (use-package-expand name-string (format "%s" keyword) body)) + ,(macroexp-progn + (use-package-expand name-string (format "post-%s hook" keyword) + `(run-hooks + ',(intern (concat "use-package--" name-string + "--post-" keyword-name "-hook"))))))))))) + +(defun use-package--with-elapsed-timer (text body) + "BODY is a list of forms, so `((foo))' if only `foo' is being called." + (declare (indent 1)) + (if use-package-expand-minimally + body + (let ((nowvar (make-symbol "now"))) + (if (bound-and-true-p use-package-verbose) + `((let ((,nowvar (current-time))) + (message "%s..." ,text) + (prog1 + ,(macroexp-progn body) + (let ((elapsed + (float-time (time-subtract (current-time) ,nowvar)))) + (if (> elapsed ,use-package-minimum-reported-time) + (message "%s...done (%.3fs)" ,text elapsed) + (message "%s...done" ,text)))))) + body)))) + +(put 'use-package--with-elapsed-timer 'lisp-indent-function 1) + +(defsubst use-package-error (msg) + "Report MSG as an error, so the user knows it came from this package." + (error "use-package: %s" msg)) + +(defsubst use-package-plist-maybe-put (plist property value) + "Add a VALUE for PROPERTY to PLIST, if it does not already exist." + (if (plist-member plist property) + plist + (plist-put plist property value))) + +(defsubst use-package-plist-cons (plist property value) + "Cons VALUE onto the head of the list at PROPERTY in PLIST." + (plist-put plist property (cons value (plist-get plist property)))) + +(defsubst use-package-plist-append (plist property value) + "Append VALUE onto the front of the list at PROPERTY in PLIST." + (plist-put plist property (append value (plist-get plist property)))) + +(defun use-package-plist-delete (plist property) + "Delete PROPERTY from PLIST. +This is in contrast to merely setting it to 0." + (let (p) + (while plist + (if (not (eq property (car plist))) + (setq p (plist-put p (car plist) (nth 1 plist)))) + (setq plist (cddr plist))) + p)) + +(defun use-package-split-list (pred xs) + (let ((ys (list nil)) (zs (list nil)) flip) + (dolist (x xs) + (if flip + (nconc zs (list x)) + (if (funcall pred x) + (progn + (setq flip t) + (nconc zs (list x))) + (nconc ys (list x))))) + (cons (cdr ys) (cdr zs)))) + +(defun use-package-keyword-index (keyword) + (loop named outer + with index = 0 + for k in use-package-keywords do + (if (eq k keyword) + (return-from outer index)) + (incf index))) + +(defun use-package-sort-keywords (plist) + (let (plist-grouped) + (while plist + (push (cons (car plist) (cadr plist)) + plist-grouped) + (setq plist (cddr plist))) + (let (result) + (dolist (x + (nreverse + (sort plist-grouped + #'(lambda (l r) (< (use-package-keyword-index (car l)) + (use-package-keyword-index (car r))))))) + (setq result (cons (car x) (cons (cdr x) result)))) + result))) + +(defsubst use-package-concat (&rest elems) + "Delete all empty lists from ELEMS (nil or (list nil)), and append them." + (apply #'nconc (delete nil (delete (list nil) elems)))) + +(defconst use-package-font-lock-keywords + '(("(\\(use-package\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?" + (1 font-lock-keyword-face) + (2 font-lock-constant-face nil t)))) + +(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Keyword processing +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Normalization functions +;; + +(defun use-package-normalize-plist (name-symbol input) + "Given a pseudo-plist, normalize it to a regular plist." + (unless (null input) + (let* ((keyword (car input)) + (xs (use-package-split-list #'keywordp (cdr input))) + (args (car xs)) + (tail (cdr xs)) + (normalizer (intern (concat "use-package-normalize/" + (symbol-name keyword)))) + (arg + (cond + ((eq keyword :disabled) + (use-package-normalize-plist name-symbol tail)) + ((functionp normalizer) + (funcall normalizer name-symbol keyword args)) + ((= (length args) 1) + (car args)) + (t + args)))) + (if (memq keyword use-package-keywords) + (cons keyword + (cons arg (use-package-normalize-plist name-symbol tail))) + (use-package-error (format "Unrecognized keyword: %s" keyword)))))) + +(defun use-package-process-keywords (name-symbol plist &optional state) + "Process the next keyword in the free-form property list PLIST. +The values in the PLIST have each been normalized by the function +use-package-normalize/KEYWORD (minus the colon). + +STATE is a property list that the function may modify and/or +query. This is useful if a package defines multiple keywords and +wishes them to have some kind of stateful interaction. + +Unless the KEYWORD being processed intends to ignore remaining +keywords, it must call this function recursively, passing in the +plist with its keyword and argument removed, and passing in the +next value for the STATE." + (unless (null plist) + (let* ((keyword (car plist)) + (arg (cadr plist)) + (rest (cddr plist))) + (unless (keywordp keyword) + (use-package-error (format "%s is not a keyword" keyword))) + (let* ((handler (concat "use-package-handler/" (symbol-name keyword))) + (handler-sym (intern handler))) + (if (functionp handler-sym) + (funcall handler-sym name-symbol keyword arg rest state) + (use-package-error + (format "Keyword handler not defined: %s" handler))))))) + +(put 'use-package-process-keywords 'lisp-indent-function 'defun) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :pin +;; + +(defun use-package-only-one (label args f) + "Call F on the first member of ARGS if it has exactly one element." + (declare (indent 1)) + (cond + ((and (listp args) (listp (cdr args)) + (= (length args) 1)) + (funcall f label (car args))) + (t + (use-package-error + (concat label " wants exactly one argument"))))) + +(put 'use-package-only-one 'lisp-indent-function 'defun) + +(defun use-package-normalize/:pin (name-symbol keyword args) + (use-package-only-one (symbol-name keyword) args + (lambda (label arg) + (cond + ((stringp arg) arg) + ((symbolp arg) (symbol-name arg)) + (t + (use-package-error + ":pin wants an archive name (a string)")))))) + +(eval-when-compile + (defvar package-pinned-packages) + (defvar package-archives)) + +(defun use-package--archive-exists-p (archive) + "Check if a given ARCHIVE is enabled. + +ARCHIVE can be a string or a symbol or 'manual to indicate a +manually updated package." + (if (member archive '(manual "manual")) + 't + (let ((valid nil)) + (dolist (pa package-archives) + (when (member archive (list (car pa) (intern (car pa)))) + (setq valid 't))) + valid))) + +(defun use-package-pin-package (package archive) + "Pin PACKAGE to ARCHIVE." + (unless (boundp 'package-pinned-packages) + (setq package-pinned-packages ())) + (let ((archive-symbol (if (symbolp archive) archive (intern archive))) + (archive-name (if (stringp archive) archive (symbol-name archive)))) + (if (use-package--archive-exists-p archive-symbol) + (push (cons package archive-name) package-pinned-packages) + (error "Archive '%s' requested for package '%s' is not available." + archive-name package)) + (package-initialize t))) + +(defun use-package-handler/:pin (name-symbol keyword archive-name rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + ;; This happens at macro expansion time, not when the expanded code is + ;; compiled or evaluated. + (if (null archive-name) + body + (use-package-pin-package name-symbol archive-name) + (use-package-concat + body + `((push '(,name-symbol . ,archive-name) + package-pinned-packages) + t))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :ensure +;; + +(defun use-package-normalize/:ensure (name-symbol keyword args) + (if (null args) + t + (use-package-only-one (symbol-name keyword) args + (lambda (label arg) + (if (symbolp arg) + arg + (use-package-error + (concat ":ensure wants an optional package name " + "(an unquoted symbol name)"))))))) (defun use-package-ensure-elpa (package) (when (not (package-installed-p package)) (package-install package))) -(defvar use-package-keywords - '( - :bind - :commands - :config - :defer - :defines - :demand - :diminish - :disabled - :ensure - :idle - :idle-priority - :if - :init - :interpreter - :load-path - :mode - :pre-init - :pre-load - :requires - ) - "Keywords recognized by `use-package'.") - -(defun use-package-mplist-get (plist prop) - "Get the values associated to PROP in PLIST, a modified plist. - -A modified plist is one where keys are keywords and values are -all non-keywords elements that follow it. - -As a special case : if the first occurrence of the keyword PROP -is followed by another keyword or is the last element in the -list, the function returns t. - -Currently this function infloops when the list is circular." - (let ((tail plist) - found - result) - (while (and - (consp tail) - (not - (eq prop (car tail)))) - (pop tail)) - (when (eq prop (pop tail)) - (setq found t)) - (while (and (consp tail) - (not (keywordp (car tail)))) - (push (pop tail) result)) - (or (nreverse result) found))) - -(defun use-package-plist-get (plist prop) - "Compatibility layer between classical and modified plists. - -If `use-package-mplist-get' returns exactly one value, that is -returned ; otherwise the list is returned wrapped in a `progn'." - (let ((values (use-package-mplist-get plist prop))) - (when values - (cond ((not (listp values)) - values) - ((eq 1 (length values)) - (car values)) - (t (cons 'progn values)))))) - -(defun use-package-mplist-keys (plist) - "Get the keys in PLIST, a modified plist. - -A modified plist is one where properties are keywords and values -are all non-keywords elements that follow it." - (let ((result)) - (mapc (lambda (elt) - (when (keywordp elt) - (push elt result))) - plist) - (nreverse result))) - -(defun use-package-validate-keywords (args) - "Error if any keyword given in ARGS is not recognized. -Return the list of recognized keywords." - (mapc - (function - (lambda (keyword) - (unless (memq keyword use-package-keywords) - (error "Unrecognized keyword: %s" keyword)))) - (use-package-mplist-keys args))) - -(defun use-package-plist-get-value (plist prop) - "Return the value of PROP in PLIST as if it was backquoted." - (eval (list '\` (use-package-plist-get plist prop)))) +(defun use-package-handler/:ensure (name-symbol keyword ensure rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + ;; This happens at macro expansion time, not when the expanded code is + ;; compiled or evaluated. + (let ((package-name (or (and (eq ensure t) name-symbol) ensure))) + (when package-name + (require 'package) + (use-package-ensure-elpa package-name))) + body)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :if, :when and :unless +;; + +(defsubst use-package-normalize-value (label arg) + "Normalize a value." + (cond ((symbolp arg) + `(symbol-value ',arg)) + ((functionp arg) + `(funcall #',arg)) + (t arg))) + +(defun use-package-normalize-test (name-symbol keyword args) + (use-package-only-one (symbol-name keyword) args + #'use-package-normalize-value)) + +(defalias 'use-package-normalize/:if 'use-package-normalize-test) +(defalias 'use-package-normalize/:when 'use-package-normalize-test) + +(defun use-package-normalize/:unless (name-symbol keyword args) + (not (use-package-only-one (symbol-name keyword) args + #'use-package-normalize-value))) + +(defun use-package-handler/:if (name-symbol keyword pred rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + `((when ,pred ,@body)))) + +(defalias 'use-package-handler/:when 'use-package-handler/:if) + +(defun use-package-handler/:unless (name-symbol keyword pred rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + `((unless ,pred ,@body)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :requires +;; + +(defun use-package-as-one (label args f) + "Call F on the first element of ARGS if it has one element, or all of ARGS." + (declare (indent 1)) + (if (and (listp args) (listp (cdr args))) + (if (= (length args) 1) + (funcall f label (car args)) + (funcall f label args)) + (use-package-error + (concat label " wants a list")))) + +(put 'use-package-as-one 'lisp-indent-function 'defun) + +(defun use-package-normalize-symbols (label arg &optional recursed) + "Normalize a list of symbols." + (cond + ((symbolp arg) + (list arg)) + ((and (not recursed) (listp arg) (listp (cdr arg))) + (mapcar #'(lambda (x) (car (use-package-normalize-symbols label x t))) arg)) + (t + (use-package-error + (concat label " wants a symbol, or list of symbols"))))) + +(defun use-package-normalize-symlist (name-symbol keyword args) + (use-package-as-one (symbol-name keyword) args + #'use-package-normalize-symbols)) + +(defalias 'use-package-normalize/:requires 'use-package-normalize-symlist) + +(defun use-package-handler/:requires (name-symbol keyword requires rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + (if (null requires) + body + `((when ,(if (listp requires) + `(not (member nil (mapcar #'featurep ',requires))) + `(featurep ',requires)) + ,@body))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :load-path +;; + +(defun use-package-normalize-paths (label arg &optional recursed) + "Normalize a list of filesystem paths." + (cond + ((or (symbolp arg) (functionp arg)) + (let ((value (use-package-normalize-value label arg))) + (use-package-normalize-paths label (eval value)))) + ((stringp arg) + (let ((path (if (file-name-absolute-p arg) + arg + (expand-file-name arg user-emacs-directory)))) + (list path))) + ((and (not recursed) (listp arg) (listp (cdr arg))) + (mapcar #'(lambda (x) + (car (use-package-normalize-paths label x t))) arg)) + (t + (use-package-error + (concat label " wants a directory path, or list of paths"))))) + +(defun use-package-normalize/:load-path (name-symbol keyword args) + (use-package-as-one (symbol-name keyword) args + #'use-package-normalize-paths)) + +(defun use-package-handler/:load-path (name-symbol keyword arg rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + (use-package-concat + (mapcar #'(lambda (path) + `(eval-and-compile (push ,path load-path))) arg) + body))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :no-require +;; + +(defun use-package-normalize-predicate (name-symbol keyword args) + (if (null args) + t + (use-package-only-one (symbol-name keyword) args + #'use-package-normalize-value))) + +(defalias 'use-package-normalize/:no-require 'use-package-normalize-predicate) + +(defun use-package-handler/:no-require (name-symbol keyword arg rest state) + ;; This keyword has no functional meaning. + (use-package-process-keywords name-symbol rest state)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :preface +;; + +(defun use-package-normalize-form (label args) + "Given a list of forms, return it wrapped in `progn'." + (unless (listp (car args)) + (use-package-error (concat label " wants a sexp or list of sexps"))) + (mapcar #'(lambda (form) + (if (and (consp form) + (eq (car form) 'use-package)) + (macroexpand form) + form)) args)) + +(defun use-package-normalize-forms (name-symbol keyword args) + (use-package-normalize-form (symbol-name keyword) args)) + +(defalias 'use-package-normalize/:preface 'use-package-normalize-forms) + +(defun use-package-handler/:preface (name-symbol keyword arg rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + (use-package-concat + (unless (null arg) + `((eval-and-compile ,@arg))) + body))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :bind, :bind* +;; + +(defsubst use-package-is-sympair (x &optional allow-vector) + "Return t if X has the type (STRING . SYMBOL)." + (and (consp x) + (or (stringp (car x)) + (and allow-vector (vectorp (car x)))) + (symbolp (cdr x)))) + +(defun use-package-normalize-pairs + (name-symbol label arg &optional recursed allow-vector) + "Normalize a list of string/symbol pairs." + (cond + ((or (stringp arg) (and allow-vector (vectorp arg))) + (list (cons arg name-symbol))) + ((use-package-is-sympair arg allow-vector) + (list arg)) + ((and (not recursed) (listp arg) (listp (cdr arg))) + (mapcar #'(lambda (x) (car (use-package-normalize-pairs + name-symbol label x t allow-vector))) arg)) + (t + (use-package-error + (concat label " wants a string, (string . symbol) or list of these"))))) + +(defun use-package-normalize-binder (name-symbol keyword args) + (use-package-as-one (symbol-name keyword) args + (lambda (label arg) + (use-package-normalize-pairs name-symbol label arg nil t)))) + +(defalias 'use-package-normalize/:bind 'use-package-normalize-binder) +(defalias 'use-package-normalize/:bind* 'use-package-normalize-binder) + +(defun use-package-handler/:bind + (name-symbol keyword arg rest state &optional override) + (let ((commands (mapcar #'cdr arg))) + (use-package-concat + (use-package-process-keywords name-symbol + (use-package-sort-keywords + (use-package-plist-maybe-put rest :defer t)) + (use-package-plist-append state :commands commands)) + `((ignore (,(if override 'bind-keys* 'bind-keys) ,@arg)))))) + +(defun use-package-handler/:bind* (name-symbol keyword arg rest state) + (use-package-handler/:bind name-symbol keyword arg rest state t)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :bind-keymap, :bind-keymap* +;; + +(defalias 'use-package-normalize/:bind-keymap 'use-package-normalize-binder) +(defalias 'use-package-normalize/:bind-keymap* 'use-package-normalize-binder) + +(defun use-package-autoload-keymap (keymap-symbol package override) + "Loads PACKAGE and then binds the key sequence used to invoke +this function to KEYMAP-SYMBOL. It then simulates pressing the +same key sequence a again, so that the next key pressed is routed +to the newly loaded keymap. + +This function supports use-package's :bind-keymap keyword. It +works by binding the given key sequence to an invocation of this +function for a particular keymap. The keymap is expected to be +defined by the package. In this way, loading the package is +deferred until the prefix key sequence is pressed." + (if (not (require package nil t)) + (use-package-error (format "Could not load package.el: %s" package)) + (if (and (boundp keymap-symbol) + (keymapp (symbol-value keymap-symbol))) + (let ((key (key-description (this-command-keys-vector))) + (keymap (symbol-value keymap-symbol))) + (if override + ;; eval form is necessary to avoid compiler error + `(eval `(bind-key* ,key ,keymap)) + (bind-key key keymap)) + (setq unread-command-events + (listify-key-sequence (this-command-keys-vector)))) + (use-package-error + (format "use-package: package.el %s failed to define keymap %s" + package keymap-symbol))))) + +(defun use-package-handler/:bind-keymap + (name-symbol keyword arg rest state &optional override) + (let* (commands + (form (mapcar + #'(lambda (binding) + (push (cdr binding) commands) + `(,(if override + 'bind-key* + 'bind-key) + ,(car binding) + #'(lambda () + (interactive) + (use-package-autoload-keymap + ',(cdr binding) ',name-symbol nil)))) arg))) + (use-package-concat + (use-package-process-keywords name-symbol + (use-package-sort-keywords + (use-package-plist-maybe-put rest :defer t)) + (use-package-plist-append state :commands commands)) + `((ignore ,@form))))) + +(defun use-package-handler/:bind-keymap* (name-symbol keyword arg rest state) + (use-package-handler/:bind-keymap name-symbol keyword arg rest state t)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :interpreter +;; + +(defun use-package-normalize-mode (name-symbol keyword args) + (use-package-as-one (symbol-name keyword) args + (apply-partially #'use-package-normalize-pairs name-symbol))) + +(defalias 'use-package-normalize/:interpreter 'use-package-normalize-mode) + +(defun use-package-handler/:interpreter (name-symbol keyword arg rest state) + (let* (commands + (form (mapcar #'(lambda (interpreter) + (push (cdr interpreter) commands) + `(push ',interpreter interpreter-mode-alist)) arg))) + (use-package-concat + (use-package-process-keywords name-symbol + (use-package-sort-keywords + (use-package-plist-maybe-put rest :defer t)) + (use-package-plist-append state :commands commands)) + `((ignore ,@form))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :mode +;; + +(defalias 'use-package-normalize/:mode 'use-package-normalize-mode) + +(defun use-package-handler/:mode (name-symbol keyword arg rest state) + (let* (commands + (form (mapcar #'(lambda (mode) + (push (cdr mode) commands) + `(push ',mode auto-mode-alist)) arg))) + (use-package-concat + (use-package-process-keywords name-symbol + (use-package-sort-keywords + (use-package-plist-maybe-put rest :defer t)) + (use-package-plist-append state :commands commands)) + `((ignore ,@form))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :commands +;; + +(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist) + +(defun use-package-handler/:commands (name-symbol keyword arg rest state) + ;; The actual processing for commands is done in :defer + (use-package-process-keywords name-symbol + (use-package-sort-keywords + (use-package-plist-maybe-put rest :defer t)) + (use-package-plist-append state :commands arg))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :defines +;; + +(defalias 'use-package-normalize/:defines 'use-package-normalize-symlist) + +(defun use-package-handler/:defines (name-symbol keyword arg rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + body)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :functions +;; + +(defalias 'use-package-normalize/:functions 'use-package-normalize-symlist) + +(defun use-package-handler/:functions (name-symbol keyword arg rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + (if (not (bound-and-true-p byte-compile-current-file)) + body + (use-package-concat + (unless (null arg) + `((eval-when-compile + ,@(mapcar + #'(lambda (fn) + `(declare-function ,fn ,(symbol-name name-symbol))) arg)))) + body)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :defer +;; + +(defalias 'use-package-normalize/:defer 'use-package-normalize-predicate) + +(defun use-package-handler/:defer (name-symbol keyword arg rest state) + (let ((body (use-package-process-keywords name-symbol rest + (plist-put state :deferred t))) + (name-string (symbol-name name-symbol))) + (use-package-concat + ;; Load the package after a set amount of idle time, if the argument to + ;; `:defer' was a number. + (when (numberp arg) + `((run-with-idle-timer ,arg nil #'require ',name-symbol nil t))) + + ;; Since we deferring load, establish any necessary autoloads, and also + ;; keep the byte-compiler happy. + (apply + #'nconc + (mapcar #'(lambda (command) + (append + `((unless (fboundp ',command) + (autoload #',command ,name-string nil t))) + (when (bound-and-true-p byte-compile-current-file) + `((eval-when-compile + (declare-function ,command ,name-string)))))) + (delete-dups (plist-get state :commands)))) + + body))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :demand +;; + +(defalias 'use-package-normalize/:demand 'use-package-normalize-predicate) + +(defun use-package-handler/:demand (name-symbol keyword arg rest state) + (use-package-process-keywords name-symbol rest + (use-package-plist-delete state :deferred))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :init +;; + +(defalias 'use-package-normalize/:init 'use-package-normalize-forms) + +(defun use-package-handler/:init (name-symbol keyword arg rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + (use-package-concat + ;; The user's initializations + (use-package-hook-injector (symbol-name name-symbol) :init arg) + body))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :config +;; + +(defalias 'use-package-normalize/:config 'use-package-normalize-forms) + +(defun use-package-handler/:config (name-symbol keyword arg rest state) + (let* ((body (use-package-process-keywords name-symbol rest state)) + (config-body + (if (equal arg '(t)) + body + (use-package--with-elapsed-timer + (format "Configuring package %s" name-symbol) + (use-package-concat + (use-package-hook-injector (symbol-name name-symbol) + :config arg) + body + (list t)))))) + (if (plist-get state :deferred) + (unless (or (null config-body) (equal config-body '(t))) + `((eval-after-load ',name-symbol + ',(macroexp-progn config-body)))) + (use-package--with-elapsed-timer + (format "Loading package %s" name-symbol) + (if use-package-expand-minimally + (use-package-concat + (list `(require ',name-symbol)) + config-body) + `((if (not (require ',name-symbol nil t)) + (ignore + (message (format "Could not load %s" ',name-symbol))) + ,@config-body))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :diminish + +(defun use-package-normalize-diminish (name-symbol label arg &optional recursed) + "Normalize the arguments to diminish down to a list of one of two forms: + SYMBOL + (SYMBOL . STRING)" + (cond + ((symbolp arg) + (list arg)) + ((stringp arg) + (list (cons (intern (concat (symbol-name name-symbol) "-mode")) arg))) + ((and (consp arg) (stringp (cdr arg))) + (list arg)) + ((and (not recursed) (listp arg) (listp (cdr arg))) + (mapcar #'(lambda (x) (car (use-package-normalize-diminish + name-symbol label x t))) arg)) + (t + (use-package-error + (concat label " wants a string, symbol, " + "(symbol . string) or list of these"))))) + +(defun use-package-normalize/:diminish (name-symbol keyword args) + (use-package-as-one (symbol-name keyword) args + (apply-partially #'use-package-normalize-diminish name-symbol))) + +(defun use-package-handler/:diminish (name-symbol keyword arg rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + (use-package-concat + (mapcar #'(lambda (var) + `(if (fboundp 'diminish) + ,(if (consp var) + `(diminish ',(car var) ,(cdr var)) + `(diminish ',var)))) + arg) + body))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; :delight +;; + +(defun use-package-normalize/:delight (name-symbol keyword args) + "Normalize arguments to delight." + (cond + ((and (= (length args) 1) + (symbolp (car args))) + (list (car args) nil name-symbol)) + ((and (= (length args) 2) + (symbolp (car args))) + (list (car args) (cadr args) name-symbol)) + ((and (= (length args) 3) + (symbolp (car args))) + args) + (t + (use-package-error ":delight expects same args as delight function")))) + +(defun use-package-handler/:delight (name-symbol keyword args rest state) + (let ((body (use-package-process-keywords name-symbol rest state))) + (use-package-concat + body + `((delight (quote ,(nth 0 args)) ,(nth 1 args) (quote ,(nth 2 args))) t)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; The main macro +;; (defmacro use-package (name &rest args) - "Use a package with configuration options. + "Declare an Emacs package by specifying a group of configuration options. -For full documentation. please see commentary. +For full documentation, please see the README file that came with +this file. Usage: (use-package package-name - :keyword option) - -:init Code to run when `use-package' form evals. -:bind Perform key bindings, and define autoload for bound - commands. -:commands Define autoloads for given commands. -:pre-load Code to run when `use-package' form evals and before - anything else. Unlike :init this form runs before the - package is required or autoloads added. -:mode Form to be added to `auto-mode-alist'. -:interpreter Form to be added to `interpreter-mode-alist'. -:defer Defer loading of package -- automatic - if :commands, :bind, :mode or :interpreter are used. -:demand Prevent deferred loading in all cases. -:config Runs if and when package loads. -:if Conditional loading. -:disabled Ignore everything. -:defines Define vars to silence byte-compiler. -:load-path Add to `load-path' before loading. -:diminish Support for diminish package (if it's installed). -:idle adds a form to run on an idle timer -:idle-priority schedules the :idle form to run with the given - priority (lower priorities run first). Default priority - is 5; forms with the same priority are run in the order in - which they are evaluated. -:ensure loads package using package.el if necessary." - (use-package-validate-keywords args) ; error if any bad keyword, ignore result - (let* ((commands (use-package-plist-get args :commands)) - (pre-init-body (use-package-plist-get args :pre-init)) - (pre-load-body (use-package-plist-get args :pre-load)) - (init-body (use-package-plist-get args :init)) - (config-body (use-package-plist-get args :config)) - (diminish-var (use-package-plist-get-value args :diminish)) - (defines (use-package-plist-get-value args :defines)) - (idle-body (use-package-plist-get args :idle)) - (idle-priority (use-package-plist-get args :idle-priority)) - (keybindings-alist (use-package-plist-get-value args :bind)) - (mode (use-package-plist-get-value args :mode)) - (mode-alist - (if (stringp mode) (cons mode name) mode)) - (interpreter (use-package-plist-get-value args :interpreter)) - (interpreter-alist - (if (stringp interpreter) (cons interpreter name) interpreter)) - (predicate (use-package-plist-get args :if)) - (pkg-load-path (use-package-plist-get-value args :load-path)) - (defines-eval (if (null defines) - nil - (if (listp defines) - (mapcar (lambda (var) `(defvar ,var)) defines) - `((defvar ,defines))))) - (requires (use-package-plist-get-value args :requires)) - (requires-test (if (null requires) - t - (if (listp requires) - `(not (member nil (mapcar #'featurep - (quote ,requires)))) - `(featurep (quote ,requires))))) - (name-string (if (stringp name) name (symbol-name name))) - (name-symbol (if (stringp name) (intern name) name))) - - ;; force this immediately -- one off cost - (unless (use-package-plist-get args :disabled) - - (let* ((ensure (use-package-plist-get args :ensure)) - (package-name - (or (and (eq ensure t) - name) - ensure))) - - (when package-name - (require 'package) - (use-package-ensure-elpa package-name))) - - - (if diminish-var - (setq config-body - `(progn - ,config-body - (ignore-errors - ,@(cond - ((stringp diminish-var) - `((diminish (quote ,(intern (concat name-string "-mode"))) - ,diminish-var))) - ((symbolp diminish-var) - `((diminish (quote ,diminish-var)))) - ((and (consp diminish-var) (stringp (cdr diminish-var))) - `((diminish (quote ,(car diminish-var)) ,(cdr diminish-var)))) - (t ; list of symbols or (symbol . "string") pairs - (mapcar (lambda (var) - (if (listp var) - `(diminish (quote ,(car var)) ,(cdr var)) - `(diminish (quote ,var)))) - diminish-var))))))) - - (if (and commands (symbolp commands)) - (setq commands (list commands))) - - - (when idle-body - (when (null idle-priority) - (setq idle-priority 5)) - (setq init-body - `(progn - (require 'use-package) - (use-package-init-on-idle (lambda () ,idle-body) ,idle-priority) - ,init-body))) - - - (let ((init-for-commands - (lambda (func sym-or-list) - (let ((cons-list (if (and (consp sym-or-list) - (stringp (car sym-or-list))) - (list sym-or-list) - sym-or-list))) - (if cons-list - (setq init-body - `(progn - ,init-body - ,@(mapcar #'(lambda (elem) - (push (cdr elem) commands) - (funcall func elem)) - cons-list)))))))) - - (funcall init-for-commands - #'(lambda (binding) - `(bind-key ,(car binding) - (quote ,(cdr binding)))) - keybindings-alist) - - (funcall init-for-commands - #'(lambda (mode) - `(add-to-list 'auto-mode-alist - (quote ,mode))) - mode-alist) - - (funcall init-for-commands - #'(lambda (interpreter) - `(add-to-list 'interpreter-mode-alist - (quote ,interpreter))) - interpreter-alist)) - - `(progn - ,pre-load-body - ,@(mapcar - #'(lambda (path) - `(add-to-list 'load-path - ,(if (file-name-absolute-p path) - path - (expand-file-name path user-emacs-directory)))) - (cond ((stringp pkg-load-path) - (list pkg-load-path)) - ((functionp pkg-load-path) - (funcall pkg-load-path)) - (t - pkg-load-path))) - - (eval-when-compile - (when (bound-and-true-p byte-compile-current-file) - ,@defines-eval - ,(if (stringp name) - `(load ,name t) - `(require ',name nil t)))) - - ,(if (and (or commands (use-package-plist-get args :defer)) - (not (use-package-plist-get args :demand))) - (let (form) - (mapc #'(lambda (command) - (push `(autoload (function ,command) - ,name-string nil t) form)) - commands) - - `(when ,(or predicate t) - ,pre-init-body - ,@form - ,init-body - ,(unless (null config-body) - `(eval-after-load ,(if (stringp name) name `',name) - `(,(lambda () - (if ,requires-test - (use-package-with-elapsed-timer - ,(format "Configuring package %s" name-string) - ,config-body)))))) - t)) - `(if (and ,(or predicate t) - ,requires-test) - (use-package-with-elapsed-timer - ,(format "Loading package %s" name-string) - (if (not ,(if (stringp name) - `(load ,name t) - `(require ',name nil t))) - (message "Could not load package %s" ,name-string) - ,pre-init-body - ,init-body - ,config-body - t)))))))) + [:keyword [option]]...) -(put 'use-package 'lisp-indent-function 'defun) +:init Code to run before PACKAGE-NAME has been loaded. +:config Code to run after PACKAGE-NAME has been loaded. Note that if + loading is deferred for any reason, this code does not execute + until the lazy load has occurred. +:preface Code to be run before everything except `:disabled'; this can + be used to define functions for use in `:if', or that should be + seen by the byte-compiler. -(defconst use-package-font-lock-keywords - '(("(\\(use-package\\(?:-with-elapsed-timer\\)?\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?" - (1 font-lock-keyword-face) - (2 font-lock-constant-face nil t)))) +:mode Form to be added to `auto-mode-alist'. +:interpreter Form to be added to `interpreter-mode-alist'. -(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords) +:commands Define autoloads for commands that will be defined by the + package. This is useful if the package is being lazily loaded, + and you wish to conditionally call functions in your `:init' + block that are defined in the package. + +:bind Bind keys, and define autoloads for the bound commands. +:bind* Bind keys, and define autoloads for the bound commands, + *overriding all minor mode bindings*. +:bind-keymap Bind a key prefix to an auto-loaded keymap defined in the + package. This is like `:bind', but for keymaps. +:bind-keymap* Like `:bind-keymap', but overrides all minor mode bindings + +:defer Defer loading of a package -- this is implied when using + `:commands', `:bind', `:bind*', `:mode' or `:interpreter'. + This can be an integer, to force loading after N seconds of + idle time, if the package has not already been loaded. +:demand Prevent deferred loading in all cases. + +:if EXPR Initialize and load only if EXPR evaluates to a non-nil value. +:disabled The package is ignored completely if this keyword is present. +:defines Declare certain variables to silence the byte-compiler. +:functions Declare certain functions to silence the byte-compiler. +:load-path Add to the `load-path' before attempting to load the package. +:diminish Support for diminish.el (if installed). +:ensure Loads the package using package.el if necessary. +:pin Pin the package to an archive." + (declare (indent 1)) + (unless (member :disabled args) + (let* ((name-symbol (if (stringp name) (intern name) name)) + (args0 (use-package-plist-maybe-put + (use-package-normalize-plist name-symbol args) + :config '(t))) + (args* (use-package-sort-keywords + (if use-package-always-ensure + (use-package-plist-maybe-put + args0 :ensure use-package-always-ensure) + args0)))) + + ;; When byte-compiling, pre-load the package so all its symbols are in + ;; scope. + (if (bound-and-true-p byte-compile-current-file) + (setq args* + (use-package-plist-cons + args* :preface + `(eval-when-compile + ,@(mapcar #'(lambda (var) `(defvar ,var)) + (plist-get args* :defines)) + (with-demoted-errors + ,(format "Cannot load %s: %%S" name-symbol) + ,(if use-package-verbose + `(message "Compiling package %s" ',name-symbol)) + ,(unless (plist-get args* :no-require) + `(require ',name-symbol))))))) + + (let ((body + (macroexp-progn + (use-package-process-keywords name-symbol args*)))) + (if use-package-debug + (display-buffer + (save-current-buffer + (let ((buf (get-buffer-create "*use-package*"))) + (with-current-buffer buf + (delete-region (point-min) (point-max)) + (emacs-lisp-mode) + (insert (pp-to-string body))) + buf)))) + body)))) + + +(put 'use-package 'lisp-indent-function 'defun) (provide 'use-package) + ;; Local Variables: ;; indent-tabs-mode: nil ;; End: + ;;; use-package.el ends here -- cgit v1.2.3