New macro setopt-local and function set-local (bug#80709)
'setopt-local' is the buffer local equivalent of 'setopt'. Unify 'setopt', 'setopt-local', 'setq-local', 'buffer-local-set-state' with 'setq' to signal 'wrong-number-of-arguments'. * lisp/cus-edit.el (setopt): Change error signal to 'wrong-number-of-arguments'. (setopt-local): New macro. (setopt--set-local): New function. * lisp/subr.el (set-local): New function. (setq-local, buffer-local-set-state): Signal 'wrong-number-of-arguments' rather than 'error'. * doc/emacs/custom.texi (Examining): Document 'setopt-local'. * etc/NEWS: Announce the new macro and function.
This commit is contained in:
committed by
Stefan Monnier
parent
5032b2167d
commit
faf1932875
@@ -890,6 +890,34 @@ special setter functions, they will be run automatically when using
|
||||
non-customizable variables, but this is less efficient than using
|
||||
@code{setq}.
|
||||
|
||||
@findex setopt-local
|
||||
There is also a buffer-local version of @code{setopt}, called
|
||||
@code{setopt-local}, that you can use to set buffer specific values for
|
||||
customizable options, for example, in mode hooks (@pxref{Hooks}).
|
||||
|
||||
This works the same as @code{setq-local}, but if the variable has any
|
||||
special setter functions, they will be run automatically when using
|
||||
@code{setopt-local}. You can also use @code{setopt-local} on other,
|
||||
non-customizable variables, but this is less efficient than using
|
||||
@code{setq-local}.
|
||||
|
||||
If you want to change the value of a customizable variable only in
|
||||
your current buffer, you can use the @code{setopt-local} macro. For
|
||||
instance:
|
||||
|
||||
@example
|
||||
M-: (setopt-local fill-column 75) @key{RET}
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
Or, if you want to do this in your initialization file, use the
|
||||
following inside a mode hook so this variable will be automatically
|
||||
customized in buffers of that mode (@pxref{Hooks}):
|
||||
|
||||
@example
|
||||
(setopt-local fill-column 75)
|
||||
@end example
|
||||
|
||||
@node Hooks
|
||||
@subsection Hooks
|
||||
@cindex hook
|
||||
|
||||
@@ -372,12 +372,15 @@ added by calls to @code{custom-add-frequent-value} (see below).
|
||||
@item :set @var{setfunction}
|
||||
Specify @var{setfunction} as the way to change the value of this
|
||||
option when using the Customize interface. The function
|
||||
@var{setfunction} should take two arguments, a symbol (the option
|
||||
name) and the new value, and should do whatever is necessary to update
|
||||
@var{setfunction} should take two or three arguments, a symbol (the option
|
||||
name), the new value, and an optional @var{buffer-local} indicator.
|
||||
@var{setfunction} should do whatever is necessary to update
|
||||
the value properly for this option (which may not mean simply setting
|
||||
the option as a Lisp variable); preferably, though, it should not
|
||||
modify its value argument destructively. The default for
|
||||
@var{setfunction} is @code{set-default-toplevel-value}.
|
||||
modify its value argument destructively. If optional @var{buffer-local}
|
||||
is non-nil, the new value should be set buffer locally and not affect its
|
||||
global or default values. The default for @var{setfunction} is
|
||||
@code{set-default-toplevel-value}.
|
||||
|
||||
If defined, @var{setfunction} will also be called when evaluating a
|
||||
@code{defcustom} form with @kbd{C-M-x} in Emacs Lisp mode and when the
|
||||
@@ -387,7 +390,7 @@ If defined, @var{setfunction} will also be called when evaluating a
|
||||
If you specify this keyword, the variable's documentation string
|
||||
should describe how to do the same job in hand-written Lisp code,
|
||||
either by invoking @var{setfunction} directly or by using
|
||||
@code{setopt}.
|
||||
@code{setopt} or @code{setopt-local}.
|
||||
|
||||
@kindex get@r{, @code{defcustom} keyword}
|
||||
@item :get @var{getfunction}
|
||||
|
||||
11
etc/NEWS
11
etc/NEWS
@@ -4152,6 +4152,17 @@ change it globally with:
|
||||
---
|
||||
*** Loading a file displays a warning if there is no 'lexical-binding' cookie.
|
||||
|
||||
---
|
||||
** New function 'set-local'.
|
||||
This is the buffer local equivalent of the function 'set'.
|
||||
|
||||
+++
|
||||
** New macro 'setopt-local'.
|
||||
This is the buffer local version of 'setopt' for user options rather
|
||||
than plain variables and uses 'custom-set'/'set-local' to set variable
|
||||
values. A new argument, BUFFER-LOCAL, is passed to 'custom-set'
|
||||
functions to indicate the buffer local context.
|
||||
|
||||
+++
|
||||
** New macros 'incf' and 'decf'.
|
||||
They increment or decrement the value stored in a variable (a symbol),
|
||||
|
||||
@@ -1084,7 +1084,7 @@ even if it doesn't match the type.)
|
||||
\(fn [VARIABLE VALUE]...)"
|
||||
(declare (debug setq))
|
||||
(unless (evenp (length pairs))
|
||||
(error "PAIRS must have an even number of variable/value members"))
|
||||
(signal 'wrong-number-of-arguments (list 'setopt (length pairs))))
|
||||
(let ((expr nil))
|
||||
(while pairs
|
||||
(unless (symbolp (car pairs))
|
||||
@@ -1100,11 +1100,53 @@ even if it doesn't match the type.)
|
||||
;; Check that the type is correct.
|
||||
(when-let* ((type (get variable 'custom-type)))
|
||||
(unless (widget-apply (widget-convert type) :match value)
|
||||
(warn "Value `%S' for variable `%s' does not match its type \"%s\""
|
||||
value variable type)))
|
||||
(warn "Value does not match %S's type `%S': %S" variable type value)))
|
||||
(put variable 'custom-check-value (list value))
|
||||
(funcall (or (get variable 'custom-set) #'set-default) variable value))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro setopt-local (&rest pairs)
|
||||
"Set buffer local VARIABLE/VALUE pairs, and return the final VALUE.
|
||||
This is like `setq-local', but is meant for user options instead of
|
||||
plain variables. This means that `setopt-local' will execute any
|
||||
`custom-set' form associated with VARIABLE. Unlike `setopt',
|
||||
`setopt-local' does not affect a user option's global value.
|
||||
|
||||
Note that `setopt-local' will emit a warning if the type of a VALUE does
|
||||
not match the type of the corresponding VARIABLE as declared by
|
||||
`defcustom'. (VARIABLE will be assigned the value even if it doesn't
|
||||
match the type.)
|
||||
|
||||
Signal an error if a `custom-set' form does not support the
|
||||
`buffer-local' argument.
|
||||
|
||||
\(fn [VARIABLE VALUE]...)"
|
||||
(declare (debug setq))
|
||||
(unless (evenp (length pairs))
|
||||
(signal 'wrong-number-of-arguments (list 'setopt-local (length pairs))))
|
||||
(let ((expr nil))
|
||||
(while pairs
|
||||
(unless (symbolp (car pairs))
|
||||
(error "Attempting to set a non-symbol: %s" (car pairs)))
|
||||
(push `(setopt--set-local ',(car pairs) ,(cadr pairs))
|
||||
expr)
|
||||
(setq pairs (cddr pairs)))
|
||||
(macroexp-progn (nreverse expr))))
|
||||
|
||||
;;;###autoload
|
||||
(defun setopt--set-local (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)
|
||||
(warn "Value does not match %S's type `%S': %S" variable type value)))
|
||||
(condition-case _
|
||||
(funcall (or (get variable 'custom-set)
|
||||
(lambda (x v &optional _) (set-local x v)))
|
||||
variable value 'buffer-local)
|
||||
(wrong-number-of-arguments
|
||||
(error "The setter of %S does not support setopt-local" variable))))
|
||||
|
||||
;;;###autoload
|
||||
(defun customize-save-variable (variable value &optional comment)
|
||||
"Set the default for VARIABLE to VALUE, and save it for future sessions.
|
||||
|
||||
@@ -160,6 +160,10 @@ of previous VARs.
|
||||
(push `(set-default ',(pop args) ,(pop args)) exps))
|
||||
`(progn . ,(nreverse exps))))
|
||||
|
||||
(defun set-local (variable value)
|
||||
"Make VARIABLE buffer local and set it to VALUE."
|
||||
(set (make-local-variable variable) value))
|
||||
|
||||
(defmacro setq-local (&rest pairs)
|
||||
"Make each VARIABLE local to current buffer and set it to corresponding VALUE.
|
||||
|
||||
@@ -181,7 +185,7 @@ In some corner cases you may need to resort to
|
||||
\(fn [VARIABLE VALUE]...)"
|
||||
(declare (debug setq))
|
||||
(unless (evenp (length pairs))
|
||||
(error "PAIRS must have an even number of variable/value members"))
|
||||
(signal 'wrong-number-of-arguments (list 'setq-local (length pairs))))
|
||||
(let ((expr nil))
|
||||
(while pairs
|
||||
(unless (symbolp (car pairs))
|
||||
@@ -229,7 +233,7 @@ in order to restore the state of the local variables set via this macro.
|
||||
\(fn [VARIABLE VALUE]...)"
|
||||
(declare (debug setq))
|
||||
(unless (evenp (length pairs))
|
||||
(error "PAIRS must have an even number of variable/value members"))
|
||||
(signal 'wrong-number-of-arguments (list 'buffer-local-set-state (length pairs))))
|
||||
(let ((vars nil)
|
||||
(tmp pairs))
|
||||
(while tmp (push (car tmp) vars) (setq tmp (cddr tmp)))
|
||||
|
||||
Reference in New Issue
Block a user