- (let ((custom--inhibit-theme-enable no-enable)
- sexp scar)
- (while (setq sexp (let ((read-circle nil))
- (condition-case nil
- (read (current-buffer))
- (end-of-file nil))))
- ;; Perform some checks on each sexp before evaluating it.
- (cond
- ((not (listp sexp)))
- ((eq (setq scar (car sexp)) 'deftheme)
- (unless (eq (cadr sexp) theme)
- (error "Incorrect theme name in `deftheme'"))
- (and (symbolp (nth 1 sexp))
- (stringp (nth 2 sexp))
- (eval (list scar (nth 1 sexp) (nth 2 sexp)))))
- ((or (eq scar 'custom-theme-set-variables)
- (eq scar 'custom-theme-set-faces))
- (unless (equal (nth 1 sexp) `(quote ,theme))
- (error "Incorrect theme name in theme settings"))
- (dolist (entry (cddr sexp))
- (unless (eq (car-safe entry) 'quote)
- (error "Unsafe expression in theme settings")))
- (eval sexp))
- ((and (eq scar 'provide-theme)
- (equal (cadr sexp) `(quote ,theme))
- (= (length sexp) 2))
- (eval sexp))))))))
+ (setq hash (sha1 (current-buffer)))
+ ;; Check file safety with `custom-safe-themes', prompting the
+ ;; user if necessary.
+ (when (or no-confirm
+ (and (memq 'default custom-safe-themes)
+ (equal (file-name-directory fn)
+ (expand-file-name "themes/" data-directory)))
+ (member hash custom-safe-themes)
+ (custom-theme-load-confirm hash))
+ (let ((custom--inhibit-theme-enable t))
+ (eval-buffer))
+ ;; Optimization: if the theme changes the `default' face, put that
+ ;; entry first. This avoids some `frame-set-background-mode' rigmarole
+ ;; by assigning the new background immediately.
+ (let* ((settings (get theme 'theme-settings))
+ (tail settings)
+ found)
+ (while (and tail (not found))
+ (and (eq (nth 0 (car tail)) 'theme-face)
+ (eq (nth 1 (car tail)) 'default)
+ (setq found (car tail)))
+ (setq tail (cdr tail)))
+ (if found
+ (put theme 'theme-settings (cons found (delq found settings)))))
+ ;; Finally, enable the theme.
+ (unless no-enable
+ (enable-theme theme))
+ t))))
+
+(defun custom-theme-load-confirm (hash)
+ "Query the user about loading a Custom theme that may not be safe.
+The theme should be in the current buffer. If the user agrees,
+query also about adding HASH to `custom-safe-themes'."
+ (if noninteractive
+ nil
+ (let ((exit-chars '(?y ?n ?\s))
+ window prompt char)
+ (save-window-excursion
+ (rename-buffer "*Custom Theme*" t)
+ (emacs-lisp-mode)
+ (setq window (display-buffer (current-buffer)))
+ (setq prompt
+ (format "Loading a theme can run Lisp code. Really load?%s"
+ (if (and window
+ (< (line-number-at-pos (point-max))
+ (window-body-height)))
+ " (y or n) "
+ (push ?\C-v exit-chars)
+ "\nType y or n, or C-v to scroll: ")))
+ (goto-char (point-min))
+ (while (null char)
+ (setq char (read-char-choice prompt exit-chars))
+ (when (eq char ?\C-v)
+ (if window
+ (with-selected-window window
+ (condition-case nil
+ (scroll-up)
+ (error (goto-char (point-min))))))
+ (setq char nil)))
+ (when (memq char '(?\s ?y))
+ ;; Offer to save to `custom-safe-themes'.
+ (and (or custom-file user-init-file)
+ (y-or-n-p "Treat this theme as safe in future sessions? ")
+ (customize-push-and-save 'custom-safe-themes (list hash)))
+ t)))))