Refactor package management system

This commit is contained in:
Henrik Lissner 2017-02-11 00:46:42 -05:00
parent 85d5360c7c
commit 7ef87546cc
10 changed files with 335 additions and 288 deletions

View file

@ -15,13 +15,13 @@ autoremove: init.el
@$(EMACS) -l core/core.el -f 'doom/packages-autoremove'
autoloads: init.el
@$(EMACS) -l init.el -f 'doom/refresh-autoloads'
@$(EMACS) -l core/core.el -f 'doom/reload-autoloads'
compile: init.el clean-elc
@$(EMACS) -l init.el -f 'doom/byte-compile'
compile: init.el clean
@$(EMACS) -l core/core.el -f 'doom/recompile'
compile-lite: init.el clean-elc
@$(EMACS) -l core/core.el --eval '(doom/byte-compile t)'
compile-lite: init.el clean
@$(EMACS) -l core/core.el --eval '(doom/recompile t)'
clean:
@rm -fv init.elc

View file

@ -32,24 +32,24 @@ quelpa or nil (if not installed)."
list, whose car is NAME, and cdr the current version list and latest version
list of the package."
(doom-refresh-packages)
(let ((pkg (or (assq name package-alist)
(assq name package--builtins))))
(when pkg
(let* ((old-version (package-desc-version (cadr pkg)))
(new-version
(pcase (doom-package-backend name)
('quelpa
(let ((recipe (assq name quelpa-cache))
(dir (f-expand (symbol-name name) quelpa-build-dir))
(inhibit-message t))
(or (and (quelpa-setup-p) (quelpa-checkout recipe dir))
old-version)))
('elpa
(package-desc-version (cadr (assq name package-archive-contents)))))))
(when (stringp new-version)
(setq new-version (version-to-list new-version)))
(when (version-list-< old-version new-version)
(list name old-version new-version))))))
(-when-let (pkg (assq name package-alist))
(let* ((old-version (package-desc-version (cadr pkg)))
(new-version
(pcase (doom-package-backend name)
('quelpa
(let ((recipe (assq name quelpa-cache))
(dir (f-expand (symbol-name name) quelpa-build-dir))
(inhibit-message t))
(-if-let (ver (and (quelpa-setup-p) (quelpa-checkout recipe dir)))
(version-to-list ver)
old-version)))
('elpa
(let ((desc (cadr (assq name package-archive-contents))))
(when (package-desc-p desc)
(package-desc-version desc)))))))
(when (and (listp old-version) (listp new-version)
(version-list-< old-version new-version))
(list name old-version new-version)))))
;;;###autoload
(defun doom-get-packages (&optional backend)
@ -59,20 +59,19 @@ the quelpa recipe (if any).
BACKEND can be 'quelpa or 'elpa, and will instruct this function to return only
the packages relevant to that backend."
(doom-read-packages t)
(doom-initialize-packages t)
(unless (quelpa-setup-p)
(error "Could not initialize quelpa"))
(-non-nil
(--map (or (assq it doom-packages)
(list (car (assq it package-alist))))
(append (mapcar 'car doom-packages)
doom-protected-packages))))
(append doom-protected-packages
(mapcar 'car doom-packages)))))
;;;###autoload
(defun doom-get-outdated-packages ()
"Return a list of lists representing packages that are out of date. Each
element is a sublist, containing (PACKAGE-SYMBOL OLD-VERSION-LIST
NEW-VERSION-LIST).
"Return a list of packages that are out of date. Each element is a list,
containing (PACKAGE-SYMBOL OLD-VERSION-LIST NEW-VERSION-LIST).
Used by `doom/packages-update'."
(-non-nil (--map (doom-package-outdated-p (car it))
@ -84,7 +83,7 @@ Used by `doom/packages-update'."
depended on.
Used by `doom/packages-autoremove'."
(doom-read-packages t)
(doom-initialize-packages t)
(let ((package-selected-packages (append (mapcar 'car doom-packages) doom-protected-packages)))
(package--removable-packages)))
@ -97,64 +96,6 @@ that package's `@package' declaration.
Used by `doom/packages-install'."
(--remove (assq (car it) package-alist) (doom-get-packages)))
(defun doom--scrape-sexps (sym file)
(declare (indent defun))
(unless (f-exists-p file)
(error "%s does not exist" file))
(unless (symbolp sym)
(error "%s is not a valid symbol" sym))
(with-temp-buffer
(buffer-disable-undo)
(emacs-lisp-mode)
(insert-file-contents file nil nil nil t)
(goto-char (point-min))
(let ((regexp (concat "\\(^\\|\\s-\\)(" (symbol-name sym) " "))
sexps)
(while (re-search-forward regexp nil t)
(unless (nth 4 (syntax-ppss))
(save-excursion
(beginning-of-defun)
(push (cdr (sexp-at-point)) sexps))))
(reverse sexps))))
;;;###autoload
(defun doom-read-packages (&optional force-p nopackages)
"Parses your Emacs config to keep track of packages declared with `@package'
in `doom-packages' and enabled modules in `doom-modules'."
(doom-initialize)
(when (or force-p (not doom-modules) (not doom-packages))
(setq doom-modules
(let (paths mode enabled-modules)
(--each (doom--scrape-sexps '@doom (f-expand "init.el" doom-emacs-dir))
(dolist (module it)
(cond ((keywordp module)
(setq mode module))
((not mode)
(error "Malformed @doom call: no namespace for %s" module))
(t
(push (cons mode module) enabled-modules)))))
enabled-modules))
(unless nopackages
(setq package-pinned-packages nil
doom-packages nil)
(mapc (lambda (pkg) (cl-pushnew pkg doom-packages :key 'car))
(-map (lambda (mplist)
(@mplist mplist &delete
:preface :ensure :requires :no-require :bind :bind* :bind-keymap
:bind-keymap* :interpreter :mode :commands :defines :functions
:defer :init :after :demand :config :diminish :delight))
(--sort (string-greaterp (symbol-name (car it))
(symbol-name (car other)))
(-flatten-n
1 (mapcar (lambda (file)
(when (f-exists-p file)
(doom--scrape-sexps '@package file)))
(append (f-glob "core*.el" doom-core-dir)
(--map (doom-module-path (car it) (cdr it) "packages.el")
doom-modules)))))))
t)))
;;;###autoload
(defun doom*package-delete (name)
"Update `quelpa-cache' upon a successful `package-delete'."
@ -176,24 +117,12 @@ in `doom-packages' and enabled modules in `doom-modules'."
"Installs package NAME with optional quelpa RECIPE (see `quelpa-recipe' for an
example; the package name can be omitted)."
(doom-refresh-packages)
(doom-read-packages)
(doom-initialize-packages)
(when (package-installed-p name)
(error "%s is already installed, skipping" name))
(when (plist-get plist :disabled)
(error "%s is disabled, skipping" name))
(when (plist-get plist :load-path)
(error "%s has a local load-path, skipping" name))
(let ((needs (plist-get plist :needs)))
(when (and needs
(--any-p (not (rassq it doom-modules))
(-list needs)))
(error "%s doesn't have necessary dependencies (%s), skipping" needs)))
(let ((inhibit-message (not doom-debug-mode)))
(cond ((plist-get plist :recipe)
(let ((recipe (plist-get plist :recipe)))
(when (and recipe (= 0 (mod (length recipe) 2)))
(setq recipe (cons name recipe)))
(quelpa recipe)))
(let ((inhibit-message (not doom-debug-mode))
(recipe (plist-get plist :recipe)))
(cond (recipe (quelpa recipe))
(t (package-install name))))
(cl-pushnew (cons name plist) doom-packages :key 'car)
(package-installed-p name))
@ -210,7 +139,7 @@ appropriate."
(pcase (doom-package-backend name)
('quelpa
(let ((quelpa-upgrade-p t))
(quelpa it)
(quelpa (assq name quelpa-cache))
(setq quelpa-modified-p t)))
('elpa
(let ((desc (cadr (assq name package-alist)))
@ -293,10 +222,10 @@ appropriate."
(let ((-max-len (or (-max (--map (length (symbol-name (car it))) packages)) 10)))
(mapconcat
(lambda (pkg)
(format "+ %s %s\t-> %s"
(format "+ %s %s -> %s"
(s-pad-right (+ -max-len 2) " " (symbol-name (car pkg)))
(cadr pkg)
(cadr (cdr pkg))))
(s-pad-right 14 " " (doom--version-list-str (cadr pkg)))
(doom--version-list-str (caddr pkg))))
(--sort (string-lessp (symbol-name (car it))
(symbol-name (car other)))
packages)
@ -345,31 +274,51 @@ appropriate."
(doom-message "Finished!")))))
(defun doom--version-list-str (vlist)
(concat (number-to-string (car vlist))
"."
(number-to-string (cadr vlist))))
;;;###autoload
(defalias 'doom/install-package 'package-install)
;;;###autoload
(defun doom/delete-package (&optional package)
(defun doom/delete-package (package)
"Prompts the user with a list of packages and deletes the selected package.
Use this interactively. Use `doom-delete-package' for direct calls."
(interactive
(list (completing-read "Delete package: " (doom-get-packages))))
(if (package-installed-p package)
(message "%s %s"
(if (doom-delete-package package)
"Deleted"
"Failed to delete")
pkg)
(if (y-or-n-p (format "%s will be deleted. Confirm?" package))
(message "%s %s"
(if (doom-delete-package package)
"Deleted"
"Failed to delete")
pkg)
(message "Aborted"))
(message "%s isn't installed" package)))
;;;###autoload
(defun doom/update-package (&optional package)
"Use this instead of package.el's update interface."
(defun doom/update-package (package)
"Prompts the user with a list of outdated packages and updates the selected
package. Use this interactively. Use `doom-update-package' for direct
calls."
(declare (interactive-only t))
(interactive
(list (completing-read "Update package: " (doom-get-packages))))
(if (doom-package-outdated-p package)
(message "%s %s"
(if (doom-update-package package)
"Updated"
"Failed to update")
pkg)
(let ((packages (doom-get-outdated-packages)))
(list
(if packages
(completing-read "Update package: " (--map (symbol-name (car it)) packages))
(user-error "All packages are up-to-date")))))
(-if-let (desc (doom-package-outdated-p (intern package)))
(if (y-or-n-p (format "%s will be updated from %s to %s. Update?"
(car desc)
(doom--version-list-str (cadr desc))
(doom--version-list-str (caddr desc))))
(message "%s %s"
(if (doom-update-package package)
"Updated"
"Failed to update")
pkg)
(message "Aborted"))
(message "%s is up-to-date" package)))

View file

@ -93,7 +93,7 @@
;; Handles whitespace (tabs/spaces) settings externally. This way projects can
;; specify their own formatting rules.
(@package editorconfig :demand t
(@def-package editorconfig :demand t
:mode ("\\.?editorconfig$" . editorconfig-conf-mode)
:config (editorconfig-mode +1)
;; Show whitespace in tabs indentation mode
@ -101,7 +101,7 @@
(if indent-tabs-mode (whitespace-mode +1))))
;; Auto-close delimiters and blocks as you type
(@package smartparens :demand t
(@def-package smartparens :demand t
:init
(setq sp-autowrap-region nil ; let evil-surround handle this
sp-highlight-pair-overlay nil
@ -137,63 +137,56 @@
;; Autoloaded Plugins
;;
(@package ace-link :commands (ace-link-help ace-link-org))
(@def-package ace-link :commands (ace-link-help ace-link-org))
(@package ace-window
(@def-package ace-window
:commands ace-window
:config (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)
aw-scope 'frame
aw-background t))
(@package avy
(@def-package avy
:commands (avy-goto-char-2 avy-goto-line)
:config (setq avy-all-windows nil
avy-background t))
(@package command-log-mode
(@def-package command-log-mode
:commands (command-log-mode global-command-log-mode)
:config
(@set :popup "*command-log*" :size 40 :align 'right :noselect t)
(setq command-log-mode-auto-show t
command-log-mode-open-log-turns-on-mode t))
(@package emr
(@def-package emr
:commands (emr-show-refactor-menu emr-declare-command)
:config (emr-initialize)
(define-key popup-menu-keymap [escape] 'keyboard-quit))
(@package expand-region :commands (er/expand-region er/contract-region er/mark-symbol er/mark-word))
(@def-package expand-region :commands (er/expand-region er/contract-region er/mark-symbol er/mark-word))
(@package goto-last-change :commands goto-last-change)
(@def-package goto-last-change :commands goto-last-change)
(@package help-fns+ ; Improved help commands
(@def-package help-fns+ ; Improved help commands
:commands (describe-buffer describe-command describe-file
describe-keymap describe-option describe-option-of-type))
(@package imenu-anywhere
(@def-package imenu-anywhere
:commands (ido-imenu-anywhere ivy-imenu-anywhere helm-imenu-anywhere))
(@package imenu-list :commands imenu-list-minor-mode)
(@def-package imenu-list :commands imenu-list-minor-mode)
(@package pcre2el :commands rxt-quote-pcre)
(@def-package pcre2el :commands rxt-quote-pcre)
(@package rotate-text
:recipe (:fetcher github :repo "debug-ito/rotate-text.el")
(@def-package rotate-text
:commands (rotate-text rotate-text-backward)
:config (push '("true" "false") rotate-text-words))
(@package smart-forward
(@def-package smart-forward
:commands (smart-up smart-down smart-backward smart-forward))
(@package smex
:commands (smex smex-major-mode-commands)
:config
(setq smex-save-file (concat doom-cache-dir "/smex-items"))
(smex-initialize))
(@def-package swiper :commands (swiper swiper-all))
(@package swiper :commands (swiper swiper-all))
(@package wgrep
(@def-package wgrep
:commands (wgrep-setup wgrep-change-to-wgrep-mode)
:config
(@set :popup "^\\*ivy-occur counsel-ag" :size 25 :select t :regexp t)

View file

@ -26,21 +26,6 @@
byte-compile-current-file)
(error "__FILE__ is unset")))
(@package anaphora
:commands (awhen aif acond awhile))
(@package async
:commands (async-start
async-start-process
async-byte-recompile-directory))
(@package persistent-soft
:preface (defvar pcache-directory (concat doom-cache-dir "pcache/"))
:commands (persistent-soft-exists-p
persistent-soft-fetch
persistent-soft-flush
persistent-soft-store))
;;
;; Library

View file

@ -55,6 +55,8 @@ if you have byte-compiled your configuration (as intended).")
'(("gnu" . "http://elpa.gnu.org/packages/")
("melpa" . "http://melpa.org/packages/")
("org" . "http://orgmode.org/elpa/"))
;; I omit Marmalade because its packages are manually submitted rather
;; than pulled, so packages are often out of date with upstream.
use-package-always-defer t
use-package-always-ensure nil
@ -74,49 +76,19 @@ if you have byte-compiled your configuration (as intended).")
;; Bootstrap function
;;
(autoload 'use-package "use-package" nil nil 'macro)
(advice-add 'package-delete :after 'doom*package-delete)
(defmacro @doom (&rest packages)
"DOOM Emacs bootstrap macro. List the modules to load. Benefits from
byte-compilation."
(let (mode)
(dolist (p packages)
(cond ((keywordp p)
(setq mode p))
((not mode)
(error "No namespace specified on `@doom' for %s" p))
((eq p '*)
(let ((mode-name (substring (symbol-name mode) 1)))
(--map (setq doom-modules (append doom-modules (list (cons mode (f-base it)))))
(f-directories (f-expand mode-name doom-modules-dir)))))
(t
(setq doom-modules (append doom-modules (list (cons mode p))))))))
(unless noninteractive
`(let (file-name-handler-alist)
,@(mapcar (lambda (pkg) `(@load ,(car pkg) ,(cdr pkg)))
doom-modules)
(when (display-graphic-p)
(require 'server)
(unless (server-running-p)
(server-start)))
;; Benchmark
(format "Loaded %s packages in %s"
(- (length load-path) (length doom--base-load-path))
(emacs-init-time)))))
(defun doom-initialize (&optional force-p)
"Initialize installed packages (using package.el) and ensure the core packages
are installed. If you byte compile core/core.el, calls to `package.el' are
avoided to speed up startup."
;; This is called early during Emacs initialization, so we can only use native
;; emacs functions.
(unless (or doom-init-p force-p)
(setq load-path doom--base-load-path
package-activated-list nil)
(package-initialize t)
;; Sure, package-initialize fills the load-path, but it will error out on
;; missing packages. UNACCEPTAABBLLLE!
;; Sure, `package-initialize' fills the load-path, but when NO-ACTIVATE is
;; non-nil, it will error out on missing packages. UNACCEPTAABBLLLE!
(setq load-path (append load-path (directory-files package-user-dir t "^[a-zA-Z0-9]" t)))
;; Ensure cache folder exists
@ -143,99 +115,168 @@ avoided to speed up startup."
;; Remove package management keywords, I'll deal with the myself
(mapc (lambda (keyword) (setq use-package-keywords (delq keyword use-package-keywords)))
'(:ensure :pin))
(setq doom-init-p t)))
(defun doom-initialize-autoloads (&optional force-p)
"Ensures that an autoloads file exists and is loaded."
(unless (or (featurep 'autoloads)
(load doom-autoload-file t t))
(doom/refresh-autoloads)
(unless (file-exists-p doom-autoload-file)
(error "Autoloads file couldn't be generated"))))
(unless (ignore-errors (require 'autoloads doom-autoload-file t))
(unless noninteractive
(doom/reload-autoloads)
(unless (file-exists-p doom-autoload-file)
(error "Autoloads file couldn't be generated")))))
(defun doom-initialize-packages (&optional force-p)
"Parses your Emacs config to keep track of packages declared with `@package'
in `doom-packages' and enabled modules in `doom-modules'."
(doom-initialize force-p)
(when (or force-p (not doom-modules) (not doom-packages))
(setq doom-modules nil)
(let ((noninteractive t))
(mapc (lambda (file) (load file nil :nomessage))
(list (f-expand "packages.el" doom-core-dir)
(f-expand "init.el" doom-emacs-dir)))
;; Look up packages.el for enabled modules
(mapc (lambda (file) (load file :noerror :nomessage))
(--map (doom-module-path (car it) (cdr it) "packages.el")
(doom-module-pairs))))))
(defun doom-module-path (module submodule &optional file)
"Get the full path to a module: e.g. :lang emacs-lisp maps to
~/.emacs.d/modules/lang/emacs-lisp/ and will append FILE if non-nil."
(unless (keywordp module)
(error "Expected a keyword, got %s" module))
(unless (symbolp submodule)
(error "Expected a symbol, got %s" submodule))
(let ((module-name (substring (symbol-name module) 1))
(submodule-name (symbol-name submodule)))
(f-expand (concat module-name "/" submodule-name "/" file)
doom-modules-dir)))
(defun doom-module-pairs ()
"TODO"
(let (pairs module)
(dolist (modules doom-modules)
(setq module (car modules))
(dolist (submodule (cdr modules))
(push (cons module submodule) pairs)))
pairs))
(defun doom-module-loaded-p (module submodule)
"TODO"
(memq submodule (cdr (assq module doom-modules))))
(defun doom-enable-module (module submodule &optional force-p)
(unless (or force-p (doom-module-loaded-p module submodule))
(let ((sublist (assq module doom-modules)))
(if sublist
(setf sublist (cons sublist submodule))
(push (list module submodule) doom-modules)))))
(defun doom-enable-modules (modules)
"TODO"
(let (mode)
(dolist (m modules)
(cond ((keywordp m)
(setq mode m))
((not mode)
(error "No namespace specified on `@doom' for %s" m))
((eq m '*)
(let ((mode-str (substring (symbol-name mode) 1)))
(doom-enable-modules
(cons mode
(--map (intern (f-base it))
(f-directories
(f-expand mode-str doom-modules-dir)))))))
(t
(doom-enable-module mode m))))
doom-modules))
;;
;; Macros
;;
(defvar __PACKAGE__ nil "The name of the current package.")
(autoload 'use-package "use-package" nil nil 'macro)
(defalias '@use-package 'use-package
(defmacro @doom (&rest modules)
"DOOM Emacs bootstrap macro. List the modules to load. Benefits from
byte-compilation."
(doom-enable-modules modules)
(unless noninteractive
`(let (file-name-handler-alist)
,@(mapcar (lambda (pkg)
`(@require ,(car pkg) ,(cdr pkg) t))
(doom-module-pairs))
(when (display-graphic-p)
(require 'server)
(unless (server-running-p)
(server-start)))
;; Benchmark
(format "Loaded %s packages in %s"
(- (length load-path) (length doom--base-load-path))
(emacs-init-time)))))
(defalias '@def-package 'use-package
"A `use-package' alias. It exists so DOOM configs adhere to the naming
conventions of DOOM emacs. Note that packages are deferred by default.
conventions of DOOM emacs. Note that packages are deferred by default.")
By DOOM conventions, using this instead of `@package' means you are configuring
a package regardless of whether it's installed or not, while `@package' is used
to declare how to install/setup a package.")
(defmacro @load (filesym &optional path noerror)
"TODO"
(let ((path (or (and path (eval path)) __DIR__))
file)
(unless path
(error "Could not find %s" filesym))
(setq file (f-expand (concat (symbol-name filesym) ".el") path))
(if (f-exists-p file)
`(let ((__FILE__ ,file)
(__DIR__ ,path))
(load ,(f-no-ext file) ,noerror (not doom-debug-mode)))
(unless noerror
(error "Could not @load file %s" file)))))
(defmacro @require (module submodule &optional reload-p)
"Like `require', but for doom modules."
(unless noninteractive
(let ((loaded-p (doom-module-loaded-p module submodule)))
(when (or reload-p (not loaded-p))
(unless loaded-p
(doom-enable-module module submodule t))
`(@load config ,(doom-module-path module submodule) t)))))
;;
;; Declarative macros
;;
(defmacro @package (name &rest plist)
"Declares a package. This does not load nor install them explicitly.
If used in `doom-core-dir', this is a wrapper for `@use-package' (all packages
are deferred by default), and takes the same arguments as `use-package'.
this macro serves a purely declarative purpose, and are run to build
`doom-packages', so that functions like `doom/packages-install' can operate on
them.
If used outside of `doom-core-dir' (i.e. in packages.el files within modules),
this macro serves a purely declarative purpose and doesn't call `@use-package'.
These calls are parsed by `doom-read-packages' to build `doom-packages'.
Adds a few custom properties in either case:
Accepts the following properties:
:recipe RECIPE Takes a MELPA-style recipe (see `quelpa-recipe' for an
example); for packages to be installed from external
sources.
:pin ARCHIVE-NAME Instructs ELPA to only look for this package in
ARCHIVE-NAME. e.g. \"org\".
:needs FEATURE Don't install this package if FEATURE isn't available. Can be a
(:module . submodule) cons pair."
ARCHIVE-NAME. e.g. \"org\"."
(declare (indent defun))
(mapc (lambda (key) (setq plist (use-package-plist-delete plist key)))
'(:recipe :pin :needs))
`(let ((__PACKAGE__ ',name))
(@use-package ,name ,@plist)))
(let ((pkg-recipe (plist-get plist :recipe))
(pkg-pin (plist-get plist :pin)))
(when (= 0 (mod (length pkg-recipe) 2))
(plist-put plist :recipe (cons name pkg-recipe)))
`(add-to-list 'doom-packages ',(cons name plist) t)))
(defmacro @load (module &optional submodule file)
"Load a module from `doom-modules-dir' when both MODULE and SUBMODULE is
provided (both symbols). If FILE is non-nil, append it to the resulting path. If
SUBMODULE is nil, MODULE is loaded relative to the current file (see `__DIR__').
When SUBMODULE is nil, FILE isn't used.
Examples:
(@load :lang emacs-lisp)
Loads modules/lang/emacs-lisp/FILE.el (defaults to config.el).
(@load +local-module)
Loads +local-module.el relative to `__DIR__' or `doom-core-dir'."
(let (path file)
(cond ((null submodule)
(setq path __DIR__
file (concat (symbol-name module) ".el")))
(t
(cl-pushnew (cons module submodule)
doom-modules
:test (lambda (x y) (and (eq (car x) (car y))
(eq (cdr x) (cdr y)))))
(setq path (doom-module-path module submodule)
file (or file "config.el"))))
(setq path (f-slash path)
file (concat path file))
`(let ((__FILE__ ,file)
(__DIR__ ,path))
(load ,(f-no-ext file) nil (not doom-debug-mode)))))
(defun doom-module-path (module submodule &optional file)
"Get the full path to a module: e.g. :lang emacs-lisp maps to
~/.emacs.d/modules/lang/emacs-lisp/ and will append FILE if non-nil."
(setq module
(cond ((keywordp module) (substring (symbol-name module) 1))
((symbolp module) (symbol-name module))
((stringp module) module)
(t (error "Not a valid module name: %s" module))))
(when (symbolp submodule)
(setq submodule (symbol-name submodule)))
(f-expand (concat module "/" submodule "/" file)
doom-modules-dir))
(defmacro @depends-on (module submodule)
"Declares that this module depends on another. MODULE is a keyword, and
SUBMODULE is a symbol."
(doom-enable-module ,module ',submodule)
`(@load packages ,(doom-module-path module submodule) t))
;;
@ -243,16 +284,13 @@ Examples:
;;
(defun doom/reload ()
"Reload `load-path', `doom-modules' and `doom-packages' by
reinitializing doom and parsing config files for `@package' and `@doom' calls.
There are few reasons to use this."
"Reload `load-path' by reinitializing package.el and reloading autoloads."
(interactive)
(doom-initialize t)
(doom-read-packages t)
(doom-initialize-autoloads)
(doom/reload-autoloads)
(message "Reloaded %s packages" (length package-alist)))
(defun doom/refresh-autoloads ()
(defun doom/reload-autoloads ()
"Refreshes the autoloads.el file, which tells Emacs where to find all the
autoloaded functions in the modules you use or among the core libraries, e.g.
core/autoload/*.el.
@ -262,6 +300,7 @@ In modules, checks modules/*/autoload.el and modules/*/autoload/*.el.
Rerun this whenever init.el is modified. You can also use `make autoloads` from
the commandline."
(interactive)
(doom-initialize-packages noninteractive)
(let ((generated-autoload-file doom-autoload-file)
autoload-files)
(setq autoload-files
@ -272,26 +311,29 @@ the commandline."
(and (f-directory-p auto-dir)
(f-glob "*.el" auto-dir))))
(--map (doom-module-path (car it) (cdr it))
doom-modules)))
(doom-module-pairs))))
(f-glob "autoload/*.el" doom-core-dir)))
(when (f-exists-p generated-autoload-file)
(f-delete generated-autoload-file)
(message "Deleted old autoloads.el"))
(dolist (file autoload-files)
(update-file-autoloads file)
(@quiet (update-file-autoloads file))
(message "Scanned %s" (f-relative file doom-emacs-dir)))
(with-current-buffer (get-file-buffer generated-autoload-file)
(save-buffer)
(eval-buffer))
(message "Done!")))
(condition-case ex
(with-current-buffer (get-file-buffer generated-autoload-file)
(save-buffer)
(eval-buffer)
(message "Done!"))
('error (error "Couldn't evaluate autoloads.el: %s" (cadr ex))))))
(defun doom/byte-compile (&optional simple-p)
(defun doom/recompile (&optional simple-p)
"Byte (re)compile the important files in your emacs configuration (init.el &
core/*.el). DOOM Emacs was designed to benefit from this.
If SIMPLE-P is nil, also byte-compile modules/*/*/*.el (except for packages.el).
There should be a measurable benefit from this, but it may take a while."
(interactive)
(doom-initialize-packages t)
(let ((targets
(append (list (f-expand "init.el" doom-emacs-dir)
(f-expand "core.el" doom-core-dir))
@ -303,7 +345,7 @@ There should be a measurable benefit from this, but it may take a while."
(or (string= (f-base it) "config")
(string-prefix-p "+" (f-base it))))
t)
doom-modules)))))
(doom-module-pairs))))))
(n 0)
results)
(dolist (file targets)
@ -318,5 +360,12 @@ There should be a measurable benefit from this, but it may take a while."
(mapconcat (lambda (file) (concat "+ " (if (cdr file) "SUCCESS" "FAIL") ": " (car file)))
(reverse results) "\n")))))
;;
;; Package.el modifications
;;
(advice-add 'package-delete :after 'doom*package-delete)
(provide 'core-packages)
;;; core-packages.el ends here

View file

@ -57,7 +57,7 @@
;; Bootstrap
;;
(@package shackle :demand t
(@def-package shackle :demand t
:init
(setq shackle-default-alignment 'below
shackle-select-reused-windows t)

View file

@ -4,7 +4,7 @@
;; tools for digging through project files and exposing an API I can use to make
;; other plugins/features project-aware.
(@package projectile :demand t
(@def-package projectile :demand t
:init
(setq projectile-cache-file (concat doom-cache-dir "/projectile.cache")
projectile-completion-system 'ivy

View file

@ -101,7 +101,7 @@ disabled.")
;; I modified the built-in `hideshow' package to enable itself when needed. A
;; better, more vim-like code-folding plugin would be the `origami' plugin, but
;; until certain breaking bugs are fixed in it, I won't switch over.
(@use-package hideshow ; built-in
(@def-package hideshow ; built-in
:commands (hs-minor-mode hs-toggle-hiding hs-already-hidden-p)
:init
(defun doom*autoload-hideshow ()
@ -110,7 +110,7 @@ disabled.")
(advice-add 'evil-toggle-fold :before 'doom*autoload-hideshow))
;; Show uninterrupted indentation markers with some whitespace voodoo.
(@package highlight-indent-guides
(@def-package highlight-indent-guides
:commands highlight-indent-guides-mode
:config
(setq highlight-indent-guides-method 'character)
@ -161,10 +161,10 @@ file."
(delete-trailing-whitespace))))
;; Some modes don't adequately highlight numbers, therefore...
(@package highlight-numbers :commands highlight-numbers-mode)
(@def-package highlight-numbers :commands highlight-numbers-mode)
;; Line highlighting
(@use-package hl-line ; built-in
(@def-package hl-line ; built-in
:init
;; stickiness doesn't play nice with emacs 25+
(setq hl-line-sticky-flag nil
@ -172,7 +172,7 @@ file."
;; Line number column. A faster (or equivalent, in the worst case) line number
;; plugin than the built-in `linum'.
(@package nlinum
(@def-package nlinum
:commands nlinum-mode
:preface (defvar nlinum-format "%4d ")
:init
@ -194,7 +194,7 @@ file."
;; Helps us distinguish stacked delimiter pairs. Especially in parentheses-drunk
;; languages like Lisp.
(@package rainbow-delimiters
(@def-package rainbow-delimiters
:commands rainbow-delimiters-mode
:config (setq rainbow-delimiters-max-face-count 3)
:init

View file

@ -50,7 +50,7 @@ line or use --debug-init to enable this.")
(defvar doom-autoload-file
(concat doom-local-dir "autoloads.el")
"Location of the autoloads.el, which is generated by `doom/refresh-autoloads'
"Location of the autoloads.el, which is generated by `doom/reload-autoloads'
and `doom-initialize-autoloads'.")
(defconst IS-MAC (eq system-type 'darwin))
@ -136,6 +136,37 @@ enable multiple minor modes for the same regexp.")
(require 'core-lib)
(doom-initialize-autoloads)
(unless noninteractive
(@def-package anaphora
:commands (awhen aif acond awhile))
(@def-package async
:commands (async-start
async-start-process
async-byte-recompile-directory))
(@def-package persistent-soft
:preface (defvar pcache-directory (concat doom-cache-dir "pcache/"))
:commands (persistent-soft-exists-p
persistent-soft-fetch
persistent-soft-flush
persistent-soft-store))
(@def-package ht
:commands (ht-create ht-merge ht-copy ht-select ht-reject ht-select-keys
ht-get ht-keys ht-values ht-items ht-find ht-size
ht-set! ht-update! ht-remove! ht-clear! ht-reject!
ht-map ht-each
ht? ht-contains? ht-equal? ht-empty?
ht->alist ht->plist
ht<-alist ht<-plist
ht ht-amap ht-aeach))
(@def-package smex
:commands (smex smex-major-mode-commands)
:config
(setq smex-save-file (concat doom-cache-dir "/smex-items"))
(smex-initialize))
(require 'core-ui) ; draw me like one of your French editors
(require 'core-popups) ; taming sudden yet inevitable windows
(require 'core-editor) ; baseline configuration for text editing

40
core/packages.el Normal file
View file

@ -0,0 +1,40 @@
;; -*- no-byte-compile: t; -*-
;;; core/packages.el
;; core packages
(@package anaphora)
(@package async)
(@package persistent-soft)
(@package ht)
(@package smex)
;; core-ui.el
(@package highlight-indent-guides)
(@package highlight-numbers)
(@package nlinum)
(@package rainbow-delimiters)
;; core-popups.el
(@package shackle)
;; core-editor.el
(@package editorconfig)
(@package smartparens)
(@package ace-link)
(@package ace-window)
(@package avy)
(@package command-log-mode)
(@package emr)
(@package expand-region)
(@package goto-last-change)
(@package help-fns+)
(@package imenu-anywhere)
(@package imenu-list)
(@package pcre2el)
(@package rotate-text :recipe (:fetcher github :repo "debug-ito/rotate-text.el"))
(@package smart-forward)
(@package swiper)
(@package wgrep)
;; core-projects.el
(@package projectile)