Subject: Re: bug#33258: inhibit-select-window

From: martin rudalics <[email-masked]>
Date: Wed, 07 Nov 2018 10:22:38 +0100

> A prototype that demonstrates a problem-free implementation is:
 >
 > (advice-add 'vc-diff :around
 > 	    (lambda (orig-fun &rest args)
 > 	      (save-selected-window
 > 		(apply orig-fun args)))
 > 	    '((name . inhibit-select-window)))
 >
 > A question is how to do something like this using 'display-buffer-alist'
 > with 'inhibit-select-window'.

You cannot do that in a systematical way - 'display-buffer-alist' is
agnostic of its clients.  And don't forget clients of 'vc-diff' who
might rely on the fact that the latter selects the window chosen.
Ironically, they might do that for exactly the same reason as yours -
they don't want the diffs window to get selected.  Now suppose they do
that by selecting the window preceding or following the diffs window
in the cyclic order of windows right after the 'vc-diff' call ...  So
even your advice is not problem-free.

 > This is a huge task to inspect all existing pop-to-buffer calls
 > and to add 'allow-inhibit-select-window' where it's safe, or to change
 > the existing code to be safe (if this is possible at all).

Nobody will ever acquire enough knowledge to do that.

 >> We could convert 'pop-to-buffer' calls to 'display-buffer' calls with
 >> a 'force-select-window' t alist entry.  Users could override that with
 >> a 'force-select-window' nil entry.  This would be the contrapositive
 >> of the 'inhibit-select-window' approach.
 >
 > Does this have the same problem of not making the displayed buffer
 > current?

The task would remain the same: Inspect all 'pop-to-buffer' calls,
possibly their callers and decide whether converting them is safe.

In the 'vc-diff' case the following stretch already looks hairy:

       ;; Display the buffer, but at the end because it can change point.
       (pop-to-buffer (current-buffer))
       ;; The diff process may finish early, so call `vc-diff-finish'
       ;; after `pop-to-buffer'; the former assumes the diff buffer is
       ;; shown in some window.
       (let ((buf (current-buffer)))
         (vc-run-delayed (vc-diff-finish buf (when verbose messages))))

I suppose the 'buf' binding is superfluous because 'pop-to-buffer'
cannot "pop away" from the current buffer even if a user inhibits
selecting the window chosen.  But if that binding had a real purpose,
then using 'inhibit-select-window' would probably affect it and
'vc-diff-finish' would work on the wrong buffer.

Worse even.  The brutal 'set-buffer' call in 'vc-diff' (right before
entering 'diff-mode') already suggests that eventually selecting the
diffs window becomes unavoidable.  Otherwise, returning from 'vc-diff'
would leave you with the diffs buffer current and a window not showing
the diffs buffer selected - a very unpleasing configuration.

Replacing the 'set-buffer' with 'with-current-buffer' is not devoid of
its problems either: You cannot reliably nest a 'display-buffer' call
in 'with-current-buffer' because 'display-buffer' might select a
window on another frame at any time.

martin