emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: "after" variable watchers


From: martin rudalics
Subject: Re: "after" variable watchers
Date: Mon, 17 May 2021 18:40:09 +0200

> But the watcher function already gets the new value, so why do we need
> to be able to call it after the variable's value was changed?

Because knowing the new value in the watch function is of no practical
use.  I'd have to pass it down to all functions called directly or
indirectly by the watch function that make use of that value.

>> 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.
>
> I don't think I understand the use case, and so cannot follow your
> "awkward" argument.

I have a function called window_updeco_window that decides for each
window which of its decorations can be displayed and which decorations
must be suppressed because the window is too small.  Each aspect like
the width of the scroll bar or its right margin has a nominal and a
realized value.

The nominal value is the one set by default or by the user in a frame-,
buffer- or window-local way.  That value changes only when it is set by
the user.

The realized value is the one as it will appear on display.  It is
calculated from the nominal value and constraints imposed by the actual
size of the window, the window's character sizes and minimum body sizes.
If, for example, the nominal width of a scroll bar is too large, that
scroll bar is not displayed.  If the nominal width of the right margin
is too large, that margin will be either shrunk or not displayed at all.

window_updeco_window is called indirectly from all places that change a
window's decorations, font or size.  In order to have it DTRT when a
user wants to change a buffer's right margin width, for example, I would
have to pass the new value from the variable watcher function to
window_updeco_window and from there to the function that calculates the
realized width of the right margin from that of its nominal width.

That final client would then have to perform the sanity check whether
the value passed to it is really a number (or, for example, the value
for the vertical scroll bar type is really one of 'right', 'left' etc.).
Checks we would then have do perform twice because they would be
immediately afterwards be done in exactly the same way when setting the
buffer-local value.  Been there, tried that, didn't like it at all.

> In general, this is a debugging feature, while you seem to be
> describing a use case where the watcher will be a constant part of an
> implementation of some feature, is that right?

Right.  In the mold of your `add-variable-watcher' at the end of
frame.el.

> First, I'd like to better understand the need for this.

First, it's useful for having a change in a buffer's decorations take
effect immediately.  So we get rid of things like

  Setting this variable does not take effect until a new buffer is displayed
  in a window.  To make the change take effect, call ‘set-window-buffer’.

We also achieve a more consistent handling of the values of decorations.
Think of recalculating a specific window's decorations from a newly set
`scroll-bar-width' frame parameter and a buffer-local `scroll-bar-width'
that has not taken effect yet.

And finally we would get rid of the present mixture of errors thrown at
the user and that of changes that are silently ignored whenever a
decoration does not fit.  A user then can set the nominal width of the
right margin to some arbitrary number.  When the window is large enough
to accommodate it, it will be displayed that way.  When the window gets
too small, it will be temporarily clipped or skipped.

> If indeed this could be useful enough, I think I'd prefer 2 separate
> list of watchers and 2 bits to indicate which one of the 2 possible
> lists of watchers should be scanned to find the watcher function.  The
> way you implemented it will slow down Emacs in one of its most
> sensitive places: where we bind symbols to values, because we now need
> to scan the same list twice, and call Fget for each symbol to see if
> it's a "before" or an "after" watcher.

Right.  So you mean to write a separate notify_after_variable_watchers
function, say?  Good idea.

>> +
>>   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);
>
> I don't think I understand why you added CHECK_SYMBOL here.  There's
> one such call right after that.

There wasn't at the time I wrote that about a year ago and for some
reason the new instance got merged successfully.

Many thanks for the comments, martin




reply via email to

[Prev in Thread] Current Thread [Next in Thread]