defcustoms change their
:type and I fail to update my customizations. How can I get Emacs to list all the variables where customize things there's a type mismatch?
I came up with this:
(defun my-custom-variable-valid-p (variable) (ignore-errors (let ((w (widget-convert (custom-variable-type variable)))) (widget-apply w :match (symbol-value variable))))) (defun my-get-mismatched-variables () (let (ret) (mapatoms (lambda (x) (when (and (custom-variable-p x) (not (my-custom-variable-valid-p x))) (push x ret)))) ret)) (defun my-show-mismatched-variables () (interactive) (help-setup-xref (list #'my-show-mismatched-variables) (called-interactively-p 'interactive)) (with-help-window (help-buffer) (dolist (var (sort (my-get-mismatched-variables) (lambda (a b) (apply #'string-lessp (mapcar #'symbol-name (list a b)))))) (princ "* ") (princ (symbol-name var)) (with-current-buffer standard-output (save-excursion (re-search-backward "* \\(.*\\)" nil t) (help-xref-button 1 'help-variable var))) (princ "\n"))))
You can then do
M-x my-show-mismatched-variables to display a buffer with list of variables (symbols) whose values are mismatched. This list will include defcustoms that were declared with invalid
:type as well. (Invalid
:type is why I use
custom-invalid-vars defined in the following elisp snippet displays a buffer with symbols of variables with mismatching customization.
Pityingly it also delivers some false positives.
emacs-version: GNU Emacs 18.104.22.168 (i686-pc-linux-gnu, GTK+ Version 3.10.8) of 2016-04-25
(defun custom-invalid-p (symbol) "Return non-nil if SYMBOL has invalid customization." (when (get symbol 'custom-type) (let* ((type (custom-variable-type symbol)) (conv (and type (widget-convert type)))) (and (widgetp conv) (null (condition-case nil (widget-apply conv :match (symbol-value symbol)) (error t))))))) (defun custom-invalid-vars () "Print list of variables with non-matching custom-type." (interactive) (let (ret) (mapatoms (lambda (symbol) (when (custom-invalid-p symbol) (setq ret (cons symbol ret))))) (when (called-interactively-p 'any) (with-current-buffer (get-buffer-create "*Custom: Invalid Vars*") (delete-region (point-min) (point-max)) (insert (mapconcat #'symbol-name ret "\n")) (display-buffer (current-buffer)))) ret))
You can use function
custom-var-val-satisfies-type-p from library
cus-edit+.el to get a list of options whose values do not match their custom types.
C-h f custom-var-val-satisfies-type-p:
custom-var-val-satisfies-type-pis a compiled Lisp function in
(custom-var-val-satisfies-type-p VARIABLE TYPES)
VARIABLEis bound, and its value satisfies a type in the list
(defun custom-mismatches () "Show options whose values do not match their custom types." (interactive) (let ((vars ()) type) (mapatoms (lambda (var) (when (custom-variable-p var) (setq type (get var 'custom-type)) (unless (or (not type) (custom-var-val-satisfies-type-p var (list (get var 'custom-type)))) (push var vars))))) (pp-display-expression vars "*Custom Type Mismatches*") vars))
(The reason for checking that
(get var 'custom-type) is non-
nil is that the "type"
nil is satisfied by any value. If a
defcustom does not actually use
:type then the type is
If the option, face, or Customize group is something defined by Emacs itself and not by a 3rd-party library then you can use command
customize-changedis an alias for
(customize-changed &optional SINCE-VERSION)
Customize all settings whose meanings have changed in Emacs itself. This includes new user options and faces, and new customization groups, as well as older options and faces whose meanings or default values have changed since the previous major Emacs release.
SINCE-VERSION(a string), customize all settings that were added or redefined since that version.