Subject: Re: bug#67993: Selecting buffer automatically

From: Juri Linkov <[email-masked]>
Date: Tue, 09 Jan 2024 19:20:13 +0200

>>> In 'display-buffer' first save the selected window as
>>> old-selected-window, display the buffer and in your code select
>>> old-selected-window instead of (old-selected-window).
>>
>> Unfortunately, this is not so easy to do.  'old-selected-window'
>> should be reinitialized before the next command is executed.
>
> Why?  As I imagine it, it would be let-bound in 'display-buffer'.

Ah, indeed, this is even better.  This shows differences
from the previous patch:

diff --git a/lisp/window.el b/lisp/window.el
index 5c3e68f04eb..f34b6d625c6 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7859,13 +7859,14 @@ display-buffer
         (setq window (funcall (car functions) buffer alist)
               functions (cdr functions)))
       (when-let ((select-window (assq 'select-window alist)))
-        (letrec ((postfun
+        (letrec ((old-selected-window (selected-window))
+                 (postfun
                   (lambda ()
                     (if (cdr select-window)
                         (when (window-live-p window)
                           (select-window window))
-                      (when (window-live-p (old-selected-window))
-                        (select-window (old-selected-window))))
+                      (when (window-live-p old-selected-window)
+                        (select-window old-selected-window)))
                     (remove-hook 'post-command-hook postfun))))
           (add-hook 'post-command-hook postfun)))
       (and (windowp window) window))))

>> So by definition 'old-selected-window' should contain
>> the window that was selected before the current command
>> was executed.  I have no idea how to do this without hooks.
>
> Hmmm... I have problems to see what the "current command" is.  One and
> the same command may contain multiple invocations of 'display-buffer'.
> I thought you wanted a 'select-window' entry to be handled separately by
> each of them.  Otherwise, IIUC the entry provided by the last invocation
> would prevail any entries provided by previous invocations.  How would
> you explain that to a user?
>
> If you want 'old-selected-window' to denote "some" state before the
> "current command", the function 'old-selected-window' might be a better
> choice than a variable you bind in 'display-buffer' (but note that
> redisplay may occur in the middle of executing a command).

I guess the variable above should be fine.

> But if you want to interpret "current command" more strictly, you need a
> separate variable, say 'pre-command-selected-window' that you always set
> in 'pre-command-hook' and consult (and maybe reset) in
> 'post-command-hook'.

This would be more troublesome.

>> 'pop-to-buffer' can't be changed because (select-window . t)
>> should be handled only at the end of the current command.
>
> Are your sure that you do not somewhat arbitrarily restrict the scope of
> this feature?  What if (select-window . t) were to be handled in a call
> from within a timer?  Would you ignore it?

It would be a good design to ignore (select-window . t) from a hook.
When windows pop up at random time while user is typing, this is
too dangerous to allow.  I remember such annoying popups as e.g.
with a button "[D]elete" with the shortcut "D" while
you are typing a text that contains "D" ;-)

>> So this also need to run 'select-frame' in post-command-hook.
>
> 'select-frame-set-input-focus' maybe.  Or, what's worse, undo the
> consequences of a preceding 'select-frame-set-input-focus' call
> triggered by 'pop-to-buffer'.

Ok, I will try to save and restore 'old-selected-frame' as well.

> That's why any such 'select-window' call (or its avoidance) you
> propose would be better handled within 'display-buffer' and not later
> in a 'post-command-hook'.

No way to call 'select-window' immediately, because this will
break too many functions that expect a window to be selected
from the previous call of pop-to-buffer until the command
is finished.