Rewrite how themes are loaded, and fonts reloaded

A follow-up to 578dddd, which wasn't sufficient.

Fixes #5000 (again)
This commit is contained in:
Henrik Lissner 2021-05-07 16:33:07 -04:00
parent 113dcd74cf
commit f989bf60f0
6 changed files with 51 additions and 92 deletions

View file

@ -71,9 +71,7 @@ FRAME parameter defaults to current frame."
"Reload your fonts, if they're set. "Reload your fonts, if they're set.
See `doom-init-fonts-h'." See `doom-init-fonts-h'."
(interactive) (interactive)
(when doom-font (doom-init-fonts-h 'reload))
(set-frame-font doom-font t))
(doom-init-fonts-h))
;;;###autoload ;;;###autoload
(defun doom/increase-font-size (count) (defun doom/increase-font-size (count)

View file

@ -28,14 +28,15 @@ all themes. It will apply to all themes once they are loaded."
`(progn `(progn
(defun ,fn () (defun ,fn ()
(let (custom--inhibit-theme-enable) (let (custom--inhibit-theme-enable)
(dolist (theme (doom-enlist (or ,theme 'user))) (dolist (theme (doom-enlist (or ,theme 'doom)))
(when (or (eq theme 'user) (when (or (eq theme 'user)
(custom-theme-enabled-p theme)) (custom-theme-enabled-p theme))
(apply #'custom-theme-set-faces theme (apply #'custom-theme-set-faces theme
(mapcan #'doom--custom-theme-set-face (mapcan #'doom--custom-theme-set-face
(list ,@specs))))))) (list ,@specs)))))))
(when (or doom-init-theme-p (null doom-theme)) (unless doom-theme (funcall #',fn))
(funcall #',fn)) ;; TODO Append to `doom-load-theme-hook' with DEPTH instead when Emacs
;; 26.x support is dropped.
(add-hook 'doom-customize-theme-hook #',fn 'append)))) (add-hook 'doom-customize-theme-hook #',fn 'append))))
;;;###autoload ;;;###autoload
@ -46,17 +47,15 @@ This is a convenience macro alternative to `custom-set-face' which allows for a
simplified face format, and takes care of load order issues, so you can use simplified face format, and takes care of load order issues, so you can use
doom-themes' API without worry." doom-themes' API without worry."
(declare (indent defun)) (declare (indent defun))
`(custom-theme-set-faces! 'user ,@specs)) `(custom-theme-set-faces! 'doom ,@specs))
;;;###autoload ;;;###autoload
(defun doom/reload-theme () (defun doom/reload-theme ()
"Reload the current color theme." "Reload the current color theme."
(interactive) (interactive)
(let ((themes (copy-sequence custom-enabled-themes))) (let ((themes (copy-sequence custom-enabled-themes)))
(mapc #'disable-theme custom-enabled-themes) (load-theme doom-theme t)
(dolist (theme themes) (doom/reload-font)
(if (get theme 'theme-feature) (message "%s %s"
(load-theme theme t) (propertize "Reloaded themes:" 'face 'bold)
(enable-theme theme))) (mapconcat #'prin1-to-string themes ", "))))
(message "Reloaded themes: %s" (mapconcat #'prin1-to-string themes ", "))
(doom/reload-font)))

View file

@ -3,9 +3,6 @@
;; ;;
;;; Variables ;;; Variables
(defvar doom-init-theme-p nil
"If non-nil, a theme has been loaded.")
(defvar doom-theme nil (defvar doom-theme nil
"A symbol representing the Emacs theme to load at startup. "A symbol representing the Emacs theme to load at startup.
@ -570,23 +567,22 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
;; ;;
;;; Theme & font ;;; Theme & font
;; Use a psuedo theme to store internal and user faces + custom.el settings
;; without risk of them being written to `custom-file'.
(custom-declare-theme 'doom nil)
;; User themes should live in ~/.doom.d/themes, not ~/.emacs.d ;; User themes should live in ~/.doom.d/themes, not ~/.emacs.d
(setq custom-theme-directory (concat doom-private-dir "themes/")) (setq custom-theme-directory (concat doom-private-dir "themes/"))
;; Always prioritize the user's themes above the built-in/packaged ones. ;; Always prioritize the user's themes above the built-in/packaged ones.
(setq custom-theme-load-path (setq custom-theme-load-path
(cons 'custom-theme-directory (cons 'custom-theme-directory
(remq 'custom-theme-directory custom-theme-load-path))) (delq 'custom-theme-directory custom-theme-load-path)))
;; Underline looks a bit better when drawn lower ;; Underline looks a bit better when drawn lower
(setq x-underline-at-descent-line t) (setq x-underline-at-descent-line t)
;; DEPRECATED In Emacs 27 (defun doom-init-fonts-h (&optional reload)
(defvar doom--prefer-theme-elc nil
"If non-nil, `load-theme' will prefer the compiled theme (unlike its default
behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
(defun doom-init-fonts-h ()
"Loads `doom-font'." "Loads `doom-font'."
(when (fboundp 'set-fontset-font) (when (fboundp 'set-fontset-font)
(let ((fn (doom-rpartial #'member (font-family-list)))) (let ((fn (doom-rpartial #'member (font-family-list))))
@ -596,22 +592,27 @@ behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
(set-fontset-font t 'unicode font)) (set-fontset-font t 'unicode font))
(when doom-unicode-font (when doom-unicode-font
(set-fontset-font t 'unicode doom-unicode-font)))) (set-fontset-font t 'unicode doom-unicode-font))))
;; Changes to a theme don't take effect immediately if the theme isn't `user',
;; so we must force it to.
(let (custom--inhibit-theme-enable)
(apply #'custom-theme-set-faces 'doom (apply #'custom-theme-set-faces 'doom
(append (when doom-font (append (when doom-font
`((fixed-pitch ((t (:font ,doom-font)))))) `((fixed-pitch ((t (:font ,doom-font))))))
(when doom-serif-font (when doom-serif-font
`((fixed-pitch-serif ((t (:font ,doom-serif-font)))))) `((fixed-pitch-serif ((t (:font ,doom-serif-font))))))
(when doom-variable-pitch-font (when doom-variable-pitch-font
`((variable-pitch ((t (:font ,doom-variable-pitch-font)))))))) `((variable-pitch ((t (:font ,doom-variable-pitch-font)))))))))
(cond (cond
(doom-font (doom-font
;; I avoid `set-frame-font' because it does a lot of extra, expensive work ;; I avoid `set-frame-font' at startup because it is expensive; doing extra,
;; we can avoid by setting the font frame parameter directly. ;; unnecessary work we can avoid by setting the frame parameter directly.
(setf (alist-get 'font default-frame-alist) (setf (alist-get 'font default-frame-alist)
(cond ((stringp doom-font) doom-font) (cond ((stringp doom-font) doom-font)
((fontp doom-font) (font-xlfd-name doom-font)) ((fontp doom-font) (font-xlfd-name doom-font))
((signal 'wrong-type-argument (list '(fontp stringp) ((signal 'wrong-type-argument
doom-font)))))) (list '(fontp stringp) doom-font)))))
(when reload
(set-frame-font doom-font t)))
((display-graphic-p) ((display-graphic-p)
(setq font-use-system-font t))) (setq font-use-system-font t)))
;; Give users a chance to inject their own font logic. ;; Give users a chance to inject their own font logic.
@ -619,58 +620,27 @@ behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
(defun doom-init-theme-h (&optional frame) (defun doom-init-theme-h (&optional frame)
"Load the theme specified by `doom-theme' in FRAME." "Load the theme specified by `doom-theme' in FRAME."
(when (and doom-theme (when (and doom-theme (not (custom-theme-enabled-p doom-theme)))
(not (eq doom-theme 'default)) ;; Fix #1397: if `doom-init-theme-h' is used on `after-make-frame-functions'
(not (memq doom-theme custom-enabled-themes))) ;; (for daemon sessions), the new frame must be focused to ensure the theme
;; loads correctly.
(with-selected-frame (or frame (selected-frame)) (with-selected-frame (or frame (selected-frame))
(let ((doom--prefer-theme-elc t)) ; DEPRECATED in Emacs 27 (load-theme doom-theme t))))
(load-theme doom-theme t)))))
(defadvice! doom--load-theme-a (orig-fn theme &optional no-confirm no-enable) (defadvice! doom--load-theme-a (orig-fn theme &optional no-confirm no-enable)
"Run `doom-load-theme-hook' on `load-theme' and fix its issues. "Record `doom-theme', disable old themes, and trigger `doom-load-theme-hook'."
1. Disable previously enabled themes.
2. Don't let face-remapping screw up loading the new theme
(*cough*`mixed-pitch-mode').
3. Record the current theme in `doom-theme'."
:around #'load-theme :around #'load-theme
;; HACK Run `load-theme' from an estranged buffer, where we can be assured ;; Run `load-theme' from an estranged buffer, where we can ensure that
;; that buffer-local face remaps (by `mixed-pitch-mode', for instance) ;; buffer-local face remaps (by `mixed-pitch-mode', for instance) won't
;; won't interfere with changing themes. ;; interfere with recalculating faces in new themes.
(with-temp-buffer (with-temp-buffer
(when-let (result (funcall orig-fn theme no-confirm no-enable)) ;; Disable previous themes so there are no conflicts. If you truly want
(unless no-enable ;; multiple themes enabled, then use `enable-theme' instead.
(setq doom-theme theme (mapc #'disable-theme custom-enabled-themes)
doom-init-theme-p t) (prog1 (funcall orig-fn theme no-confirm no-enable)
;; `load-theme' doesn't disable previously enabled themes, which seems (when (and (not no-enable) (custom-theme-enabled-p theme))
;; like what you'd want. You could always use `enable-theme' to activate (setq doom-theme theme)
;; multiple themes instead. (doom-run-hooks 'doom-load-theme-hook)))))
(mapc #'disable-theme (remq theme custom-enabled-themes))
(run-hooks 'doom-load-theme-hook))
result)))
(eval-when! (not EMACS27+)
;; DEPRECATED `doom--load-theme-a' handles this for us after the theme is
;; loaded, but this only works on Emacs 27+. Disabling old themes
;; must be done *before* the theme is loaded in Emacs 26.
(defadvice! doom--disable-previous-themes-a (theme &optional _no-confirm no-enable)
"Disable other themes when loading a new one."
:before #'load-theme
(unless no-enable
(mapc #'disable-theme custom-enabled-themes)))
;; DEPRECATED Not needed in Emacs 27
(defadvice! doom--prefer-compiled-theme-a (orig-fn &rest args)
"Have `load-theme' prioritize the byte-compiled theme.
This offers a moderate boost in startup (or theme switch) time, so long as
`doom--prefer-theme-elc' is non-nil."
:around #'load-theme
(if (or (null after-init-time)
doom--prefer-theme-elc)
(letf! (defun locate-file (filename path &optional _suffixes predicate)
(funcall locate-file filename path '("c" "") predicate))
(apply orig-fn args))
(apply orig-fn args))))
;; ;;

View file

@ -58,13 +58,6 @@ envvar will enable this at startup.")
(define-error 'doom-private-error "Error in private config" 'doom-error) (define-error 'doom-private-error "Error in private config" 'doom-error)
(define-error 'doom-package-error "Error with packages" 'doom-error) (define-error 'doom-package-error "Error with packages" 'doom-error)
;;; Declare a psuedo theme to store faces and variables in, with no risk of it
;;; getting saved to `custom-file', or accidentally overwritten by user config.
(custom-declare-theme 'doom nil)
(enable-theme 'doom)
;; But immediately hide it, because it's not a real theme.
(setq custom-enabled-themes (remq 'doom custom-enabled-themes))
;; ;;
;;; Directory variables ;;; Directory variables

View file

@ -8,8 +8,7 @@
(use-package! doom-themes (use-package! doom-themes
:defer t :defer t
:init :init
(unless doom-theme (setq doom-theme 'doom-one)
(setq doom-theme 'doom-one))
;; improve integration w/ org-mode ;; improve integration w/ org-mode
(add-hook 'doom-load-theme-hook #'doom-themes-org-config) (add-hook 'doom-load-theme-hook #'doom-themes-org-config)
;; more Atom-esque file icons for neotree/treemacs ;; more Atom-esque file icons for neotree/treemacs

View file

@ -15,7 +15,7 @@
;; access to 256 colors. So if the user uses a daemon we must wait for ;; access to 256 colors. So if the user uses a daemon we must wait for
;; the first graphical frame to be available to do. ;; the first graphical frame to be available to do.
(add-hook 'doom-load-theme-hook #'+indent-guides-init-faces-h) (add-hook 'doom-load-theme-hook #'+indent-guides-init-faces-h)
(when doom-init-theme-p (when doom-theme
(+indent-guides-init-faces-h)) (+indent-guides-init-faces-h))
;; `highlight-indent-guides' breaks when `org-indent-mode' is active ;; `highlight-indent-guides' breaks when `org-indent-mode' is active