summaryrefslogtreecommitdiff
path: root/lisp/cus-theme.el
diff options
context:
space:
mode:
authorChong Yidong <cyd@stupidchicken.com>2010-10-11 23:10:21 -0400
committerChong Yidong <cyd@stupidchicken.com>2010-10-11 23:10:21 -0400
commit6b09b5d118f2870e54a385f6ecd03cbf4508e120 (patch)
tree2c4523afdc963fe1628268773be8f46bff1c4a9a /lisp/cus-theme.el
parent57b6ae53514ccef149507cfd5f53d2e418810d30 (diff)
downloademacs-6b09b5d118f2870e54a385f6ecd03cbf4508e120.tar.gz
New interface for choosing Custom themes.
* lisp/cus-edit.el (custom--initialize-widget-variables): New function. (Custom-mode): Use it. * lisp/cus-face.el (custom-theme-set-faces): Remove dead code. Obey custom--inhibit-theme-enable. * lisp/cus-theme.el (describe-theme, customize-themes) (custom-theme-save): New commands. (custom-new-theme-mode-map): Bind C-x C-s. (custom-new-theme-mode): Use custom--initialize-widget-variables. (customize-create-theme): New optional arg THEME. (custom-theme-revert): Use it. (custom-theme-visit-theme): Remove dead code. (custom-theme-merge-theme): Use custom-available-themes. (custom-theme-write): Make interactive. (custom-theme-write): Use custom-theme-name-valid-p. (describe-theme-1, custom-theme-choose-revert) (custom-theme-checkbox-toggle, custom-theme-selections-toggle): New funs. (custom-theme-allow-multiple-selections): New option. (custom-theme-choose-mode): New major mode. * lisp/custom.el (custom-theme-set-variables): Remove dead code. Obey custom--inhibit-theme-enable. (custom--inhibit-theme-enable): New var. (provide-theme): Obey it. (load-theme): Replace load with manual read/eval, in order to check for correctness. Use custom-theme-name-valid-p. (custom-theme-name-valid-p): New function. (custom-available-themes): Use it. * lisp/help-mode.el (help-theme-def, help-theme-edit): New buttons.
Diffstat (limited to 'lisp/cus-theme.el')
-rw-r--r--lisp/cus-theme.el259
1 files changed, 224 insertions, 35 deletions
diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index d8192e860e4..3c1295ea923 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -35,27 +35,18 @@
(let ((map (make-keymap)))
(set-keymap-parent map widget-keymap)
(suppress-keymap map)
+ (define-key map "\C-x\C-s" 'custom-theme-write)
(define-key map "n" 'widget-forward)
(define-key map "p" 'widget-backward)
map)
"Keymap for `custom-new-theme-mode'.")
-(define-derived-mode custom-new-theme-mode nil "New-Theme"
- "Major mode for the buffer created by `customize-create-theme'.
-Do not call this mode function yourself. It is only meant for internal
-use by `customize-create-theme'."
+(define-derived-mode custom-new-theme-mode nil "Cus-Theme"
+ "Major mode for editing Custom themes.
+Do not call this mode function yourself. It is meant for internal use."
(use-local-map custom-new-theme-mode-map)
- (define-key custom-new-theme-mode-map [mouse-1] 'widget-move-and-invoke)
- (set (make-local-variable 'widget-documentation-face) 'custom-documentation)
- (set (make-local-variable 'widget-button-face) custom-button)
- (set (make-local-variable 'widget-button-pressed-face) custom-button-pressed)
- (set (make-local-variable 'widget-mouse-face) custom-button-mouse)
- (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert)
- (when custom-raised-buttons
- (set (make-local-variable 'widget-push-button-prefix) "")
- (set (make-local-variable 'widget-push-button-suffix) "")
- (set (make-local-variable 'widget-link-prefix) "")
- (set (make-local-variable 'widget-link-suffix) "")))
+ (custom--initialize-widget-variables)
+ (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
(put 'custom-new-theme-mode 'mode-class 'special)
(defvar custom-theme-name nil)
@@ -82,17 +73,21 @@ use by `customize-create-theme'."
query-replace)
"Faces listed by default in the *Custom Theme* buffer.")
+(defvar custom-theme--save-name)
+
;;;###autoload
-(defun customize-create-theme (&optional buffer)
- "Create a custom theme.
+(defun customize-create-theme (&optional theme buffer)
+ "Create or edit a custom theme.
+THEME, if non-nil, should be an existing theme to edit.
BUFFER, if non-nil, should be a buffer to use."
(interactive)
- (switch-to-buffer (or buffer (generate-new-buffer "*Custom Theme*")))
+ (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
;; Save current faces
(let ((inhibit-read-only t))
(erase-buffer))
(custom-new-theme-mode)
(make-local-variable 'custom-theme-name)
+ (set (make-local-variable 'custom-theme--save-name) theme)
(set (make-local-variable 'custom-theme-faces) nil)
(set (make-local-variable 'custom-theme-variables) nil)
(set (make-local-variable 'custom-theme-description) "")
@@ -116,7 +111,8 @@ BUFFER, if non-nil, should be a buffer to use."
(widget-insert "\n\nTheme name : ")
(setq custom-theme-name
- (widget-create 'editable-field))
+ (widget-create 'editable-field
+ :value (if theme (symbol-name theme) "")))
(widget-insert "Description: ")
(setq custom-theme-description
(widget-create 'text
@@ -164,14 +160,15 @@ BUFFER, if non-nil, should be a buffer to use."
:action (lambda (widget &optional event)
(call-interactively 'custom-theme-add-variable)))
(widget-insert ?\n)
+ (if theme
+ (custom-theme-merge-theme theme))
(widget-setup)
(goto-char (point-min))
(message ""))
(defun custom-theme-revert (ignore-auto noconfirm)
(when (or noconfirm (y-or-n-p "Discard current changes? "))
- (erase-buffer)
- (customize-create-theme (current-buffer))))
+ (customize-create-theme custom-theme--save-name (current-buffer))))
;;; Theme variables
@@ -318,10 +315,8 @@ Optional EVENT is the location for the menu."
(defun custom-theme-visit-theme ()
(interactive)
- (when (or (and (null custom-theme-variables)
- (null custom-theme-faces))
- (and (y-or-n-p "Discard current changes? ")
- (progn (revert-buffer) t)))
+ (when (and (y-or-n-p "Discard current changes? ")
+ (progn (revert-buffer) t))
(let ((theme (call-interactively 'custom-theme-merge-theme)))
(unless (eq theme 'user)
(widget-value-set custom-theme-name (symbol-name theme)))
@@ -331,9 +326,14 @@ Optional EVENT is the location for the menu."
(widget-setup))))
(defun custom-theme-merge-theme (theme)
- (interactive "SCustom theme name: ")
- (unless (eq theme 'user)
- (load-theme theme))
+ (interactive
+ (list
+ (intern (completing-read "Merge custom theme: "
+ (mapcar 'symbol-name
+ (custom-available-themes))))))
+ (unless (custom-theme-name-valid-p theme)
+ (error "Invalid theme name `%s'" theme))
+ (load-theme theme)
(let ((settings (get theme 'theme-settings)))
(dolist (setting settings)
(if (eq (car setting) 'theme-value)
@@ -343,6 +343,7 @@ Optional EVENT is the location for the menu."
theme)
(defun custom-theme-write (&rest ignore)
+ (interactive)
(let* ((name (widget-value custom-theme-name))
(doc (widget-value custom-theme-description))
(vars custom-theme-variables)
@@ -351,12 +352,8 @@ Optional EVENT is the location for the menu."
(when (string-equal name "")
(setq name (read-from-minibuffer "Theme name: " (user-login-name)))
(widget-value-set custom-theme-name name))
- (cond ((or (string-equal name "")
- (string-equal name "user")
- (string-equal name "changed"))
- (error "Custom themes cannot be named `%s'" name))
- ((string-match " " name)
- (error "Custom theme names should not contain spaces")))
+ (unless (custom-theme-name-valid-p (intern name))
+ (error "Custom themes cannot be named `%s'" name))
(setq filename (expand-file-name (concat name "-theme.el")
custom-theme-directory))
@@ -384,7 +381,8 @@ Optional EVENT is the location for the menu."
(dolist (face custom-theme-faces)
(when (widget-get (cdr face) :children)
(widget-put (cdr face) :custom-state 'saved)
- (custom-redraw-magic (cdr face))))))
+ (custom-redraw-magic (cdr face))))
+ (message "Theme written to %s" filename)))
(defun custom-theme-write-variables (theme vars)
"Write a `custom-theme-set-variables' command for THEME.
@@ -456,5 +454,196 @@ It includes all faces in list FACES."
(unless (looking-at "\n")
(princ "\n")))))
+
+;;; Describing Custom themes.
+
+;;;###autoload
+(defun describe-theme (theme)
+ "Display a description of the Custom theme THEME (a symbol)."
+ (interactive
+ (list
+ (intern (completing-read "Describe custom theme: "
+ (mapcar 'symbol-name
+ (custom-available-themes))))))
+ (unless (custom-theme-name-valid-p theme)
+ (error "Invalid theme name `%s'" theme))
+ (help-setup-xref (list 'describe-theme theme)
+ (called-interactively-p 'interactive))
+ (with-help-window (help-buffer)
+ (with-current-buffer standard-output
+ (describe-theme-1 theme))))
+
+(defun describe-theme-1 (theme)
+ (prin1 theme)
+ (princ " is a custom theme")
+ (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
+ (cons custom-theme-directory load-path)
+ '("" "c"))))
+ (when fn
+ (princ " in `")
+ (help-insert-xref-button (file-name-nondirectory fn)
+ 'help-theme-def fn)
+ (princ "'"))
+ (princ ".\n"))
+ (if (not (memq theme custom-known-themes))
+ (princ "It is not loaded.")
+ (if (custom-theme-enabled-p theme)
+ (princ "It is loaded and enabled.\n")
+ (princ "It is loaded but disabled.\n"))
+ (princ "\nDocumentation:\n")
+ (princ (or (get theme 'theme-documentation)
+ "No documentation available.")))
+ (princ "\n\nYou can ")
+ (help-insert-xref-button "customize" 'help-theme-edit theme)
+ (princ " this theme."))
+
+
+;;; Theme chooser
+
+(defvar custom--listed-themes)
+
+(defcustom custom-theme-allow-multiple-selections nil
+ "Whether to allow multi-selections in the *Custom Themes* buffer."
+ :type 'boolean
+ :group 'custom-buffer)
+
+(defvar custom-theme-choose-mode-map
+ (let ((map (make-keymap)))
+ (set-keymap-parent map widget-keymap)
+ (suppress-keymap map)
+ (define-key map "\C-x\C-s" 'custom-theme-save)
+ (define-key map "n" 'widget-forward)
+ (define-key map "p" 'widget-backward)
+ (define-key map "?" 'custom-describe-theme)
+ map)
+ "Keymap for `custom-theme-choose-mode'.")
+
+(define-derived-mode custom-theme-choose-mode nil "Cus-Theme"
+ "Major mode for selecting Custom themes.
+Do not call this mode function yourself. It is meant for internal use."
+ (use-local-map custom-theme-choose-mode-map)
+ (custom--initialize-widget-variables)
+ (set (make-local-variable 'revert-buffer-function)
+ (lambda (ignore-auto noconfirm)
+ (when (or noconfirm (y-or-n-p "Discard current choices? "))
+ (customize-themes (current-buffer))))))
+(put 'custom-theme-choose-mode 'mode-class 'special)
+
+;;;###autoload
+(defun customize-themes (&optional buffer)
+ "Display a selectable list of Custom themes.
+When called from Lisp, BUFFER should be the buffer to use; if
+omitted, a buffer named *Custom Themes* is used."
+ (interactive)
+ (pop-to-buffer (get-buffer-create (or buffer "*Custom Themes*")))
+ (let ((inhibit-read-only t))
+ (erase-buffer))
+ (custom-theme-choose-mode)
+ (set (make-local-variable 'custom--listed-themes) nil)
+ (make-local-variable 'custom-theme-allow-multiple-selections)
+ (and (null custom-theme-allow-multiple-selections)
+ (> (length custom-enabled-themes) 1)
+ (setq custom-theme-allow-multiple-selections t))
+
+ (widget-insert
+ (substitute-command-keys
+ "Type RET or click to enable/disable listed custom themes.
+Type \\[custom-describe-theme] to describe the theme at point.
+Theme files are named *-theme.el in `"))
+ (when (stringp custom-theme-directory)
+ (widget-create 'link :value custom-theme-directory
+ :button-face 'custom-link
+ :mouse-face 'highlight
+ :pressed-face 'highlight
+ :help-echo "Describe `custom-theme-directory'."
+ :keymap custom-mode-link-map
+ :follow-link 'mouse-face
+ :action (lambda (widget &rest ignore)
+ (describe-variable 'custom-theme-directory)))
+ (widget-insert "' or `"))
+ (widget-create 'link :value "load-path"
+ :button-face 'custom-link
+ :mouse-face 'highlight
+ :pressed-face 'highlight
+ :help-echo "Describe `load-path'."
+ :keymap custom-mode-link-map
+ :follow-link 'mouse-face
+ :action (lambda (widget &rest ignore)
+ (describe-variable 'load-path)))
+ (widget-insert "'.\n\n")
+ (widget-create 'push-button
+ :tag " Save Theme Settings "
+ :help-echo "Save the selected themes for future sessions."
+ :action 'custom-theme-save)
+ (widget-insert ?\n)
+ (widget-create 'checkbox
+ :value custom-theme-allow-multiple-selections
+ :action 'custom-theme-selections-toggle)
+ (widget-insert (propertize " Allow more than one theme at a time"
+ 'face '(variable-pitch (:height 0.9))))
+
+ (widget-insert "\n\nAvailable Custom Themes:\n")
+ (let (widget)
+ (dolist (theme (custom-available-themes))
+ (setq widget (widget-create 'checkbox
+ :value (custom-theme-enabled-p theme)
+ :theme-name theme
+ :action 'custom-theme-checkbox-toggle))
+ (push (cons theme widget) custom--listed-themes)
+ (widget-create-child-and-convert widget 'push-button
+ :button-face-get 'ignore
+ :mouse-face-get 'ignore
+ :value (format " %s" theme)
+ :action 'widget-parent-action)
+ (widget-insert ?\n)))
+ (goto-char (point-min))
+ (widget-setup))
+
+(defun custom-theme-checkbox-toggle (widget &optional event)
+ (let ((this-theme (widget-get widget :theme-name)))
+ (if (widget-value widget)
+ ;; Disable the theme.
+ (disable-theme this-theme)
+ ;; Enable the theme.
+ (unless custom-theme-allow-multiple-selections
+ ;; If only one theme is allowed, disable all other themes and
+ ;; uncheck their boxes.
+ (dolist (theme custom-enabled-themes)
+ (and (not (eq theme this-theme))
+ (assq theme custom--listed-themes)
+ (disable-theme theme)))
+ (dolist (theme custom--listed-themes)
+ (unless (eq (car theme) this-theme)
+ (widget-value-set (cdr theme) nil)
+ (widget-apply (cdr theme) :notify (cdr theme) event))))
+ (load-theme this-theme)))
+ ;; Mark `custom-enabled-themes' as "set for current session".
+ (put 'custom-enabled-themes 'customized-value
+ (list (custom-quote custom-enabled-themes)))
+ ;; Check/uncheck the widget.
+ (widget-toggle-action widget event))
+
+(defun custom-describe-theme ()
+ "Describe the Custom theme on the current line."
+ (interactive)
+ (let ((widget (widget-at (line-beginning-position))))
+ (and widget
+ (describe-theme (widget-get widget :theme-name)))))
+
+(defun custom-theme-save (&rest ignore)
+ (interactive)
+ (customize-save-variable 'custom-enabled-themes custom-enabled-themes)
+ (message "Custom themes saved for future sessions."))
+
+(defun custom-theme-selections-toggle (widget &optional event)
+ (when (widget-value widget)
+ ;; Deactivate multiple-selections.
+ (if (> (length (delq nil (mapcar (lambda (x) (widget-value (cdr x)))
+ custom--listed-themes)))
+ 1)
+ (error "More than one theme is currently selected")))
+ (widget-toggle-action widget event)
+ (setq custom-theme-allow-multiple-selections (widget-value widget)))
+
;; arch-tag: cd6919bc-63af-410e-bae2-b6702e762344
;;; cus-theme.el ends here