Skip to content

Commit

Permalink
feat: support multiple themes (#57)
Browse files Browse the repository at this point in the history
* Support multiple themes

Like `custom-enabled-themes`, Auto-Dark now allows multiple themes to be set for
either each mode. It also now defaults to using `custom-enabled-themes` if there
is nothing explicitly set for Auto-Dark. Because (dis|en)abling themes modifies
`custom-enabled-themes`, you either have to set both the dark-themes and
light-themes or neither, so there is a single new variable `auto-dark-themes`
that manages both lists.

If neither the new variable nor `custom-enabled-themes` is set, then it falls
back to the pre-existing single theme behavior, which is now marked obsolete.

With this change[^1] I can now configure my themes like
```elisp
(use-package emacs
  :custom (custom-enabled-themes '(bringhurst solarized inheritance)))

(use-package auto-dark
  :init (auto-dark-mode))
```
(since my themes all support dark/light modes).

[^1]: This change is built on #56, because it doesn’t make sense to use
`custom-enabled-themes` with Auto-Dark unless it updates
`frame-background-mode`.

* Update the README to match these changes

* Update the version to 0.13

* Improve variable documentation
  • Loading branch information
sellout authored Sep 14, 2024
1 parent 39b168e commit 681537d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 54 deletions.
73 changes: 33 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Install it from [MELPA](https://melpa.org/#/auto-dark) and add to your

```emacs-lisp
(require 'auto-dark)
(auto-dark-mode t)
(auto-dark-mode)
```


Expand All @@ -40,15 +40,15 @@ and then add the following to your `.emacs`:
```emacs-lisp
(add-to-list 'load-path "~/.emacs.d/auto-dark/")
(require 'auto-dark)
(auto-dark-mode t)
(auto-dark-mode)
```

Or use `use-package` to install:


```emacs-lisp
(use-package auto-dark
:config (auto-dark-mode t))
:init (auto-dark-mode))
```


Expand All @@ -61,7 +61,7 @@ If you use Spacemacs, add `(auto-dark)` to the

```emacs-lisp
(use-package auto-dark
:init (spacemacs/defer-until-after-user-config (lambda () (auto-dark-mode t)))
:init (spacemacs/defer-until-after-user-config #'auto-dark-mode)
:defer t)
```

Expand All @@ -83,16 +83,15 @@ enough:
(after! doom-ui
;; set your favorite themes
(setq! auto-dark-dark-theme 'doom-one
auto-dark-light-theme 'doom-one-light)
(auto-dark-mode 1))
(setq! auto-dark-themes '((doom-one) '(doom-one-light)))
(auto-dark-mode))
```


## Notes for MacOS users

From the box, this package takes advantage of some built-in functionality found
on the formulaes [Emacs Plus](https://github.com/d12frosted/homebrew-emacs-plus)
on the formulaes [Emacs Plus](https://github.com/d12frosted/homebrew-emacs-plus)
and [Emacs Mac](https://github.com/railwaycat/homebrew-emacsmacport?tab=readme-ov-file)
to make detecting switches faster.

Expand All @@ -116,7 +115,7 @@ by going to:


```
Settings -> Privacy & Security -> Emacs -> System Events
Settings -> Privacy & Security -> Emacs -> System Events
```


Expand All @@ -142,47 +141,42 @@ Following, a complete configuration with all settings set to its defaults:
```emacs-lisp
(use-package auto-dark
:ensure t
:config
(setq auto-dark-dark-theme 'wombat)
(setq auto-dark-light-theme 'leuven)
(setq auto-dark-polling-interval-seconds 5)
(setq auto-dark-allow-osascript nil)
(setq auto-dark-allow-powershell nil)
;; (setq auto-dark-detection-method nil) ;; dangerous to be set manually
(add-hook 'auto-dark-dark-mode-hook
(lambda ()
;; something to execute when dark mode is detected))
(add-hook 'auto-dark-light-mode-hook
(lambda ()
;; something to execute when light mode is detected))
(auto-dark-mode t))
:custom
(auto-dark-themes '((wombat) (leuven)))
(auto-dark-polling-interval-seconds 5)
(auto-dark-allow-osascript nil)
(auto-dark-allow-powershell nil)
;; (auto-dark-detection-method nil) ;; dangerous to be set manually
:hook
(auto-dark-dark-mode
. (lambda ()
;; something to execute when dark mode is detected
))
(auto-dark-light-mode
. (lambda ()
;; something to execute when light mode is detected
))
:init (auto-dark-mode))
```


A short description of each setting:


#### `auto-dark-dark-theme`
#### `auto-dark-themes`

The theme to enable when dark-mode is active.
A list containing two elements. The first is the list of themes to enable when
dark-mode is active and the second is the list of themes to enable when
dark-mode is inactive.


Possible values are themes installed on your system found by
`customize-themes` or `nil` to use Emacs with no themes (default
appearance).
Possible values for each sublist are themes installed on your system found by
`customize-themes` or `nil` to use Emacs with no themes (default appearance).


#### `auto-dark-light-theme`

The theme to enable when dark-mode is inactive.


Possible values are themes installed on your system found by
`customize-themes` or `nil` to use Emacs with no themes (default
appearance).
If this variable is `nil`, then the set of themes from `custom-enabled-themes`
will be used for both dark and light mode. These themes must support
`frame-background-mode`, or else there will be no visible change.


#### `auto-dark-polling-interval-seconds`
Expand Down Expand Up @@ -261,4 +255,3 @@ This package in action:
- Linux (Gnome DE)

![auto-dark-emacs in action - linux gnome](images/demo_gnome.gif)

94 changes: 80 additions & 14 deletions auto-dark.el
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
;; Vincent Zhang <[email protected]>
;; Jonathan Arnett <[email protected]>
;; Created: July 16 2019
;; Version: 0.12
;; Version: 0.13
;; Keywords: macos, windows, linux, themes, tools, faces
;; URL: https://github.com/LionyxML/auto-dark-emacs
;; Package-Requires: ((emacs "24.4"))
Expand Down Expand Up @@ -37,16 +37,66 @@
:group 'tools
:prefix "auto-dark-*")

;; Dark & light themes need to be set together because enabling and disabling
;; themes modifies `custom-enabled-themes', so if only one mode were expected to
;; default to `custom-enabled-themes', it would use the wrong list of themes
;; after the first time the other mode enables its themes.
(defcustom auto-dark-themes nil
"The themes to enable for dark and light modes.
The default is to use the themes in `custom-enabled-themes', but that only works
if the themes are aware of `frame-background-mode', which many aren’t.
If your themes aren’t aware of `frame-background-mode' (or you just prefer
different themes for dark and light modes), you can set explicit lists of themes
for each mode. Like with `custom-enabled-themes', the earlier themes in the list
have higher precedence."
:group 'auto-dark
:type '(choice
(const :tag "Use custom-enabled-themes" nil)
(list :tag "Use distinct dark & light lists"
(repeat :tag "Dark" symbol)
(repeat :tag "Light" symbol))))

(defcustom auto-dark-dark-theme 'wombat
"The theme to enable when dark-mode is active."
"The theme to enable when dark-mode is active.
This variable is obsolete. You should set `auto-dark-themes' instead."
:group 'auto-dark
:type '(choice symbol (const nil)))

(defcustom auto-dark-light-theme 'leuven
"The theme to enable when dark-mode is inactive."
"The theme to enable when dark-mode is inactive.
This variable is obsolete. You should set `auto-dark-themes' instead."
:group 'auto-dark
:type '(choice symbol (const nil)))

(make-obsolete-variable 'auto-dark-dark-theme 'auto-dark-themes "0.13")
(make-obsolete-variable 'auto-dark-light-theme 'auto-dark-themes "0.13")

(defun auto-dark--patch-theme-list (themes deprecated-theme)
"Support the deprecated ‘auto-dark-*-theme’ variables.
If THEMES is non-nil, it’s simply returned. If ‘custom-enabled-themes’ isn’t
set, a list containing only DEPRECATED-THEME is returned, otherwise nil.
Once the deprecated variables are removed “(auto-dark--patch-theme-list a b)”
can be replaced by “a”."
(or themes
(unless (and custom-enabled-themes
(not (equal custom-enabled-themes
(list auto-dark-dark-theme)))
(not (equal custom-enabled-themes
(list auto-dark-light-theme))))
(when deprecated-theme (list deprecated-theme)))))

(defun auto-dark--dark-themes ()
"Return the set of themes to be used in dark mode."
(auto-dark--patch-theme-list (car auto-dark-themes) auto-dark-dark-theme))

(defun auto-dark--light-themes ()
"Return the set of themes to be used in light mode."
(auto-dark--patch-theme-list (cadr auto-dark-themes) auto-dark-light-theme))

(defcustom auto-dark-polling-interval-seconds 5
"The number of seconds between which to poll for dark mode state.
Emacs must be restarted for this value to take effect."
Expand Down Expand Up @@ -183,24 +233,40 @@ already set the theme for the current dark mode state."
(setq frame-background-mode appearance)
(mapc #'frame-set-background-mode (frame-list)))

(defun auto-dark--enable-themes (&optional themes)
"Re-enable THEMES, which defaults to ‘custom-enabled-themes’.
This will load themes if necessary."
(interactive)
(let ((full-themes (remq 'user
(delete-dups (or themes custom-enabled-themes)))))
;; Disable only the themes we’re not going to re-enable.
(mapc (lambda (theme)
(unless (memq theme full-themes)
(disable-theme theme)))
custom-enabled-themes)
(let ((failures (mapcan (lambda (theme)
(condition-case nil
;; Enable instead of load when possible.
(if (custom-theme-p theme)
(enable-theme theme)
(load-theme theme))
(:success nil)
(error (list theme))))
(reverse full-themes))))
(when failures
(warn "Failed to enable theme(s): %s"
(mapconcat #'symbol-name failures ", "))))))

(defun auto-dark--set-theme (appearance)
"Set light/dark theme Argument APPEARANCE should be light or dark."
(mapc #'disable-theme custom-enabled-themes)
(setq auto-dark--last-dark-mode-state appearance)
(auto-dark--update-frame-backgrounds appearance)
(pcase appearance
('dark
(when auto-dark-light-theme
(disable-theme auto-dark-light-theme))
(auto-dark--update-frame-backgrounds 'dark)
(when auto-dark-dark-theme
(load-theme auto-dark-dark-theme t))
(auto-dark--enable-themes (auto-dark--dark-themes))
(run-hooks 'auto-dark-dark-mode-hook))
('light
(when auto-dark-dark-theme
(disable-theme auto-dark-dark-theme))
(auto-dark--update-frame-backgrounds 'light)
(when auto-dark-light-theme
(load-theme auto-dark-light-theme t))
(auto-dark--enable-themes (auto-dark--light-themes))
(run-hooks 'auto-dark-light-mode-hook))))

(defvar auto-dark--timer nil)
Expand Down

0 comments on commit 681537d

Please sign in to comment.