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)
"Read the additonal packages declared in the dotfile and create 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))
(obj (configuration-layer/get-package pkg-name)))
(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
configuration in `dotspacemacs/user-config'.")
(defvar dotspacemacs--additional-packages '()
"Same as `dotspacemacs-additonal-packages' but reserved for Spacemacs
internals.")
(defvar dotspacemacs-editing-style 'vim
"One of `vim', `emacs' or `hybrid'.
`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
dotspacemacs-editing-style))
(configuration-layer/initialize)
;; Apply theme
(let ((default-theme (car dotspacemacs-themes)))
(condition-case err
(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)))
;; theme
(spacemacs/load-theme (car dotspacemacs-themes)
spacemacs--fallback-theme)
;; font
(spacemacs|do-after-display-system-init
;; 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
(setq-default spacemacs-version-check-lighter "[⇪]"))
;; install the dotfile if required
(dotspacemacs/maybe-install-dotfile)
;; install user default theme if required
(when spacemacs--default-user-theme
(spacemacs/load-theme spacemacs--default-user-theme 'install)))
(dotspacemacs/maybe-install-dotfile))
(defun spacemacs//removes-gui-elements ()
"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)
(with-current-buffer "*scratch*"
(funcall dotspacemacs-scratch-mode)))
(when spacemacs--delayed-user-theme
(spacemacs/load-theme spacemacs--delayed-user-theme))
(configuration-layer/display-summary emacs-start-time)
(spacemacs-buffer//startup-hook)
(spacemacs/check-for-new-version nil spacemacs-version-check-interval)

View File

@ -15,7 +15,7 @@
(defvar spacemacs--fallback-theme 'spacemacs-dark
"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.")
(defface org-kbd
@ -167,7 +167,7 @@ package name does not match theme name + `-theme' suffix.")
(defvar spacemacs-post-theme-change-hook nil
"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."
(cond
;; built-in
@ -178,73 +178,63 @@ package name does not match theme name + `-theme' suffix.")
;; fallback to <name>-theme
(t (intern (format "%S-theme" theme)))))
(defun spacemacs/load-theme (theme &optional install)
"Load THEME.
If INSTALL is non-nil then attempt to install the theme."
;; Required dependencies for some themes
(defun spacemacs/load-theme (theme &optional fallback-theme disable)
"Apply user theme.
If FALLBACK-THEME is non-nil it must be a package name which will be loaded if
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
(progn
(when install
(spacemacs-buffer/append
(format "--> Installing user theme: %s..."
spacemacs--default-user-theme))
(redisplay))
;; 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))
(eq 'default theme))
(cond
;; themes with explicitly declared package names
((assq theme spacemacs-theme-name-to-package)
(let* ((pkg (spacemacs//get-theme-package theme))
(pkg-dir (configuration-layer/load-or-install-package
pkg install)))
(let* ((pkg (spacemacs/get-theme-package theme))
(pkg-dir
(when pkg
(configuration-layer/get-elpa-package-install-directory
pkg))))
(when pkg-dir
(add-to-list 'custom-theme-load-path pkg-dir)
(when (or (eq 'moe-light theme)
(eq 'moe-dark theme))
(load-file (concat pkg-dir "moe-light-theme.el"))
(load-file (concat pkg-dir "moe-dark-theme.el")))
(when pkg-dir
(add-to-list 'custom-theme-load-path pkg-dir))))
(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
(load-file (concat pkg-dir "moe-dark-theme.el"))))))
(when disable
(mapc 'disable-theme custom-enabled-themes))
(eval `(spacemacs|do-after-display-system-init
(load-theme ',theme t)))
(when install
(spacemacs-buffer/replace-last-line
(format (concat "--> User theme \"%s\" has been applied, you may "
"have to restart Emacs.\n")
spacemacs--default-user-theme))
(redisplay)))
(setq-default spacemacs--cur-theme theme)
(setq-default spacemacs--cycle-themes (cdr dotspacemacs-themes)))
('error
(if install
(if fallback-theme
;; fallback to Spacemacs default theme
(progn
(spacemacs-buffer/warning
(concat "An error occurred while applying "
"the theme \"%s\", fallback on theme \"%s\". \n"
"Error was: %s") theme spacemacs--fallback-theme err)
(spacemacs-buffer/warning
(concat "Please check the value of \"dotspacemacs-themes\" in your "
"dotfile or open an issue \n"
"so we can add support for the theme \"%s\".") theme)
(unless (display-graphic-p)
(eval `(spacemacs|do-after-display-system-init
(load-theme ',spacemacs--fallback-theme t)))))
(throw 'error)))))
(setq spacemacs--delayed-user-theme theme)
(spacemacs/load-fallback-theme fallback-theme disable))
;; no fallback theme was specified, so we log explicit warning
(spacemacs-buffer/warning
(concat "An error occurred while applying "
"the theme \"%s\", fallback on theme \"%s\". \n"
"Error was: %s") theme spacemacs--fallback-theme err)
(spacemacs-buffer/warning
(concat "Please check the value of \"dotspacemacs-themes\" in your "
"dotfile or open an issue \n"
"so we can add support for the theme \"%s\".") theme)))))
(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 ()
"Cycle through themes defined in `dotspacemacs-themes.'"
@ -277,4 +267,11 @@ has been changed to THEME."
(interactive)
(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)