unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Eli Zaretskii <eliz@gnu.org>
To: martin rudalics <rudalics@gmx.at>
Cc: npostavs@gmail.com, emacs-devel@gnu.org
Subject: Re: "after" variable watchers
Date: Thu, 20 May 2021 16:46:42 +0300	[thread overview]
Message-ID: <83sg2ho6v1.fsf@gnu.org> (raw)
In-Reply-To: <37077232-fdf9-983c-3a34-a2334a7a8f49@gmx.at> (message from martin rudalics on Tue, 18 May 2021 17:10:24 +0200)

> Cc: npostavs@gmail.com, emacs-devel@gnu.org
> From: martin rudalics <rudalics@gmx.at>
> Date: Tue, 18 May 2021 17:10:24 +0200
> 
> (1) The desired width of W's left fringe as set by `set-window-fringes'
>      and stored in a slot w->nominal_left_fringe_width where a value of
>      -1 stands for "take the width from W's buffer",

Side note: could we please NOT call these "nominal" values?  "Nominal"
means "standard", whereas these aren't.  How about "desired" or
"requested"?

> (2) the value of `left-fringe-width' of W's buffer where anything but a
>      non-negative number means to "take the width from W's frame", and
> 
> (3) the value of f->left_fringe_width of W's frame as installed by
>      gui_set_left_fringe - a non-negative integer.
> 
> This is the function:
> 
> /** Return configured width of W's left fringe.  */
> static int
> window_config_left_fringe_width (struct window *w)
> {
>    int width = (WINDOW_NON_GRAPHICAL_OR_PSEUDO_P (w)
> 	       ? 0 : w->nominal_left_fringe_width);
> 
>    if (width < 0)
>      {
>        Lisp_Object value = WINDOW_BUFFER_LOCAL_VALUE (Qleft_fringe_width, w);
> 
>        width = (RANGED_FIXNUMP (0, value, INT_MAX)
> 	       ? XFIXNAT (value)
> 	       : FRAME_LEFT_FRINGE_WIDTH (XFRAME (WINDOW_FRAME (w))));
>      }
> 
>    return width;
> }
> 
> window_config_left_fringe_width would be run, among many others,
> whenever we
> 
> (i) call `set-window-fringes' for W, change `left-fringe-width' of W's
>      buffer or change the 'left-fringe' parameter of W's frame, and
> 
> (ii) change the size of W.
> 
> The value produced by this function is stored in w->left_fringe_width
> provided it fits into that window.  Otherwise, a value of 0 is stored.
> (In the latter case, all remaining horizontal decorations of W will get
> a width of 0 too.) The value stored is called the "realized" value of
> W's left fringe width.  The realized value is used to display the
> window, to determine its box width and the horizontal position where the
> text area starts.
> 
> The value produced by this function is _also_ used to determine the
> minimum width of W which is needed to tell whether W can be split or
> resized and also to tell the window manager what W's frame's minimum
> width should be.
> 
> Please tell me now if any of the reasoning I've done so far is wrong in
> your opinion.  In that case we could try to find a different solution
> for such a function or abolish the idea.  Otherwise, please read on.
> 
> Now suppose I assign a new value to `left-fringe-width' of W's buffer.
> 
> - If I do not watch `left-fringe-width' at all, the new value will be
>    picked up by redisplay the next time I call this function for some
>    other reason, for example, when resizing W, unless it is preceded by a
>    `set-window-buffer'.  Such an effect could be surprising at least.  It
>    may lead to inconsistent behavior when W shall be split or resized.

Presumably, we are now at this situation?  If so, what are the
practical problems with what we have now?  We had this since many
years ago, and I'm not aware of any significant problems with what we
have.  So what are the reasons for wanting such a significant new
infrastructure, if we don't have serious problems with what we have?

> - If I use a normal "before" watcher, the effect would probably be seen
>    with the next redisplay.  Still there's no guarantee that this would
>    happen, so a surprising effect can still not be excluded.
> 
> So I would either have to explicitly pass the new value of
> `left-fringe-width' down to window_config_left_fringe_width, check there
> whether it is sane (which amounts to do twice everything the
> gui_set_... functions do) and apply it then or, use what I called an
> "after" variable watcher which installs the new value before running
> window_config_left_fringe_width.

If your proposed "after" watcher will calculate a "sanitized" value of
w->left_fringe_width and store it in the window's structure, then why
does it have to run "after" the change? the effect of the change will
not be shown until the next redisplay cycle anyway.

