From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: martin rudalics Newsgroups: gmane.emacs.devel Subject: "after" variable watchers Date: Mon, 17 May 2021 10:27:40 +0200 Message-ID: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------B7DD5BFF9859C534CC2D68F8" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="36128"; mail-complaints-to="usenet@ciao.gmane.io" To: emacs-devel , Noam Postavsky Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon May 17 10:28:48 2021 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1liYcK-0009H4-3S for ged-emacs-devel@m.gmane-mx.org; Mon, 17 May 2021 10:28:48 +0200 Original-Received: from localhost ([::1]:50864 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1liYcJ-0004Mo-3a for ged-emacs-devel@m.gmane-mx.org; Mon, 17 May 2021 04:28:47 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:52220) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1liYbL-0003h4-KV for emacs-devel@gnu.org; Mon, 17 May 2021 04:27:47 -0400 Original-Received: from mout.gmx.net ([212.227.17.20]:49573) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1liYbI-0007oI-DQ for emacs-devel@gnu.org; Mon, 17 May 2021 04:27:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1621240061; bh=bkBKJZBTweFhF2yhNjsG3GVk8MJc75XMxVxWuCVc7uU=; h=X-UI-Sender-Class:To:From:Subject:Date; b=cPdM2qGc8GSfVkvQsHxjmorGcE49zn0XwiVo94xfiPjVS6PjyDs3u11hP/GPBGKN7 iSnoaX+wAqkSsBWLOPjmg8hP7y7RXPwyDA0N+MLFOOJWAHcVLpai2k1TvU/IE8+g2+ g77Jw032sFK6GUK6E110CsYrYI69vmG0pcdFwk3o= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Original-Received: from [192.168.1.100] ([213.142.96.206]) by mail.gmx.net (mrgmx105 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MdNcG-1l9UpZ10Mq-00ZOdW; Mon, 17 May 2021 10:27:41 +0200 Content-Language: en-US X-Provags-ID: V03:K1:FACnILZntP+uEKR5QVhdvfFydUdcuVZp9QL3NMkTuAfuJsgoMMF BOpih/2QKnOFm6WfEMnQ+RCf3t52MbMFO1vjyfZGFUMZXZ95fsSg9JURKvJ9yxe5y7CL7pS zNAFfGFwgq/Nf/cyCIOmIXJVRl/B48IbLEEcMatAREENd9M9l+hlHS5xUYBFi0gNIj3mBuw 7xQROHa4NhksX3Ngi5F8A== X-UI-Out-Filterresults: notjunk:1;V03:K0:bDk1EpH9/YI=:lGHm3H5NS5+UL8M9aEKwTy FdGRTxGE1e6R8+wOJFhKoH2qHsj9/gUgtlzg0IS7PuYQe3BUi0kueP/uCt3ZlPZds00KRmOlZ 4VlkX0hzJZy9muDCp7PhKi6ejD0P8G8Clwm+JuviHL1yhLTX8+Vlb3bjRJUAjaBGiqqI0DsvS wyjWYIttcbv8p9d55gZECbh0whM6T9VoQKCN7+90otZycHtB2yQdN/5EgcgA+eXTkR+wP98hi u5475a9jW5ON9CVFGGHFFrDytSw2QlOPhiMKQnFG2BKVvYwaHG0WYGezL/zm3H/4D0B/0NbPW Pa+MC8q2WeP3iensqcv6+w+uRkvJHEcj6modGay8W/bjRT1zh8d47hsaz0VthrI1ECh6ry7TD JfWqoNA3GElRdK6/raq9wi8sUoFtHYcB0N/kp3Y3EvclRWGigLsD+GznrjyFIOxafxWBgcMn5 p212Bw5UdVSDVUEyStxh1r9bd8RRKIFr6AJmngvUcUNl58JMx27EF27uNb4J24a/a1RcJXR/4 EPa3f2U9Kf7WqcK4KI61XyLYrytbR1v9MQgI7pI8kQ1BgnOdcKDRr9P1tsCMfNbDz5TT9jawx pMi2rjlgRVI1EfIJK7yrzesW6RgCukk/PdZcnT60MNBA0pJnqhpaK9w510d2c17V2vhMVUVig yCj/R68UtQ/TSn//9d3sITiaz8v8joqiMv2dAeBgapqgs7wI4aROQ90q36QzQ/v/cFRWeVLpk druJhoTBJlv4TRWpOOXMrGMaMa6ftNWNQZriIuO+8Ize6sgGFB+Jofc7/tDeJgE7YXv68luJ Received-SPF: pass client-ip=212.227.17.20; envelope-from=rudalics@gmx.at; helo=mout.gmx.net X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:269396 Archived-At: This is a multi-part message in MIME format. --------------B7DD5BFF9859C534CC2D68F8 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit I'd like to install the attached patch which expands on the existing variable watching mechanism in the sense that the variable whose value gets changed has already the new value assigned to within the body of the watch function. Such a feature is useful when the watch function calls already existing functions which act upon the variable's new value in a possibly deeply nested fashion. Consider the following example: A user wants to set `right-margin-width' of a buffer and I want to decide whether that margin really fits. The mechanism whether it fits would be nested in a common function that decides whether any decoration (fringe, scroll bar, margin) fits into any window showing that buffer based on the minimum sizes of that window and the sizes of the remaining decorations. Passing a "this is the requested new value of the right margin" setting to such a function is awkward at the very least. Objections, suggestions, comments? Thanks, martin --------------B7DD5BFF9859C534CC2D68F8 Content-Type: text/x-patch; name="after-variable-watchers.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="after-variable-watchers.diff" diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 36abc316cb..8a4ff26c13 100644 =2D-- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -842,7 +842,7 @@ Watching Variables The following functions may be used to manipulate and query the watch functions for a variable. -@defun add-variable-watcher symbol watch-function +@defun add-variable-watcher symbol watch-function after This function arranges for @var{watch-function} to be called whenever @var{symbol} is modified. Modifications through aliases (@pxref{Variable Aliases}) will have the same effect. @@ -858,16 +858,25 @@ Watching Variables @code{unlet}, @code{makunbound}, or @code{defvaralias}. @var{where} is a buffer if the buffer-local value of the variable is being changed, @code{nil} otherwise. + +If the optional third argument @var{after} is non-@code{nil}, this means +to call @var{watch-function} after changing the value of @var{symbol}. +In that case the second argument passed to @var{watch-function} will be +the value of @var{symbol} before it was set to the current value. @end defun -@defun remove-variable-watcher symbol watch-function +@defun remove-variable-watcher symbol watch-function after This function removes @var{watch-function} from @var{symbol}'s list of -watchers. +watchers. The third argument @var{after} should match the same argument +used by the previous @code{add-variable-watcher} call. @end defun -@defun get-variable-watchers symbol +@defun get-variable-watchers symbol after This function returns the list of @var{symbol}'s active watcher -functions. +functions. If the optional second argument @var{after} is @code{nil}, +this means to return watchers run before @var{symbol}'s value is set. +If @var{after} is non-@code{nil}, this means to return watchers run +after @var{symbol}'s value is set. @end defun @subsection Limitations diff --git a/src/alloc.c b/src/alloc.c index 76d8c7ddd1..a9a67462eb 100644 =2D-- a/src/alloc.c +++ b/src/alloc.c @@ -7662,14 +7662,14 @@ syms_of_alloc (void) { .a4 =3D watch_gc_cons_threshold }, 4, 4, "watch_gc_cons_threshold", {0}, 0}}; XSETSUBR (watcher, &Swatch_gc_cons_threshold.s); - Fadd_variable_watcher (Qgc_cons_threshold, watcher); + Fadd_variable_watcher (Qgc_cons_threshold, watcher, Qnil); static union Aligned_Lisp_Subr Swatch_gc_cons_percentage =3D {{{ PSEUDOVECTOR_FLAG | (PVEC_SUBR << PSEUDOVECTOR_AREA_BITS) }, { .a4 =3D watch_gc_cons_percentage }, 4, 4, "watch_gc_cons_percentage", {0}, 0}}; XSETSUBR (watcher, &Swatch_gc_cons_percentage.s); - Fadd_variable_watcher (Qgc_cons_percentage, watcher); + Fadd_variable_watcher (Qgc_cons_percentage, watcher, Qnil); } #ifdef HAVE_X_WINDOWS diff --git a/src/buffer.c b/src/buffer.c index df302db0e5..cc1f6414b8 100644 =2D-- a/src/buffer.c +++ b/src/buffer.c @@ -1045,10 +1045,9 @@ reset_buffer_local_variables (struct buffer *b, boo= l permanent_too) Lisp_Object prop =3D Fget (local_var, Qpermanent_local); Lisp_Object sym =3D local_var; - /* Watchers are run *before* modifying the var. */ if (XSYMBOL (local_var)->u.s.trapped_write =3D=3D SYMBOL_TRAPPE= D_WRITE) - notify_variable_watchers (local_var, Qnil, - Qmakunbound, Fcurrent_buffer ()); + notify_variable_watchers (local_var, Qnil, Qmakunbound, + Fcurrent_buffer (), false); eassert (XSYMBOL (sym)->u.s.redirect =3D=3D SYMBOL_LOCALIZED); /* Need not do anything if some other buffer's binding is @@ -1076,9 +1075,9 @@ reset_buffer_local_variables (struct buffer *b, bool= permanent_too) for (newlist =3D Qnil; CONSP (list); list =3D XCDR (l= ist)) { Lisp_Object elt =3D XCAR (list); - /* Preserve element ELT if it's t, - if it is a function with a `permanent-local-ho= ok' property, - or if it's not a symbol. */ + /* Preserve element ELT if it's t, if it is a + function with a `permanent-local-hook' + property, or if it's not a symbol. */ if (! SYMBOLP (elt) || EQ (elt, Qt) || !NILP (Fget (elt, Qpermanent_local_hook))) @@ -1087,8 +1086,8 @@ reset_buffer_local_variables (struct buffer *b, bool= permanent_too) newlist =3D Fnreverse (newlist); if (XSYMBOL (local_var)->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE) - notify_variable_watchers (local_var, newlist, - Qmakunbound, Fcurrent_buffe= r ()); + notify_variable_watchers (local_var, newlist, Qmakunb= ound, + Fcurrent_buffer (), true); XSETCDR (XCAR (tmp), newlist); continue; /* Don't do variable write trapping twice. *= / } @@ -1112,7 +1111,24 @@ reset_buffer_local_variables (struct buffer *b, boo= l permanent_too) if ((idx > 0 && (permanent_too || buffer_permanent_local_flags[idx] =3D=3D 0))) - set_per_buffer_value (b, offset, per_buffer_default (offset)); + { + Lisp_Object symbol =3D PER_BUFFER_SYMBOL (offset); + Lisp_Object old_value =3D ((idx =3D=3D -1 || PER_BUFFER_VALUE_P (b, id= x)) + ? per_buffer_value (b, offset) + : Qnil); + + if (SYMBOLP (symbol) + && XSYMBOL (symbol)->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE= ) + notify_variable_watchers (symbol, old_value, Qmakunbound, + Fcurrent_buffer (), false); + + set_per_buffer_value (b, offset, per_buffer_default (offset)); + + if (SYMBOLP (symbol) + && XSYMBOL (symbol)->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE= ) + notify_variable_watchers (symbol, old_value, Qmakunbound, + Fcurrent_buffer (), true); + } } } diff --git a/src/data.c b/src/data.c index d547f5da5e..bf0722bc65 100644 =2D-- a/src/data.c +++ b/src/data.c @@ -1478,6 +1478,8 @@ set_internal (Lisp_Object symbol, Lisp_Object newval= , Lisp_Object where, CHECK_SYMBOL (symbol); struct Lisp_Symbol *sym =3D XSYMBOL (symbol); + Lisp_Object old_value =3D Qunbound; + switch (sym->u.s.trapped_write) { case SYMBOL_NOWRITE: @@ -1489,13 +1491,13 @@ set_internal (Lisp_Object symbol, Lisp_Object newv= al, Lisp_Object where, return; case SYMBOL_TRAPPED_WRITE: + old_value =3D find_symbol_value (symbol); /* Setting due to thread-switching doesn't count. */ if (bindflag !=3D SET_INTERNAL_THREAD_SWITCH) - notify_variable_watchers (symbol, voide? Qnil : newval, - (bindflag =3D=3D SET_INTERNAL_BIND? Qle= t : - bindflag =3D=3D SET_INTERNAL_UNBIND? Q= unlet : - voide? Qmakunbound : Qset), - where); + notify_variable_watchers (symbol, voide ? Qnil : newval, + ((bindflag =3D=3D SET_INTERNAL_BIND) ? Qlet : + (bindflag =3D=3D SET_INTERNAL_UNBIND) ? Qunlet : + voide ? Qmakunbound : Qset), where, false); break; case SYMBOL_UNTRAPPED_WRITE: @@ -1508,7 +1510,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval= , Lisp_Object where, switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym =3D indirect_variable (sym); goto start; - case SYMBOL_PLAINVAL: SET_SYMBOL_VAL (sym , newval); return; + case SYMBOL_PLAINVAL: SET_SYMBOL_VAL (sym, newval); goto stop; case SYMBOL_LOCALIZED: { struct Lisp_Buffer_Local_Value *blv =3D SYMBOL_BLV (sym); @@ -1619,6 +1621,15 @@ set_internal (Lisp_Object symbol, Lisp_Object newva= l, Lisp_Object where, } default: emacs_abort (); } + + stop: + if (sym->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE + && bindflag !=3D SET_INTERNAL_THREAD_SWITCH) + notify_variable_watchers (symbol, EQ (old_value, Qunbound) ? Qnil : o= ld_value, + ((bindflag =3D=3D SET_INTERNAL_BIND) ? Qlet : + (bindflag =3D=3D SET_INTERNAL_UNBIND) ? Qunlet : + voide ? Qmakunbound : Qset), + where, true); return; } @@ -1626,6 +1637,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval= , Lisp_Object where, set_symbol_trapped_write (Lisp_Object symbol, enum symbol_trapped_write t= rap) { struct Lisp_Symbol *sym =3D XSYMBOL (symbol); + if (sym->u.s.trapped_write =3D=3D SYMBOL_NOWRITE) xsignal1 (Qtrapping_constant, symbol); sym->u.s.trapped_write =3D trap; @@ -1647,7 +1659,7 @@ harmonize_variable_watchers (Lisp_Object alias, Lisp= _Object base_variable) } DEFUN ("add-variable-watcher", Fadd_variable_watcher, Sadd_variable_watch= er, - 2, 2, 0, + 2, 3, 0, doc: /* Cause WATCH-FUNCTION to be called when SYMBOL is about to = be set. It will be called with 4 arguments: (SYMBOL NEWVAL OPERATION WHERE). @@ -1659,55 +1671,86 @@ DEFUN ("add-variable-watcher", Fadd_variable_watch= er, Sadd_variable_watcher, WHERE is a buffer if the buffer-local value of the variable is being changed, nil otherwise. +Third argument AFTER, if non-nil, means to call WATCH-FUNCTION after +SYMBOL has been set. In that case, the second argument for +WATCH-FUNCTION will be the value of SYMBOL before it was set to the +current value. + All writes to aliases of SYMBOL will call WATCH-FUNCTION too. */) - (Lisp_Object symbol, Lisp_Object watch_function) + (Lisp_Object symbol, Lisp_Object watch_function, Lisp_Object after) { + CHECK_SYMBOL (symbol); + symbol =3D Findirect_variable (symbol); CHECK_SYMBOL (symbol); set_symbol_trapped_write (symbol, SYMBOL_TRAPPED_WRITE); map_obarray (Vobarray, harmonize_variable_watchers, symbol); - Lisp_Object watchers =3D Fget (symbol, Qwatchers); - Lisp_Object member =3D Fmember (watch_function, watchers); - if (NILP (member)) - Fput (symbol, Qwatchers, Fcons (watch_function, watchers)); + if (NILP (after)) + { + Lisp_Object watchers =3D Fget (symbol, Qwatchers_before); + + if (NILP (Fmember (watch_function, watchers))) + Fput (symbol, Qwatchers_before, Fcons (watch_function, watchers)); + } + else + { + Lisp_Object watchers =3D Fget (symbol, Qwatchers_after); + + if (NILP (Fmember (watch_function, watchers))) + Fput (symbol, Qwatchers_after, Fcons (watch_function, watchers)); + } + return Qnil; } DEFUN ("remove-variable-watcher", Fremove_variable_watcher, Sremove_varia= ble_watcher, - 2, 2, 0, + 2, 3, 0, doc: /* Undo the effect of `add-variable-watcher'. Remove WATCH-FUNCTION from the list of functions to be called when SYMBOL (or its aliases) are set. */) - (Lisp_Object symbol, Lisp_Object watch_function) + (Lisp_Object symbol, Lisp_Object watch_function, Lisp_Object after) { symbol =3D Findirect_variable (symbol); - Lisp_Object watchers =3D Fget (symbol, Qwatchers); - watchers =3D Fdelete (watch_function, watchers); - if (NILP (watchers)) + + Lisp_Object watchers_before =3D Fget (symbol, Qwatchers_before); + Lisp_Object watchers_after =3D Fget (symbol, Qwatchers_after); + + if (NILP (after)) + { + watchers_before =3D Fdelete (watch_function, watchers_before); + Fput (symbol, Qwatchers_before, watchers_before); + } + else + { + watchers_after =3D Fdelete (watch_function, watchers_after); + Fput (symbol, Qwatchers_after, watchers_after); + } + + if (NILP (watchers_before) && NILP (watchers_after)) { set_symbol_trapped_write (symbol, SYMBOL_UNTRAPPED_WRITE); map_obarray (Vobarray, harmonize_variable_watchers, symbol); } - Fput (symbol, Qwatchers, watchers); + return Qnil; } DEFUN ("get-variable-watchers", Fget_variable_watchers, Sget_variable_wat= chers, - 1, 1, 0, - doc: /* Return a list of SYMBOL's active watchers. */) - (Lisp_Object symbol) + 1, 2, 0, + doc: /* Return a list of SYMBOL's active watchers. +Optional second argument AFTER nil means to return watchers run before +SYMBOL's value is set. AFTER non-nil means to return watchers run after +SYMBOL's value is set. */) + (Lisp_Object symbol, Lisp_Object after) { - return (SYMBOL_TRAPPED_WRITE_P (symbol) =3D=3D SYMBOL_TRAPPED_WRITE) - ? Fget (Findirect_variable (symbol), Qwatchers) - : Qnil; + return (Fget (Findirect_variable (symbol), + NILP (after) ? Qwatchers_before : Qwatchers_after)); } void -notify_variable_watchers (Lisp_Object symbol, - Lisp_Object newval, - Lisp_Object operation, - Lisp_Object where) +notify_variable_watchers (Lisp_Object symbol, Lisp_Object newval, + Lisp_Object operation, Lisp_Object where, bool after) { symbol =3D Findirect_variable (symbol); @@ -1719,22 +1762,23 @@ notify_variable_watchers (Lisp_Object symbol, if (NILP (where) && !EQ (operation, Qset_default) && !EQ (operation, Qmakunbound) && !NILP (Flocal_variable_if_set_p (symbol, Fcurrent_buffer ()))) - { - XSETBUFFER (where, current_buffer); - } + XSETBUFFER (where, current_buffer); if (EQ (operation, Qset_default)) operation =3D Qset; - for (Lisp_Object watchers =3D Fget (symbol, Qwatchers); + for (Lisp_Object watchers + =3D Fget (symbol, after ? Qwatchers_after : Qwatchers_before); CONSP (watchers); watchers =3D XCDR (watchers)) { Lisp_Object watcher =3D XCAR (watchers); + /* Call subr directly to avoid gc. */ if (SUBRP (watcher)) { Lisp_Object args[] =3D { symbol, newval, operation, where }; + funcall_subr (XSUBR (watcher), ARRAYELTS (args), args); } else @@ -1828,6 +1872,8 @@ set_default_internal (Lisp_Object symbol, Lisp_Objec= t value, { CHECK_SYMBOL (symbol); struct Lisp_Symbol *sym =3D XSYMBOL (symbol); + Lisp_Object old_value =3D Qunbound;; + switch (sym->u.s.trapped_write) { case SYMBOL_NOWRITE: @@ -1839,11 +1885,12 @@ set_default_internal (Lisp_Object symbol, Lisp_Obj= ect value, return; case SYMBOL_TRAPPED_WRITE: + old_value =3D find_symbol_value (symbol); /* Don't notify here if we're going to call Fset anyway. */ if (sym->u.s.redirect !=3D SYMBOL_PLAINVAL /* Setting due to thread switching doesn't count. */ && bindflag !=3D SET_INTERNAL_THREAD_SWITCH) - notify_variable_watchers (symbol, value, Qset_default, Qnil); + notify_variable_watchers (symbol, value, Qset_default, Qnil, fals= e); break; case SYMBOL_UNTRAPPED_WRITE: @@ -1867,7 +1914,7 @@ set_default_internal (Lisp_Object symbol, Lisp_Objec= t value, /* If the default binding is now loaded, set the REALVALUE slot too. */ if (blv->fwd.fwdptr && EQ (blv->defcell, blv->valcell)) store_symval_forwarding (blv->fwd, value, NULL); - return; + goto stop; } case SYMBOL_FORWARDED: { @@ -1906,10 +1953,16 @@ set_default_internal (Lisp_Object symbol, Lisp_Obj= ect value, } else set_internal (symbol, value, Qnil, bindflag); - return; + goto stop; } default: emacs_abort (); } + + stop: + if (sym->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE + && sym->u.s.redirect !=3D SYMBOL_PLAINVAL + && bindflag !=3D SET_INTERNAL_THREAD_SWITCH) + notify_variable_watchers (symbol, old_value, Qset_default, Qnil, true= ); } DEFUN ("set-default", Fset_default, Sset_default, 2, 2, 0, @@ -2142,6 +2195,9 @@ DEFUN ("kill-local-variable", Fkill_local_variable, = Skill_local_variable, struct Lisp_Symbol *sym; CHECK_SYMBOL (variable); + + Lisp_Object old_value =3D find_symbol_value (variable); + sym =3D XSYMBOL (variable); start: @@ -2173,7 +2229,8 @@ DEFUN ("kill-local-variable", Fkill_local_variable, = Skill_local_variable, } if (sym->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE) - notify_variable_watchers (variable, Qnil, Qmakunbound, Fcurrent_buffe= r ()); + notify_variable_watchers (variable, Qnil, Qmakunbound, + Fcurrent_buffer (), false); /* Get rid of this buffer's alist element, if any. */ XSETSYMBOL (variable, sym); /* Propagate variable indirection. */ @@ -2192,6 +2249,10 @@ DEFUN ("kill-local-variable", Fkill_local_variable,= Skill_local_variable, swap_in_global_binding (sym); } + if (sym->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE) + notify_variable_watchers (variable, old_value, Qmakunbound, + Fcurrent_buffer (), true); + return variable; } @@ -4195,7 +4256,8 @@ #define PUT_ERROR(sym, tail, msg) \ Vmost_negative_fixnum =3D make_fixnum (MOST_NEGATIVE_FIXNUM); make_symbol_constant (intern_c_string ("most-negative-fixnum")); - DEFSYM (Qwatchers, "watchers"); + DEFSYM (Qwatchers_before, "watchers-before"); + DEFSYM (Qwatchers_after, "watchers-after"); DEFSYM (Qmakunbound, "makunbound"); DEFSYM (Qunlet, "unlet"); DEFSYM (Qset, "set"); diff --git a/src/eval.c b/src/eval.c index aeedcc50cc..6d69d54ef2 100644 =2D-- a/src/eval.c +++ b/src/eval.c @@ -603,6 +603,7 @@ DEFUN ("defvaralias", Fdefvaralias, Sdefvaralias, 2, 3= , 0, (Lisp_Object new_alias, Lisp_Object base_variable, Lisp_Object docstrin= g) { struct Lisp_Symbol *sym; + Lisp_Object old_value =3D Qnil; CHECK_SYMBOL (new_alias); CHECK_SYMBOL (base_variable); @@ -634,7 +635,7 @@ DEFUN ("defvaralias", Fdefvaralias, Sdefvaralias, 2, 3= , 0, set_internal (base_variable, find_symbol_value (new_alias), Qnil, SET_INTERNAL_BIND); else if (!NILP (Fboundp (new_alias)) - && !EQ (find_symbol_value (new_alias), + && !EQ (old_value =3D find_symbol_value (new_alias), find_symbol_value (base_variable))) call2 (intern ("display-warning"), list3 (Qdefvaralias, intern ("losing-value"), new_alias), @@ -653,8 +654,8 @@ DEFUN ("defvaralias", Fdefvaralias, Sdefvaralias, 2, 3= , 0, } if (sym->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE) - notify_variable_watchers (new_alias, base_variable, Qdefvaralias, Qni= l); - + notify_variable_watchers (new_alias, base_variable, + Qdefvaralias, Qnil, false); sym->u.s.declared_special =3D true; XSYMBOL (base_variable)->u.s.declared_special =3D true; sym->u.s.redirect =3D SYMBOL_VARALIAS; @@ -664,6 +665,9 @@ DEFUN ("defvaralias", Fdefvaralias, Sdefvaralias, 2, 3= , 0, /* Even if docstring is nil: remove old docstring. */ Fput (new_alias, Qvariable_documentation, docstring); + if (sym->u.s.trapped_write =3D=3D SYMBOL_TRAPPED_WRITE) + notify_variable_watchers (new_alias, old_value, Qdefvaralias, Qnil, t= rue); + return base_variable; } diff --git a/src/lisp.h b/src/lisp.h index f83c55f827..ba7edb86a3 100644 =2D-- a/src/lisp.h +++ b/src/lisp.h @@ -3535,7 +3535,7 @@ modiff_to_integer (modiff_count a) /* Defined in data.c. */ extern AVOID wrong_choice (Lisp_Object, Lisp_Object); extern void notify_variable_watchers (Lisp_Object, Lisp_Object, - Lisp_Object, Lisp_Object); + Lisp_Object, Lisp_Object, bool); extern Lisp_Object indirect_function (Lisp_Object); extern Lisp_Object find_symbol_value (Lisp_Object); enum Arith_Comparison { --------------B7DD5BFF9859C534CC2D68F8--