Subject: bug#19576: write-file writes the wrong buffer

From: Eli Zaretskii <[email-masked]>
Date: Wed, 18 Nov 2015 22:52:26 +0200

> Date: Wed, 18 Nov 2015 20:23:42 +0100
> From: Anders Lindgren <[email-masked]>
> Cc: Juri Linkov <[email-masked]>, martin rudalics <[email-masked]>, Alan Mackenzie <[email-masked]>, 
> 	[email-masked]
> 
>     I don't understand why
>     
>     (set-window-start WINDOW POS t)
>     
>     is not sufficient. It does force the display engine to honor the
>     window-start position requested by the call; no recentering will take
>     place. You say you "would prefer if it was possible to tell the
>     display engine to leave some windows alone", but that's exactly what
>     the above call does, wrt the starting position of the window. So why
>     isn't it sufficient?
>     
> 
> If "pos" is point-max, the window will be recentered after a while. You can try
> by entering the following in the *scratch* buffer:
> 
> (set-window-start (selected-window) (point-max) t)
> 
> Place the cursor at the end of the buffer and evaluate the expression using
> M-C-x.
> 
> If you work with Emacs for a while, you will notice that the content of the
> *scratch* buffer will be visible after a while.

Is the M-C-x part important?  (I used M-: instead.)  If it isn't, then
I don't see any spontaneous recentering after that, so a reproducible
test case will be appreciated.  Maybe something that makes the
difference hides behind "work with Emacs for a while", I don't know.

> As I have mentioned before, I would like to have a hook variable that the
> display engine can call when doing this.

When doing what?

> Packaged like follow-mode can use this to override the default
> behaviour.

The default behavior in what aspect?

> "Grep" does in fact do the right thing, the grep hit arrow move across the
> visible windows nicely.
> 
> A package like "ispell" behaves behaves worse since it, somehow, prevent
> follow-mode from doing it's job. The effect is that the windows are no longer
> aligned (i.e. some lines are visible in more than one window, or some lines
> between two windows are no longer shown.)
> 
> Another thing that makes things difficult is that the *selected* window group
> is aligned by follow-mode. If a package wants to show (but not select) another
> buffer, the windows of the other buffer will not be aligned automatically, and
> there is no good interface for this. (In my package `font-lock-studio', a
> control buffer is shown in the selected window, but I wanted the source buffer
> to be displayed aligned (if follow-mode was active). I ended up calling
> follow-post-command-hook directly, which really isn't a good practice.)

These all sound like application-level problems to me, not issues with
the display engine.  At least not in the first approximation.

>     > * Process output: In early versions of follow-mode, it could be used with
>     > any process. This was accomplished using `defadvice' on a handful of
>     > process-related functions. At some point in time, this system was
>     replaced
>     > with a system specific to comint and compilation buffers -- as part of
>     the
>     > great defadvice sweep. Personally, I would like to Emacs to provide
>     > `pre-process-output-functions' and `post-process-output-functions',
>     > allowing packages like follow-mode to perform whatever action they would
>     > like to the output of any process.
>     
>     Such hooks will be almost trivial to provide, I think. But I don't
>     think I understand what problems would such hooks solve. Could you
>     elaborate?
>     
> 
> Follow mode can be used both in plain source buffers and in process buffers.
> Concretely, you can have a *shell* buffer displayed in a number of side by side
> windows, where the prompt is at the bottom of the rightmost one, and the rest
> shows your recent activity.
> 
> Normally, follow-mode use the post-command-hook to ensure that the windows are
> aligned. However, when you type something like "ls -lR" in your shell, output
> will be coming in through the process system, which is not seen by the
> post-command-hook.

Doesn't this mean that you need a way to hook buffer text changes?
Hooking processes is not necessarily what you want, since a process
filter could eat up the output completely and not show it in any
window, in which case follow-mode shouldn't be bothered.  Right?

> However, one way to handle this is to respect an explicit `set-window-start'
> position even if the column isn't a multiple of the screen width.

Ask Alain how easy that is.

I'm telling you: this is the tip of a huge iceberg.  The display
engine was never designed to handle windows whose redisplay depends on
other windows.

> > Thanks for working on this, Martin. However, I don't think we should
> > install this change. We call Lisp hooks from many places, including
> > maybe a dozen in the display engine. It makes little sense to make
> > only one of them resistant to this kind of problems. OTOH, if we do
> > this everywhere, I feel that we will unduly punish 99.999% percent of
> > legitimate users of these hooks just because one of them had a bug.
> >
> > I think this is a clear bug in follow.el, and should be fixed there,
> > and nowhere else. Perhaps we should also have some prominent warnings
> > in the documentation about this gotcha, so that the probability this
> > will happen again becomes lower.
> 
> I don't agree with you on this but I respect your opinion.
> 
> This is one of the most obscure bugs I have seen when working with Emacs --
> trying to figure out why on earth `write-file' would save the wrong buffer was
> no easy task, even with many years of Emacs experience under my belt.
> 
> There is a risk that other package writers will stumble upon similar problems
> and give up, or write it of as "unexplainable". Ensuring that the caller saves
> and restores the state is a very cheap life saver.

It's cheap for the "perpetrators", but it distributes the cost among
the "innocent".  Sorry, I simply cannot agree to such "re-balancing"
of guilt.

And yes, I know how much time debugging a tricky bug can consume.
been there, done that.  Still, once the reason is identified, we must
find the best place to fix it.  Choosing that place frequently
involves compromises.