Refactor core & core-lib

And make their tests pass
This commit is contained in:
Henrik Lissner 2019-09-03 00:42:36 -04:00
parent 059ede53b6
commit 62b089ba36
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
2 changed files with 62 additions and 57 deletions

View file

@ -1,8 +1,7 @@
;;; core-lib.el -*- lexical-binding: t; -*-
(let ((load-path doom--initial-load-path))
(require 'subr-x)
(require 'cl-lib))
(require 'cl-lib)
(require 'subr-x)
;; Polyfills
(unless EMACS26+
@ -175,7 +174,7 @@ at the values with which this function was called."
"Push VALUES sequentially into PLACE, if they aren't already present.
This is a variadic `cl-pushnew'."
(let ((var (make-symbol "result")))
`(dolist (,var (list ,@values))
`(dolist (,var (list ,@values) (with-no-warnings ,place))
(cl-pushnew ,var ,place :test #'equal))))
(defmacro prependq! (sym &rest lists)
@ -338,7 +337,10 @@ If NOERROR is non-nil, don't throw an error if the file doesn't exist."
(setq path (or (dir!)
(error "Could not detect path to look for '%s' in"
filename))))
(let ((file (if path `(expand-file-name ,filename ,path) filename)))
(let ((file (if path
`(let (file-name-handler-alist)
(expand-file-name ,filename ,path))
filename)))
`(condition-case e
(load ,file ,noerror ,(not doom-debug-mode))
((debug doom-error) (signal (car e) (cdr e)))
@ -372,29 +374,29 @@ serve as a predicated alternative to `after!'."
(put ',fn 'permanent-local-hook t)
(add-hook 'after-load-functions #',fn)))))
(defmacro defer-feature! (feature &optional mode)
"Pretend FEATURE hasn't been loaded yet, until FEATURE-hook is triggered.
(defmacro defer-feature! (feature &optional fn)
"Pretend FEATURE hasn't been loaded yet, until FEATURE-hook or FN runs.
Some packages (like `elisp-mode' and `lisp-mode') are loaded immediately at
startup, which will prematurely trigger `after!' (and `with-eval-after-load')
blocks. To get around this we make Emacs believe FEATURE hasn't been loaded yet,
then wait until FEATURE-hook (or MODE-hook, if MODE is provided) is triggered to
then wait until FEATURE-hook (or MODE-hook, if FN is provided) is triggered to
reverse this and trigger `after!' blocks at a more reasonable time."
(let ((advice-fn (intern (format "doom--defer-feature-%s-a" feature)))
(mode (or mode feature)))
(fn (or fn feature)))
`(progn
(setq features (delq ',feature features))
(advice-add #',mode :before #',advice-fn)
(advice-add #',fn :before #',advice-fn)
(defun ,advice-fn (&rest _)
;; Some plugins (like yasnippet) will invoke a mode early to parse
;; Some plugins (like yasnippet) will invoke a fn early to parse
;; code, which would prematurely trigger this. In those cases, well
;; behaved plugins will use `delay-mode-hooks', which we can check for:
(when (and ,(intern (format "%s-hook" mode))
(when (and ,(intern (format "%s-hook" fn))
(not delay-mode-hooks))
;; ...Otherwise, announce to the world this package has been loaded,
;; so `after!' handlers can react.
(provide ',feature)
(advice-remove #',mode #',advice-fn))))))
(advice-remove #',fn #',advice-fn))))))
(defmacro quiet! (&rest forms)
"Run FORMS without generating any output.

View file

@ -1,5 +1,16 @@
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
(defconst doom-version "2.0.9"
"Current version of Doom Emacs.")
(defconst EMACS26+ (> emacs-major-version 25))
(defconst EMACS27+ (> emacs-major-version 26))
(defconst IS-MAC (eq system-type 'darwin))
(defconst IS-LINUX (eq system-type 'gnu/linux))
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
;;
(defvar doom-init-p nil
"Non-nil if Doom has been initialized.")
@ -19,18 +30,6 @@ DEBUG envvar will enable this at startup.")
"The default value to use for `gc-cons-threshold'. If you experience freezing,
decrease this. If you experience stuttering, increase this.")
;;; Constants
(defconst doom-version "2.0.9"
"Current version of Doom Emacs.")
(defconst EMACS26+ (> emacs-major-version 25))
(defconst EMACS27+ (> emacs-major-version 26))
(defconst IS-MAC (eq system-type 'darwin))
(defconst IS-LINUX (eq system-type 'gnu/linux))
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
;;; Directories/files
(defvar doom-emacs-dir
(eval-when-compile (file-truename user-emacs-directory))
@ -63,9 +62,7 @@ dependencies or long-term shared data. Must end with a slash.")
Use this for files that change often, like cache files. Must end with a slash.")
(defvar doom-elpa-dir (concat doom-local-dir "elpa/")
"Where package.el and quelpa plugins (and their caches) are stored.
Must end with a slash.")
"Where package.el plugins (and their caches) are stored. Must end with a slash.")
(defvar doom-docs-dir (concat doom-emacs-dir "docs/")
"Where Doom's documentation files are stored. Must end with a slash.")
@ -225,8 +222,8 @@ users).")
(setq fast-but-imprecise-scrolling t)
;; Resizing the Emacs frame can be a terribly expensive part of changing the
;; font. By inhibiting this, we easily halve startup times with fonts that are
;; larger than the system default.
;; font. By inhibiting this, we halve startup times, particularly when we use
;; fonts that are larger than the system default (which would resize the frame).
(setq frame-inhibit-implied-resize t)
;; Don't ping things that look like domain names.
@ -323,7 +320,8 @@ This is already done by the lang/org module, however.
If you want to disable incremental loading altogether, either remove
`doom-load-packages-incrementally-h' from `emacs-startup-hook' or set
`doom-incremental-first-idle-timer' to nil.")
`doom-incremental-first-idle-timer' to nil. Incremental loading does not occur
in daemon sessions (they are loaded immediately at startup).")
(defvar doom-incremental-first-idle-timer 2
"How long (in idle seconds) until incremental loading starts.
@ -404,7 +402,8 @@ If RETURN-P, return the message as a string instead of displaying it."
(- (length load-path) (length doom--initial-load-path))
(if doom-modules (hash-table-count doom-modules) 0)
(or doom-init-time
(setq doom-init-time (float-time (time-subtract (current-time) before-init-time))))))
(setq doom-init-time
(float-time (time-subtract (current-time) before-init-time))))))
(defun doom-load-autoloads-file (file)
"Tries to load FILE (an autoloads file). Return t on success, throws an error
@ -422,25 +421,28 @@ in interactive sessions, nil otherwise (but logs a warning)."
(if (not (file-readable-p file))
(unless noerror
(signal 'file-error (list "Couldn't read envvar file" file)))
(with-temp-buffer
(insert-file-contents file)
(search-forward "\n\n" nil t)
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t)
(save-excursion
(let ((var (match-string 1))
(value (buffer-substring-no-properties
(point)
(1- (or (when (re-search-forward "^\\([^= ]+\\)=" nil t)
(line-beginning-position))
(point-max))))))
(setenv var value)))))
(setq-default
exec-path (append (split-string (getenv "PATH")
(if IS-WINDOWS ";" ":"))
(list exec-directory))
shell-file-name (or (getenv "SHELL")
shell-file-name))
t))
(let (vars)
(with-temp-buffer
(insert-file-contents file)
(search-forward "\n\n")
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t)
(save-excursion
(let ((var (match-string 1))
(value (buffer-substring-no-properties
(point)
(1- (or (when (re-search-forward "^\\([^= ]+\\)=" nil t)
(line-beginning-position))
(point-max))))))
(push (cons var value) vars)
(setenv var value)))))
(when vars
(setq-default
exec-path (append (split-string (getenv "PATH")
(if IS-WINDOWS ";" ":"))
(list exec-directory))
shell-file-name (or (getenv "SHELL")
shell-file-name))
(nreverse vars)))))
(defun doom-initialize (&optional force-p)
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
@ -510,9 +512,9 @@ to least)."
(require 'core-packages)
(doom-initialize-packages)))
;; Eagerly load these libraries because this module may be loaded in a session
;; that hasn't been fully initialized (where autoloads files haven't been
;; generated or `load-path' populated).
;; Eagerly load these libraries because we may be in a session that
;; hasn't been fully initialized (e.g. where autoloads files haven't
;; been generated or `load-path' populated).
(mapc (doom-rpartial #'load 'noerror 'nomessage)
(file-expand-wildcards (concat doom-core-dir "autoload/*.el")))
@ -533,10 +535,11 @@ to least)."
force-p
(not doom-interactive-mode))
(unless core-autoloads-p
(message "Your Doom core autoloads file is missing"))
(warn "Your Doom core autoloads file is missing"))
(unless pkg-autoloads-p
(message "Your package autoloads file is missing"))
(user-error "Run `bin/doom refresh' to generate them")))))
(warn "Your package autoloads file is missing"))
(signal 'doom-autoload-error "Run `bin/doom refresh' to generate them")))
t))
(defun doom-initialize-core ()
"Load Doom's core files for an interactive session."