branch: externals/modus-themes
commit f52e2f16b02cacefb148e81f06c8ad464696fe06
Author: Protesilaos Stavrou <[email protected]>
Commit: Protesilaos Stavrou <[email protected]>

    Define commands to load a random theme, plus necessary helper functions
---
 modus-themes.el | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/modus-themes.el b/modus-themes.el
index aae748954c..1bc9cef4a4 100644
--- a/modus-themes.el
+++ b/modus-themes.el
@@ -1318,6 +1318,87 @@ modify THEMES in the process."
           (modus-themes-load-theme candidate))
       (user-error "`%s' is not part of the Modus collection" candidate))))
 
+;;;;; Load a random theme
+
+(defun modus-themes--has-background-mode-p (theme mode)
+  "Return non-nil if THEME has MODE :background-mode property."
+  (when-let* ((properties (get theme 'theme-properties))
+              (background (plist-get properties :background-mode)))
+    (eq background mode)))
+
+(defun modus-themes--dark-p (theme)
+  "Return non-nil if THEME has `dark' :background-mode property."
+  (modus-themes--has-background-mode-p theme 'dark))
+
+(defun modus-themes--light-p (theme)
+  "Return non-nil if THEME has `light' :background-mode property."
+  (modus-themes--has-background-mode-p theme 'light))
+
+(defun modus-themes-filter-by-background-mode (light-or-dark)
+  "Return list of `modus-themes-get-all-known-themes' by LIGHT-OR-DARK.
+LIGHT-OR-DARK is the symbol `dark' or `light'.  It corresponds to the
+theme property of :background-mode."
+  (when-let* ((themes (modus-themes-get-all-known-themes))
+              (fn (pcase light-or-dark
+                    ('dark #'modus-themes--dark-p)
+                    ('light #'modus-themes--light-p)
+                    (_ (error "LIGHT-OR-DARK must be either `dark' or `light', 
not `%s'" light-or-dark)))))
+    (seq-filter fn themes)))
+
+(defun modus-themes--minus-current (&optional background-mode)
+  "Return list of themes minus the current one.
+Optional BACKGROUND-MODE limits the list of themes to either the dark or light
+subset.  BACKGROUND-MODE is either `light' or `dark'.."
+  (let* ((themes (if (null background-mode)
+                     (modus-themes-get-all-known-themes)
+                   (modus-themes-filter-by-background-mode background-mode)))
+         (copy (copy-sequence themes)))
+    (if-let* ((current-theme (modus-themes-get-current-theme)))
+        (delete current-theme copy)
+      themes)))
+
+(defun modus-themes-background-mode-prompt ()
+  "Select `dark' or `light' and return it as a symbol."
+  (intern
+   (cadr
+    (read-multiple-choice
+     "Variant"
+     '((?d "dark" "Load a random dark theme")
+       (?l "light" "Load a random light theme"))
+     "Limit to the dark or light subset of the themes."))))
+
+;;;###autoload
+(defun modus-themes-load-random (&optional variant)
+  "Load a Modus theme at random, excluding the current one.
+
+With optional VARIANT as a prefix argument, prompt to limit the set of
+themes to either dark or light variants.  When called from Lisp, VARIANT
+is either the `dark' or `light' symbol.
+
+Run `modus-themes-after-load-theme-hook' after loading a theme."
+  (interactive
+   (list
+    (when current-prefix-arg
+      (modus-themes-background-mode-prompt))))
+  (let* ((themes (modus-themes--minus-current variant))
+         (match (or (nth (random (length themes)) themes) (car themes))))
+    (modus-themes-load-theme match)
+    (message "Match `%s'" (propertize (symbol-name match) 'face 'bold))))
+
+;;;###autoload
+(defun modus-themes-load-random-dark ()
+  "Load a random dark theme."
+  (declare (interactive-only t))
+  (interactive)
+  (modus-themes-load-random 'dark))
+
+;;;###autoload
+(defun modus-themes-load-random-light ()
+  "Load a random light theme."
+  (declare (interactive-only t))
+  (interactive)
+  (modus-themes-load-random 'light))
+
 ;;;;; Preview a theme palette
 
 (defun modus-themes--list-colors-get-mappings (palette)

Reply via email to