summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Ingebrigtsen <larsi@gnus.org>2022-02-17 12:31:12 +0100
committerLars Ingebrigtsen <larsi@gnus.org>2022-02-17 12:31:12 +0100
commit136f1cb54962f5dcae9e8b63e41e4df70995599c (patch)
tree2fc2c2300361b185dcf5e4c9db6a57bd66ca4316
parent33a9ee2084f860610dbdc67bd3db237dcb64202e (diff)
downloademacs-136f1cb54962f5dcae9e8b63e41e4df70995599c.tar.gz
Have setopt check types
* doc/lispref/variables.texi (Setting Variables): Note type checking. * lisp/cus-edit.el (setopt--set): New function to avoid having Customize saving values, too. (setopt): Use it.
-rw-r--r--doc/lispref/variables.texi4
-rw-r--r--lisp/cus-edit.el16
-rw-r--r--test/lisp/cus-edit-tests.el8
3 files changed, 23 insertions, 5 deletions
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index a520b3856c5..d991ae9e277 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -886,6 +886,10 @@ will also issue a message:
(setopt my-var 2)
@end example
+@code{setopt} also checks whether the value is valid for the user
+option. For instance, using @code{setopt} to set a user option
+defined with a @code{number} type to a string will signal an error.
+
The @code{setopt} macro can be used on regular, non-user option
variables, but is much less efficient than @code{setq}. The main use
case for this macro is setting user options in the user's init file.
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index bb7ffc1eae5..bec7348099a 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -1049,10 +1049,7 @@ If given a prefix (or a COMMENT argument), also prompt for a comment."
"Set VARIABLE/VALUE pairs, and return the final VALUE.
This is like `setq', but is meant for user options instead of
plain variables. This means that `setopt' will execute any
-Customize form associated with VARIABLE.
-
-If VARIABLE has a `custom-set' property, that is used for setting
-VARIABLE, otherwise `set-default' is used.
+`custom-set' form associated with VARIABLE.
\(fn [VARIABLE VALUE]...)"
(declare (debug setq))
@@ -1062,12 +1059,21 @@ VARIABLE, otherwise `set-default' is used.
(while pairs
(unless (symbolp (car pairs))
(error "Attempting to set a non-symbol: %s" (car pairs)))
- (push `(customize-set-variable ',(car pairs) ,(cadr pairs))
+ (push `(setopt--set ',(car pairs) ,(cadr pairs))
expr)
(setq pairs (cddr pairs)))
(macroexp-progn (nreverse expr))))
;;;###autoload
+(defun setopt--set (variable value)
+ (custom-load-symbol variable)
+ ;; Check that the type is correct.
+ (when-let ((type (get variable 'custom-type)))
+ (unless (widget-apply (widget-convert type) :match value)
+ (user-error "Value `%S' does not match type %s" value type)))
+ (funcall (or (get variable 'custom-set) #'set-default) variable value))
+
+;;;###autoload
(defun customize-save-variable (variable value &optional comment)
"Set the default for VARIABLE to VALUE, and save it for future sessions.
Return VALUE.
diff --git a/test/lisp/cus-edit-tests.el b/test/lisp/cus-edit-tests.el
index 01a1407dcaa..7a597ccf343 100644
--- a/test/lisp/cus-edit-tests.el
+++ b/test/lisp/cus-edit-tests.el
@@ -76,5 +76,13 @@
(customize-saved)
(should (search-forward cus-edit-tests--obsolete-option-tag nil t)))))
+(ert-deftest test-setopt ()
+ (defcustom cus-edit-test-foo1 0
+ ""
+ :type 'number)
+ (should (= (setopt cus-edit-test-foo1 1) 1))
+ (should (= cus-edit-test-foo1 1))
+ (should-error (setopt cus-edit-test-foo1 :foo)))
+
(provide 'cus-edit-tests)
;;; cus-edit-tests.el ends here