summaryrefslogtreecommitdiff
path: root/modules/ui-theme.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
committerCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
commit754bbf7a25a8dda49b5d08ef0d0443bbf5af0e36 (patch)
treef1190704f78f04a2b0b4c977d20fe96a828377f1 /modules/ui-theme.el
new repository
Diffstat (limited to 'modules/ui-theme.el')
-rw-r--r--modules/ui-theme.el110
1 files changed, 110 insertions, 0 deletions
diff --git a/modules/ui-theme.el b/modules/ui-theme.el
new file mode 100644
index 00000000..609acab3
--- /dev/null
+++ b/modules/ui-theme.el
@@ -0,0 +1,110 @@
+;;; ui-theme.el --- UI Theme Configuration and Persistence -*- lexical-binding: t; -*-
+;; Craig Jennings <c@cjennings.net>
+;;
+;;; Commentary:
+
+;; Add custom theme files to "themes" subdirectory.
+;; Load other preferred themes via use-package.
+;; cj/switch-theme function unloads previous themes then applies the chosen theme.
+;; Persist themes between sessions using a file to store the theme name.
+;; The persist file can live in a sync'd dir, so theme choice may persist across machines.
+
+;;; Code:
+
+;; ----------------------------------- Themes ----------------------------------
+;; theme choices and settings
+
+;; downloaded custom themes go in themes subdirectory
+(setq custom-safe-themes t) ;; trust all custom themes
+(add-to-list 'custom-theme-load-path
+ (concat user-emacs-directory "themes"))
+
+(use-package ef-themes)
+(use-package github-dark-vscode-theme)
+(use-package madhat2r-theme)
+(use-package adwaita-dark-theme)
+
+;; ------------------------------- Switch Themes -------------------------------
+;; loads themes in completing read, then persists via the functions below
+
+(defun cj/switch-themes ()
+ "Function to switch themes and save chosen theme name for persistence.
+Unloads any other applied themes before applying the chosen theme."
+ (interactive)
+ (let ((chosentheme ""))
+ (setq chosentheme
+ (completing-read "Load custom theme: "
+ (mapcar 'symbol-name
+ (custom-available-themes))))
+ (mapcar #'disable-theme custom-enabled-themes)
+ (load-theme (intern chosentheme) t))
+ (cj/save-theme-to-file))
+(global-set-key (kbd "M-L") 'cj/switch-themes)
+
+;; ----------------------------- Theme Persistence -----------------------------
+;; persistence utility functions used by switch themes.
+
+(defvar theme-file (concat sync-dir "emacs-theme.persist")
+ "The location of the file to persist the theme name.")
+
+(defvar fallback-theme-name "wombat"
+ "The name of the theme to fallback on.
+This is used then there's no file, or the theme name doesn't match
+any of the installed themes. If theme name is 'nil', there will be
+no theme.")
+
+(defun cj/read-file-contents (filename)
+ "Read FILENAME and return its content as a string.
+If FILENAME isn't readable, return nil."
+ (if (file-readable-p filename)
+ (with-temp-buffer
+ (insert-file-contents filename)
+ (buffer-string))
+ 'nil))
+
+(defun cj/write-file-contents (content filename)
+ "Write CONTENT to FILENAME.
+If FILENAME isn't writeable, return nil. If successful, return t."
+ (if (file-writable-p filename)
+ (progn
+ (with-temp-buffer
+ (insert content)
+ (write-file filename))
+ 't)
+ 'nil))
+
+(defun cj/get-active-theme-name ()
+ "Return the name of the active UI theme as a string."
+ (symbol-name (car custom-enabled-themes)))
+
+(defun cj/save-theme-to-file ()
+ "Save the string representing the current theme to the theme-file."
+ (if (equal (cj/write-file-contents (cj/get-active-theme-name) theme-file) 'nil)
+ (message "Cannot save theme: %s is unwriteable" theme-file)
+ (message "%s theme saved to %s" (cj/get-active-theme-name) theme-file)))
+
+(defun cj/load-fallback-theme (msg)
+ "Display MSG and load ui-theme fallback-theme-name.
+Used to handle errors with loading persisted theme."
+ (message (concat msg (format " Loading fallback theme %s" fallback-theme-name)))
+ (load-theme fallback-theme-name t))
+
+(defun cj/load-theme-from-file ()
+ "Apply the thame name contained in theme-file as the active UI theme.
+If the theme is nil, it disables all current themes. If an error occurs
+loading the file name, the fallback-theme-name is applied and saved."
+ (let ((theme-name (cj/read-file-contents theme-file)))
+ ;; if theme-name is nil, unload all themes
+ (if (string= theme-name "nil")
+ (mapcar #'disable-theme custom-enabled-themes)
+ ;; apply theme name or if error, load fallback theme
+ (progn
+ (condition-case err
+ (load-theme (intern theme-name) t)
+ (error
+ (cj/load-fallback-theme (concat "Error loading " theme-name "."))))))))
+
+(cj/load-theme-from-file)
+
+(provide 'ui-theme)
+;;; ui-theme.el ends here.