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

From: Anders Lindgren <[email-masked]>
Date: Wed, 18 Nov 2015 20:23:42 +0100

Hi!

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. This is what
`follow-avoid-tail-recenter' is designed to avoid. (For follow-mode, this
mean that the illusion of one tall window is broken, when the visible text
doesn't reach the rightmost window.)

As I have mentioned before, I would like to have a hook variable that the
display engine can call when doing this. Packaged like follow-mode can use
this to override the default behaviour.

> > * Make it easier for other packages to use it. By this I mean packages
> that
> > display information, like "grep", should be able to use follow mode to
> > display a buffer using side by side windows.
>
> But Follow is a minor-mode, right?  So why cannot Grep etc. just turn
> it on?
>

A package should never turn follow-mode on, but it should respect it when
it is activated in buffer!

Effectively, if a package wants to display a line in a buffer, and that
line is visible in any of the windows in a follow-mode window group, that
window should be used regardless if it was the window that was selected
before.

"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.)

> * When follow-mode is enabled, there is a noticeable lag when updating the
> > region. You can see this by pressing C-c SPACE and holding the up or down
> > key. When follow-mode is disabled, the region is updated as fast as the
> > cursor moves, when enabled, it is updated in chunks.
>
> I guess follow-mode's post-command-hook interferes with
> pre-redisplay-functions used to display the region nowadays.  Please
> look into this, it would be good to fix this before Emacs 25.1 is out.
>

Unfortunately, I won't be able to work on this. We are expecting a baby any
day now and when it comes to Emacs-related activitied I have picked up
where Jan Djärv left of regarding the NextStep port.

Besides, this is more of a minor irritation point rather than showstopper,
so it might just as well wait.

> * 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.

In my original follow-mode implementation, the process filter functions
were advices so that all process output were passed through follow-modes
own filter functions that aligned the windows and passed the output the
real filter functions. The effect was that all process buffer, regardless
of which system they used, worked with follow mode. At some point in time
it was decided that `defavice' should not be used and this system was
replaced with a simpler system only working with compilation and comint
buffers.

If generic process output hooks follow-mode could once again work for all
processes, and in a much cleaner way. I can see other packages taking
advantage of this, like packages that would color output or strip away
parts of the output etc.

> * If a user have columns with different widths, follow-mode can't
> correctly
> > display long lines stretching from one window to the next. The reason for
> > this is that the start position can't be placed at an arbitrary location
> on
> > a long line, only on positions that are a multiple of the column width. I
> > don't see any way to solve this without modifying the display engine.
>
> This is a tough nut, and the real problem is not necessarily obvious.
> The real problem is that the display engine _assumes_ the lines above
> and below the window edge are of the same pixel width.  It uses this
> assumption in its layout code and decisions.  But when follow-mode us
> used in windows of unequal width, that assumption breaks.  This is a
> very serious problem, because the basic design of the Emacs display
> engine is that it does its job one window at a time, i.e. it assumes
> that displaying a window is possible by examining only the data of
> that single window, and its associated buffer.
>

In most cases this is the sane thing to do, I guess.

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.

> 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.

    -- Anders