From: Lars Ingebrigtsen Date: Thu, 17 Feb 2022 11:31:12 +0000 (+0100) Subject: Have setopt check types X-Git-Tag: emacs-29.0.90~2274 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=136f1cb54962f5dcae9e8b63e41e4df70995599c;p=emacs.git 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. --- 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,11 +1059,20 @@ 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. 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