>  > And note that the analogy is incomplete at best: the watchers in
>  > frame.el watch _variables_ that we used to have forever, so making
>  > them modifiable only via accessor functions would be a breaking
>  > change.  Whereas you are talking about stuff which is done by
>  > functions already.
> 
> My window.el has
> 
> (mapc (lambda (var)
>          (add-variable-watcher var (symbol-function 'window-update-decorations-for-variable) t))
>        '(window-scale-body
>          window-drop-decorations
>          face-remapping-alist
>          line-spacing
>          min-body-width
>          min-body-height
>          left-fringe-width
>          right-fringe-width
>          fringes-outside-margins
>          vertical-scroll-bar
>          horizontal-scroll-bar
>          scroll-bar-width
>          scroll-bar-height
>          left-margin-width
>          right-margin-width
>          mode-line-format
>          header-line-format
>          tab-line-format))
> 
> where most are variables that we used to have for quite some time and
> some figure here as well as in your list.

line-spacing and face-remapping-alist don't really belong there, do
they?  Likewise mode-line-format and header-line-format, AFAIR.
AFAIK, the changes in those are immediately shown by the next
redisplay.  So why are they in the above list?

As for the rest: once again, what problems do we have now with changes
to them?

Note that changes to the variables listed in frame.el do only one
thing: set a flag in the buffer's structure telling the display code
this buffer needs to be redisplayed.  By contrast, you want to run
complex functions when the variables are modified, and actually affect
the values stored as result.  That is unheard of in Emacs; it is
almost like you are asking for having changes in some variables to
automatically run a function.

>  > I think this could be a step in the wrong direction.  It might be
>  > easier for users, but it makes it harder for us to develop Emacs in
>  > the long run, for example if we want more threading.  That's because
>  > all those global and buffer-local variables are part of the huge
>  > global state we have, and that gets in the way of some features.
> 
> Can you explain how my proposal could be related to threading and what
> kind of features it might break there?

Reducing the global state means we need to access variables via
accessor functions.  Your suggestion goes in the exact opposite
direction: you want a change in a variable's value to have an
immediate effect, which would mean we'd need more variables to be
thread-local, or risk causing changes in the wrong buffer/thread.

>  >> 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.
>  >
>  > So we get silent fixes for all of them?  Not sure this is an
>  > improvement.  I think we already had complaints about silently
>  > "fixing" the decorations as we see fit.
> 
> Your last statement is partially ironic and not really nice, in
> particular because it inverts the state of affairs.

There's no irony there, none at all.  As for not being nice, I
apologize if this comes that way, but I assure you nothing like that
was ever intended.

> Emacs 27 explicitly states in set_window_fringes to
> 
>        	 Check dimensions of new fringes.  Make changes only if they
> 	 fit the window's dimensions.
> 
> So Emacs 27 silently ignores the value of `left-fringe-width' whenever
> it does not fit and keeps on ignoring it when the window gets enlarged
> sufficiently to show them afterwards.

Ignoring invalid changes, when this is documented, is not a
catastrophe.  Maybe I don't understand your plan, but it sounds to me
like you want to extend such silent "editing" of set values to many
more widow-related attributes; left-fringe-width was just an example,
right? and setting it to zero when unfit was also just an example,
right?

> With my proposal, no settings are ever ignored or fixed silently.
> Decorations will grow and shrink together with their windows and frames.
> IMO this is better than, for example, showing the left margin instead of
> the window's text area when a window has become too narrow.

I don't know if it's better.  I'm mainly worried that we are trying to
invent significant infrastructure to fix problems that I don't think I
understand sufficiently well, and in fact am not aware they even
exist.  So maybe we should make a step back and describe and discuss
those problems first.



  reply	other threads:[~2021-05-20 13:46 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-17  8:27 "after" variable watchers martin rudalics
2021-05-17 10:23 ` Eli Zaretskii
2021-05-17 16:40   ` martin rudalics
2021-05-17 16:57     ` Eli Zaretskii
2021-05-18 15:10       ` martin rudalics
2021-05-20 13:46         ` Eli Zaretskii [this message]
2021-05-24  8:47           ` martin rudalics
2021-05-27 16:51             ` Eli Zaretskii
2021-06-06  7:42               ` martin rudalics
2021-05-17 18:36     ` Stefan Monnier
2021-05-17 18:45       ` Eli Zaretskii
2021-05-17 18:54         ` Stefan Monnier
2021-05-17 18:55           ` Stefan Monnier
2021-05-18 15:10       ` martin rudalics
2021-05-18 15:57         ` Stefan Monnier
2021-05-18 17:01           ` martin rudalics
2021-05-20 13:49             ` Eli Zaretskii
2021-05-24  8:48               ` martin rudalics
2021-05-27 16:53                 ` Eli Zaretskii
2021-05-17 14:57 ` Matt Armstrong
2021-05-17 16:41   ` martin rudalics

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=83sg2ho6v1.fsf@gnu.org \
    --to=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=npostavs@gmail.com \
    --cc=rudalics@gmx.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).