core: improve theme application

Add all theme packages defined in dotspacemacs-themes to the variable
dotspacemacs-additional-packages and delay the application of user theme at the
end of startup (only when user theme cannot be applied at the very beginning
of Emacs startup).

This has nice properties:
- we leverage the layer system to handle the theme packages installation and
  cleanup.
- theme packages are automatically owned by the dotfile preventing them from
being garbage collected.
- the protected package mechanism is now obsolete since themes were the last
packages using it. This mechanism may be removed in a near future.

Thanks to TheBB for the initial idea.
This commit is contained in:
syl20bnr 2017-01-25 23:30:25 -05:00
parent 05c8ac8ba7
commit b3c8ebc816
4 changed files with 66 additions and 82 deletions

View File

@ -951,7 +951,8 @@ variable as well."
(defun configuration-layer/make-packages-from-dotfile (&optional usedp) (defun configuration-layer/make-packages-from-dotfile (&optional usedp)
"Read the additonal packages declared in the dotfile and create packages. "Read the additonal packages declared in the dotfile and create packages.
USEDP if non-nil indicates that made packages are used packages." USEDP if non-nil indicates that made packages are used packages."
(dolist (pkg dotspacemacs-additional-packages) (dolist (pkg (append dotspacemacs-additional-packages
dotspacemacs--additional-packages))
(let* ((pkg-name (if (listp pkg) (car pkg) pkg)) (let* ((pkg-name (if (listp pkg) (car pkg) pkg))
(obj (configuration-layer/get-package pkg-name))) (obj (configuration-layer/get-package pkg-name)))
(if obj (if obj

View File

@ -100,6 +100,10 @@ wrapped in a layer. If you need some configuration for these
packages then consider to create a layer, you can also put the packages then consider to create a layer, you can also put the
configuration in `dotspacemacs/user-config'.") configuration in `dotspacemacs/user-config'.")
(defvar dotspacemacs--additional-packages '()
"Same as `dotspacemacs-additonal-packages' but reserved for Spacemacs
internals.")
(defvar dotspacemacs-editing-style 'vim (defvar dotspacemacs-editing-style 'vim
"One of `vim', `emacs' or `hybrid'. "One of `vim', `emacs' or `hybrid'.
`hybrid' is like `vim' except that `insert state' is replaced by the `hybrid' is like `vim' except that `insert state' is replaced by the

View File

@ -103,26 +103,9 @@ the final step of executing code in `emacs-startup-hook'.")
(setq dotspacemacs-editing-style (dotspacemacs//read-editing-style-config (setq dotspacemacs-editing-style (dotspacemacs//read-editing-style-config
dotspacemacs-editing-style)) dotspacemacs-editing-style))
(configuration-layer/initialize) (configuration-layer/initialize)
;; Apply theme ;; theme
(let ((default-theme (car dotspacemacs-themes))) (spacemacs/load-theme (car dotspacemacs-themes)
(condition-case err spacemacs--fallback-theme)
(spacemacs/load-theme default-theme nil)
('error
;; fallback on Spacemacs default theme
(setq spacemacs--default-user-theme default-theme)
(setq dotspacemacs-themes (delq spacemacs--fallback-theme
dotspacemacs-themes))
(add-to-list 'dotspacemacs-themes spacemacs--fallback-theme)
(setq default-theme spacemacs--fallback-theme)
(load-theme spacemacs--fallback-theme t)))
;; protect used themes from deletion as orphans
(setq configuration-layer--protected-packages
(append
(delq nil (mapcar 'spacemacs//get-theme-package
dotspacemacs-themes))
configuration-layer--protected-packages))
(setq-default spacemacs--cur-theme default-theme)
(setq-default spacemacs--cycle-themes (cdr dotspacemacs-themes)))
;; font ;; font
(spacemacs|do-after-display-system-init (spacemacs|do-after-display-system-init
;; If you are thinking to remove this call to `message', think twice. You'll ;; If you are thinking to remove this call to `message', think twice. You'll
@ -163,10 +146,7 @@ the final step of executing code in `emacs-startup-hook'.")
(if dotspacemacs-mode-line-unicode-symbols (if dotspacemacs-mode-line-unicode-symbols
(setq-default spacemacs-version-check-lighter "[⇪]")) (setq-default spacemacs-version-check-lighter "[⇪]"))
;; install the dotfile if required ;; install the dotfile if required
(dotspacemacs/maybe-install-dotfile) (dotspacemacs/maybe-install-dotfile))
;; install user default theme if required
(when spacemacs--default-user-theme
(spacemacs/load-theme spacemacs--default-user-theme 'install)))
(defun spacemacs//removes-gui-elements () (defun spacemacs//removes-gui-elements ()
"Remove the menu bar, tool bar and scroll bars." "Remove the menu bar, tool bar and scroll bars."
@ -230,6 +210,8 @@ defer call using `spacemacs-post-user-config-hook'."
(when (fboundp dotspacemacs-scratch-mode) (when (fboundp dotspacemacs-scratch-mode)
(with-current-buffer "*scratch*" (with-current-buffer "*scratch*"
(funcall dotspacemacs-scratch-mode))) (funcall dotspacemacs-scratch-mode)))
(when spacemacs--delayed-user-theme
(spacemacs/load-theme spacemacs--delayed-user-theme))
(configuration-layer/display-summary emacs-start-time) (configuration-layer/display-summary emacs-start-time)
(spacemacs-buffer//startup-hook) (spacemacs-buffer//startup-hook)
(spacemacs/check-for-new-version nil spacemacs-version-check-interval) (spacemacs/check-for-new-version nil spacemacs-version-check-interval)

View File

@ -15,7 +15,7 @@
(defvar spacemacs--fallback-theme 'spacemacs-dark (defvar spacemacs--fallback-theme 'spacemacs-dark
"Fallback theme if user theme cannot be applied.") "Fallback theme if user theme cannot be applied.")
(defvar spacemacs--default-user-theme nil (defvar spacemacs--delayed-user-theme nil
"Internal variable storing user theme to be installed.") "Internal variable storing user theme to be installed.")
(defface org-kbd (defface org-kbd
@ -167,7 +167,7 @@ package name does not match theme name + `-theme' suffix.")
(defvar spacemacs-post-theme-change-hook nil (defvar spacemacs-post-theme-change-hook nil
"Hook run after theme has changed.") "Hook run after theme has changed.")
(defun spacemacs//get-theme-package (theme) (defun spacemacs/get-theme-package (theme)
"Returns the package theme for the given THEME name." "Returns the package theme for the given THEME name."
(cond (cond
;; built-in ;; built-in
@ -178,73 +178,63 @@ package name does not match theme name + `-theme' suffix.")
;; fallback to <name>-theme ;; fallback to <name>-theme
(t (intern (format "%S-theme" theme))))) (t (intern (format "%S-theme" theme)))))
(defun spacemacs/load-theme (theme &optional install) (defun spacemacs/load-theme (theme &optional fallback-theme disable)
"Load THEME. "Apply user theme.
If INSTALL is non-nil then attempt to install the theme." If FALLBACK-THEME is non-nil it must be a package name which will be loaded if
;; Required dependencies for some themes THEME cannot be applied.
If DISABLE is non-nil then disable all previously applied themes before applying
THEME."
(spacemacs//add-themes-to-additional-packages dotspacemacs-themes)
(condition-case err (condition-case err
(progn (progn
(when install
(spacemacs-buffer/append
(format "--> Installing user theme: %s..."
spacemacs--default-user-theme))
(redisplay))
;; Load theme ;; Load theme
(when (or (memq theme '(zonokai-blue
zonokai-red
solarized-light
solarized-dark
doom-one
doom-molokai)))
(configuration-layer/load-or-install-package 'dash install))
;; Unless Emacs stock themes
(unless (or (memq theme (custom-available-themes)) (unless (or (memq theme (custom-available-themes))
(eq 'default theme)) (eq 'default theme))
(cond (let* ((pkg (spacemacs/get-theme-package theme))
;; themes with explicitly declared package names (pkg-dir
((assq theme spacemacs-theme-name-to-package) (when pkg
(let* ((pkg (spacemacs//get-theme-package theme)) (configuration-layer/get-elpa-package-install-directory
(pkg-dir (configuration-layer/load-or-install-package pkg))))
pkg install))) (when pkg-dir
(add-to-list 'custom-theme-load-path pkg-dir)
(when (or (eq 'moe-light theme) (when (or (eq 'moe-light theme)
(eq 'moe-dark theme)) (eq 'moe-dark theme))
(load-file (concat pkg-dir "moe-light-theme.el")) (load-file (concat pkg-dir "moe-light-theme.el"))
(load-file (concat pkg-dir "moe-dark-theme.el"))) (load-file (concat pkg-dir "moe-dark-theme.el"))))))
(when pkg-dir (when disable
(add-to-list 'custom-theme-load-path pkg-dir)))) (mapc 'disable-theme custom-enabled-themes))
(t
;; other themes
;; we assume that the package name is suffixed with `-theme'
;; if not we will handle the special themes as we get issues
;; in the tracker.
(let ((pkg (spacemacs//get-theme-package theme)))
(configuration-layer/load-or-install-package pkg install)))))
;; Apply theme
(mapc 'disable-theme custom-enabled-themes)
;; explicitly reload the theme for the first GUI client
(eval `(spacemacs|do-after-display-system-init (eval `(spacemacs|do-after-display-system-init
(load-theme ',theme t))) (load-theme ',theme t)))
(when install (setq-default spacemacs--cur-theme theme)
(spacemacs-buffer/replace-last-line (setq-default spacemacs--cycle-themes (cdr dotspacemacs-themes)))
(format (concat "--> User theme \"%s\" has been applied, you may "
"have to restart Emacs.\n")
spacemacs--default-user-theme))
(redisplay)))
('error ('error
(if install (if fallback-theme
;; fallback to Spacemacs default theme
(progn (progn
(spacemacs-buffer/warning (setq spacemacs--delayed-user-theme theme)
(concat "An error occurred while applying " (spacemacs/load-fallback-theme fallback-theme disable))
"the theme \"%s\", fallback on theme \"%s\". \n" ;; no fallback theme was specified, so we log explicit warning
"Error was: %s") theme spacemacs--fallback-theme err) (spacemacs-buffer/warning
(spacemacs-buffer/warning (concat "An error occurred while applying "
(concat "Please check the value of \"dotspacemacs-themes\" in your " "the theme \"%s\", fallback on theme \"%s\". \n"
"dotfile or open an issue \n" "Error was: %s") theme spacemacs--fallback-theme err)
"so we can add support for the theme \"%s\".") theme) (spacemacs-buffer/warning
(unless (display-graphic-p) (concat "Please check the value of \"dotspacemacs-themes\" in your "
(eval `(spacemacs|do-after-display-system-init "dotfile or open an issue \n"
(load-theme ',spacemacs--fallback-theme t))))) "so we can add support for the theme \"%s\".") theme)))))
(throw 'error)))))
(defun spacemacs/load-fallback-theme (theme &optional disable)
"Apply the fallback theme.
If DISABLE is non-nil then disable all previously applied themes before applying
THEME."
;; pop up fallback theme to the top of the list
(setq spacemacs--cur-theme theme)
(setq dotspacemacs-themes (delq theme dotspacemacs-themes))
(add-to-list 'dotspacemacs-themes theme)
(when disable
(mapc 'disable-theme custom-enabled-themes))
(eval `(spacemacs|do-after-display-system-init
(load-theme ',theme t))))
(defun spacemacs/cycle-spacemacs-theme () (defun spacemacs/cycle-spacemacs-theme ()
"Cycle through themes defined in `dotspacemacs-themes.'" "Cycle through themes defined in `dotspacemacs-themes.'"
@ -277,4 +267,11 @@ has been changed to THEME."
(interactive) (interactive)
(run-hooks 'spacemacs-post-theme-change-hook)) (run-hooks 'spacemacs-post-theme-change-hook))
(defun spacemacs//add-themes-to-additional-packages (themes)
"Add the THEMES packages to `dotspacemacs-additional-packages'."
(dolist (theme themes)
(let ((pkg (spacemacs/get-theme-package theme)))
(when pkg
(add-to-list 'dotspacemacs--additional-packages pkg)))))
(provide 'core-themes-support) (provide 'core-themes-support)