Subject: bug#62833: 30.0.50; ERC 5.6: Rethink buffer-display options and behavior

From: "J.P." <[email-masked]>
Date: Thu, 22 Jun 2023 06:48:40 -0700

v3 (Custom function choice). Change interface of function choice in
Custom `:type' spec to support full `display-buffer' action parameter.
Cancel second patch focusing on frames-related display styles (work to
continue in a separate bug).

"J.P." <[email-masked]> writes:

> I've simplified this further. Instead of a cons of a `display-buffer'-
> compatible function and action, I think it's simpler to expect a
> function that takes as arguments the new buffer and a "context alist"
> (that can double as an "action alist"). This way, the user's code can
> inspect the context, assemble the action parameter appropriately, and
> dispatch `display-buffer' or similar as needed.

I've flip-flopped on this completely and have reverted back to favoring
the idea of having user implementations (and `function-item' offerings)
expect a full `display-buffer' action rather than just the alist portion
alone. As explained up thread, I originally figured it'd be easier on
users if we gave them just the alist to ponder rather than something
requiring destructuring and recomposing. But now I think it's cleaner to
sacrifice that minor convenience in favor of having folks mentally
associate these functions with `display-buffer', `pop-to-buffer', etc.,
since they roughly serve the same purpose (as opposed to the "action
functions" they consume).

Along with this U-turn, I think we ought to consider exporting the new
variable `erc--display-context'. I've left it internal, for now, but
making it public would allow folks with an existing collection of
`display-buffer' actions to write simple match predicates (for
`display-buffer-alist') that decide things based on calling context.

> I've also added some ready-made function items, though possibly only
> as placeholders.

Actually, looking back on

  bug#55540: 29.0.50; ERC launches autojoin-channels in current frame

which led to a change that's been on HEAD for two months now

  https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=0e4c07dc

I've come to the belated realization that this feature is not all that
useful in and of itself. For whatever reason, I fixated on fulfilling
the requirements described in the bug without questioning whether that
alone would result in a satisfactory user experience. Indeed, after
actually trying out the feature from the perspective of someone wanting
to conduct all ERC-related business in a separate frame, merely offering
a display style oriented toward that end seems wholly insufficient.

For example, buffers spawned in other contexts, via related options,
such as `erc-receive-query-display', won't find their way to the correct
frame unless they've also been customized accordingly. Similarly, once a
buffer is correctly routed to a "dedicated" frame, it's unclear how the
user wants it displayed. I suppose we could affix existing options as
combined choices, like

  `erc-use-existing-frame-buffer'
  `erc-use-existing-frame-window'
  `erc-use-existing-frame-window-no-select'
  `erc-create-new-frame-buffer'
  ...

but that adds a lot of clutter and isn't great for maintenance. There's
also the issue of integrating with other modules, like `erc-track',
whose users likely want the mode line to only show changes for
associated buffers and C-SPC to limit its switching between those.

In sum, I think the basic idea of being able to marry new ERC buffers to
an ERC-managed frame is a good one, but it may be orthogonal to our
traditional idea of display styles. I'm now leaning toward exploring
something like a separate module to make the experience feel more
integrated and less bolted on. I therefore move that we revert the
change cited above in the meantime so people don't get used to it, and
then pursue a more comprehensive solution to frame-oriented
buffer-display styles in this (or some related) bug. Thanks.

>From 78bba39e65b168a117c077518f2aee2a8465e470 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Wed, 21 Jun 2023 06:36:45 -0700
Subject: [PATCH 0/2] *** NOT A PATCH ***

*** BLURB HERE ***

F. Jason Park (2):
  Revert "Allow erc-reuse-frames to favor connections"
  [5.6] Allow custom display-buffer actions in ERC

 etc/ERC-NEWS               |  20 +-
 lisp/erc/erc-backend.el    |   9 +-
 lisp/erc/erc.el            | 217 ++++++++++++---------
 test/lisp/erc/erc-tests.el | 376 +++++++------------------------------
 4 files changed, 212 insertions(+), 410 deletions(-)

Interdiff:
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 6cec2919460..9177f61f8cc 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -58,8 +58,8 @@ option (now known as 'erc-receive-query-display') is nil, ERC uses
 'erc-interactive-display'.  The old nil behavior can still be gotten
 via the new compatibility flag 'erc-receive-query-display-defer'.
 
-A few subtleties affecting the display of new or reassociated buffers
-have also been introduced.  One involves buffers that already occupy
+This release also introduces a few subtleties affecting the display of
+new or reassociated buffers.  One involves buffers that already occupy
 the selected window.  ERC now treats these as deserving of an implicit
 'bury'.  An escape hatch for this and most other baked-in behaviors is
 now available in the form of a new type variant recognized by all such
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index a0e89795a57..f1dafd0dbf8 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1555,10 +1555,10 @@ erc--buffer-display-choices
            (const :tag "New frame" frame)
            (const :tag "Don't display" bury)
            (const :tag "Use current window" buffer)
-           (choice :tag "Show in granular, context-aware manner"
-                   (function-item erc-display-buffer-in-existing-frame)
-                   (function-item erc-display-buffer-ensuring-frame)
-                   (function :tag "User-provided function")))
+           (choice :tag "Defer to a display function"
+                   (function-item display-buffer)
+                   (function-item pop-to-buffer)
+                   (function :tag "User-defined")))
   "Common choices for buffer-display options.")
 
 (defvaralias 'erc-join-buffer 'erc-buffer-display)
@@ -1576,24 +1576,23 @@ erc-buffer-display
   `frame'           - in another frame,
   `bury'            - bury it in a new buffer,
   `buffer'          - in place of the current buffer,
-  DISPLAY-FUNCTION  - called with a buffer and an ACTION-ALIST
+  DISPLAY-FUNCTION  - a `display-buffer'-like function
 
-Here, DISPLAY-FUNCTION should accept a buffer and an ACTION-ALIST
-of the kind described by the Info node `(elisp) Buffer Display
-Action Alists'.  Note that unlike a full display \"action\", this
-lacks a function (or list of functions) at its head.  At times,
-ERC may add hints about the calling context to this alist.  Keys
-are symbols of options themselves, like `erc-buffer-display'.
-Values are chosen from a set of predefined constants.  In the
-case of this option specifically, ERC uses the symbols
+Here, DISPLAY-FUNCTION should accept a buffer and an ACTION of
+the kind described by the Info node `(elisp) Choosing Window'.
+At times, ERC may add hints about the calling context to the
+ACTION's alist.  Keys are symbols of user options, like
+`erc-buffer-display', and values are predefined constants
+specific to each.  For this particular option, possible values
+include the symbols
 
   `JOIN', `PRIVMSG', `NOTICE', `erc', and `erc-tls'.
 
 The first three signify IRC commands received from the server and
 the rest entry-point commands responsible for the connection.
-When dealing with the latter, users may prefer to call
-DISPLAY-FUNCTION directly on a returned buffer (in this case,
-server buffer) because the context leading to its creation is
+When dealing with the latter two, users may prefer to call
+DISPLAY-FUNCTION directly on (server) buffers returned by these
+entry points because the context leading to their creation is
 plainly obvious.
 
 Note that when the selected window already shows the current
@@ -1614,9 +1613,9 @@ erc-interactive-display
 values.
 
 When the value is a user-provided function, ERC may inject a hint
-about the invocation context as an extra item in the alist passed
-as the second argument.  The hint item's key is the symbol
-`erc-interactive-display' and its value one of
+about the invocation context as an extra item in the \"action
+alist\" included as part of the second argument.  The item's key
+is the symbol `erc-interactive-display' and its value one of
 
   `/QUERY', `/JOIN', `url', `erc', or `erc-tls'.
 
@@ -1635,9 +1634,9 @@ erc-reconnect-display
 `erc-buffer-display' for a description of possible values.
 
 When the value is function, ERC may inject a hint about the
-calling context as an extra item in the second, \"action alist\"
-argument.  The item's key is the symbol `erc-reconnect-display'
-and its value something non-nil."
+calling context as an extra item in the alist making up the tail
+of the second, \"action\" argument.  The item's key is the symbol
+`erc-reconnect-display' and its value something non-nil."
   :package-version '(ERC . "5.5")
   :group 'erc-buffers
   :type erc--buffer-display-choices)
@@ -1666,13 +1665,13 @@ erc-frame-dedicated-flag
 (defcustom erc-reuse-frames t
   "Determines whether new frames are always created.
 Non-nil means only create a frame for undisplayed buffers.  Nil
-means always create a new frame.  Regardless of its value, this
-option is ignored unless `erc-join-buffer' is set to `frame'.
-And like most options in the `erc-buffer' customize group, this
-has no effect on server buffers while reconnecting because those
-are always buried."
+means always create a new frame.  Regardless of its value, ERC
+ignores this option unless `erc-join-buffer' is `frame'.  And
+like most options in the `erc-buffer' customize group, this has
+no effect on server buffers while reconnecting because ERC always
+buries those."
   :group 'erc-buffers
-  :type '(choice boolean))
+  :type 'boolean)
 
 (defun erc-channel-p (channel)
   "Return non-nil if CHANNEL seems to be an IRC channel name."
@@ -2125,74 +2124,6 @@ erc--updating-modules-p
 confidently call (erc-foo-mode 1) without having to learn
 anything about the dependency's implementation.")
 
-(defun erc--setup-buffer-first-window (frame a b)
-  (catch 'found
-    (walk-window-tree
-     (lambda (w)
-       (when (cond ((functionp a) (with-current-buffer (window-buffer w)
-                                    (funcall a b)))
-                   (t (eq (buffer-local-value a (window-buffer w)) b)))
-         (throw 'found t)))
-     frame nil 0)))
-
-(defun erc--display-buffer-use-some-frame (buffer alist)
-  "Maybe display BUFFER in an existing frame for the same connection.
-If performed, return winning window; otherwise, return nil.
-Forward ALIST to `display-buffer' machinery."
-  (let* ((idp (lambda (value)
-                (and erc-networks--id
-                     (erc-networks--id-equal-p erc-networks--id value))))
-         (procp (lambda (frame)
-                  (erc--setup-buffer-first-window frame idp erc-networks--id)))
-         (anyp (assq 'erc--frame-any alist))
-         (ercp (lambda (frame)
-                 (let ((val (erc--setup-buffer-first-window frame 'major-mode
-                                                            'erc-mode)))
-                   (if anyp val (not val)))))
-         new)
-    (when (or (cdr (frame-list))
-              (funcall ercp (selected-frame))
-              (and (not anyp)
-                   (push `(pop-up-frame-parameters ,erc-frame-alist) alist)
-                   (setq new t)))
-      (or (and new (display-buffer-pop-up-frame buffer alist))
-          ;; Workaround to avoid calling `window--display-buffer' directly.
-          (display-buffer-use-some-frame buffer `((frame-predicate . ,procp)
-                                                  ,@alist))
-          (display-buffer-use-some-frame buffer `((frame-predicate . ,ercp)
-                                                  ,@alist))))))
-
-(defun erc-display-buffer-in-existing-frame (buffer alist)
-  "Display BUFFER in an existing frame with others from ERC.
-Use any existing, potentially hidden frame already displaying a
-buffer from the same network context or, failing that, a frame
-showing any ERC buffer.  As a last resort, use the selected
-frame, except for brand new connections, which always get the
-invoking frame.  Pass ALIST along to `display-buffer'."
-  (unless (get-buffer-window buffer t)
-    (display-buffer buffer `((erc--display-buffer-use-some-frame)
-                             (erc--frame-any . t)
-                             (inhibit-switch-frame . t)
-                             (inhibit-same-window . t)
-                             ,@alist))))
-
-(defun erc-display-buffer-ensuring-frame (buffer alist)
-  "Display BUFFER in a frame with others from its connection.
-Use any frame already displaying a buffer from the same network
-context.  Failing that, create one unless some existing frame is
-free of any ERC buffers, in which case, use that.  Pass ALIST
-along to `display-buffer'.
-
-WARNING: if a frame for the existing connection does not exist,
-this function may raise a new one and steal focus."
-  (unless (get-buffer-window buffer t)
-    (let ((interactivep (alist-get 'erc-interactive-display alist)))
-      (display-buffer buffer `((erc--display-buffer-use-some-frame)
-                               ,@(and (not interactivep)
-                                      '((inhibit-same-window . t)))
-                               (inhibit-switch-frame . t)
-                               ,@alist)))))
-
 (defvar erc--setup-buffer-hook nil
   "Internal hook for module setup involving windows and frames.")
 
@@ -2210,6 +2141,11 @@ erc-skip-displaying-selected-window-buffer
 (make-obsolete 'erc-show-already-displayed-buffer
                "non-nil behavior to be made permanent" "30.1")
 
+(defvar-local erc--display-buffer-action nil
+  "The value of `display-buffer-overriding-action' when non-nil.
+Influences the displaying of new or reassociated ERC buffers.
+Reserved for use by built-in modules.")
+
 (defun erc-setup-buffer (buffer)
   "Consults `erc-join-buffer' to find out how to display `BUFFER'."
   (pcase (if (zerop (erc-with-server-buffer
@@ -2219,7 +2155,7 @@ erc-setup-buffer
     ((and (pred functionp) disp-fn (let context erc--display-context))
      (unless (zerop erc--server-last-reconnect-count)
        (push '(erc-reconnect-display . t) context))
-     (funcall disp-fn buffer context))
+     (funcall disp-fn buffer (cons nil context)))
     ((guard (and erc-skip-displaying-selected-window-buffer
                  (eq (window-buffer) buffer))))
     ('window
@@ -2419,8 +2355,10 @@ erc-open
         ;; we can't log to debug buffer, it may not exist yet
         (message "erc: old buffer %s, switching to %s"
                  old-buffer buffer))
-      (erc-setup-buffer buffer)
-      (run-hooks 'erc--setup-buffer-hook))
+      (let ((display-buffer-overriding-action
+             (or erc--display-buffer-action display-buffer-overriding-action)))
+        (erc-setup-buffer buffer)
+        (run-hooks 'erc--setup-buffer-hook)))
 
     buffer))
 
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 6e45a9731ed..6dbd0d4704f 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -503,309 +503,6 @@ erc--switch-to-buffer
     (dolist (b '("server" "other" "#chan" "#foo" "#fake"))
       (kill-buffer b))))
 
-(defun erc-tests--run-in-term (&optional debug)
-  (let* ((default-directory (getenv "EMACS_TEST_DIRECTORY"))
-         (emacs (expand-file-name invocation-name invocation-directory))
-         (process-environment (cons "ERC_TESTS_SUBPROCESS=1"
-                                    process-environment))
-         (name (ert-test-name (ert-running-test)))
-         (temp-file (make-temp-file "erc-term-test-"))
-         (cmd `(let ((stats 1))
-                 (setq enable-dir-local-variables nil)
-                 (unwind-protect
-                     (setq stats (ert-run-tests-batch ',name))
-                   (unless ',debug
-                     (let ((buf (with-current-buffer (messages-buffer)
-                                  (buffer-string))))
-                       (with-temp-file ,temp-file
-                         (insert buf)))
-                     (kill-emacs (ert-stats-completed-unexpected stats))))))
-         ;; `ert-test' object in Emacs 29 has a `file-name' field
-         (file-name (symbol-file name 'ert--test))
-         (default-directory (expand-file-name (file-name-directory file-name)))
-         (package (if-let* ((found (getenv "ERC_PACKAGE_NAME"))
-                            ((string-prefix-p "erc-" found)))
-                      (intern found)
-                    'erc))
-         (setup (and (featurep 'compat)
-                     `(progn
-                        (require 'package)
-                        (let ((package-load-list '((compat t) (,package t))))
-                          (package-initialize)))))
-         ;; Make subprocess terminal bigger than controlling.
-         (buf (cl-letf (((symbol-function 'window-screen-lines)
-                         (lambda () 20))
-                        ((symbol-function 'window-max-chars-per-line)
-                         (lambda () 40)))
-                (make-term (symbol-name name) emacs nil "-Q" "-nw"
-                           "-eval" (prin1-to-string setup)
-                           "-l" file-name "-eval" (format "%S" cmd))))
-         (proc (get-buffer-process buf))
-         (err (lambda ()
-                (with-temp-buffer
-                  (insert-file-contents temp-file)
-                  (message "Subprocess: %s" (buffer-string))
-                  (delete-file temp-file)))))
-    (with-current-buffer buf
-      (set-process-query-on-exit-flag proc nil)
-      (with-timeout (10 (funcall err) (error "Timed out awaiting result"))
-        (while (process-live-p proc)
-          (accept-process-output proc 0.1)))
-      (while (accept-process-output proc))
-      (goto-char (point-min))
-      ;; Otherwise gives process exited abnormally with exit-code >0
-      (unless (search-forward (format "Process %s finished" name) nil t)
-        (funcall err)
-        (ert-fail (when (search-forward "exited" nil t)
-                    (buffer-substring-no-properties (line-beginning-position)
-                                                    (line-end-position)))))
-      (delete-file temp-file)
-      (when noninteractive
-        (kill-buffer)))))
-
-(defun erc-tests--servars (source &rest vars)
-  (unless (bufferp source)
-    (setq source (get-buffer source)))
-  (dolist (var vars)
-    (should (local-variable-if-set-p var))
-    (set var (buffer-local-value var source))))
-
-(defun erc-tests--erc-reuse-frames (test &optional debug)
-  (if (and (or debug noninteractive) (not (getenv "ERC_TESTS_SUBPROCESS")))
-      (progn
-        (when (memq system-type '(windows-nt ms-dos))
-          (ert-skip "System must be UNIX"))
-        (erc-tests--run-in-term debug))
-    (should-not erc-frame-dedicated-flag)
-    (should (eq erc-reuse-frames t))
-    (let ((erc-join-buffer 'frame)
-          (erc-reuse-frames t)
-          (erc-frame-alist nil)
-          (orig-frame (selected-frame))
-          erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
-      (delete-other-frames)
-      (delete-other-windows)
-      (set-window-buffer (selected-window) "*scratch*")
-      (funcall test orig-frame)
-      (delete-other-frames orig-frame)
-      (delete-other-windows))))
-
-;; TODO add cases for frame-display behavior while reconnecting
-
-(defun erc-tests--erc-reuse-frames--t (_)
-  (ert-info ("New server buffer creates and raises second frame")
-    (with-current-buffer (generate-new-buffer "server")
-      (erc-mode)
-      (setq erc-server-process (start-process "server"
-                                              (current-buffer) "sleep" "10")
-            erc-frame-alist (cons '(name . "server") default-frame-alist)
-            erc-network 'foonet
-            erc-networks--id (erc-networks--id-create nil)
-            erc--server-last-reconnect-count 0)
-      (set-process-buffer erc-server-process (current-buffer))
-      (set-process-query-on-exit-flag erc-server-process nil)
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should (equal "server" (frame-parameter (window-frame) 'name)))
-      (should (get-buffer-window (current-buffer) t))))
-
-  (ert-info ("New channel creates and raises third frame")
-    (with-current-buffer (generate-new-buffer "#chan")
-      (erc-mode)
-      (erc-tests--servars "server" 'erc-server-process 'erc-networks--id
-                          'erc-network)
-      (setq erc-frame-alist (cons '(name . "#chan") default-frame-alist)
-            erc-default-recipients '("#chan"))
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should (equal "#chan" (frame-parameter (window-frame) 'name)))
-      (should (get-buffer-window (current-buffer) t))
-      (should (cddr (frame-list))))))
-
-(ert-deftest erc-reuse-frames--t ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (erc-tests--erc-reuse-frames--t orig-frame)
-     (dolist (b '("server" "#chan"))
-       (kill-buffer b)))))
-
-(defun erc-tests--erc-reuse-frames--displayed-single (_ server-name chan-name)
-
-  (should (eq erc-buffer-display #'erc-display-buffer-in-existing-frame))
-
-  (ert-info ("New server buffer shown in existing frame")
-    (with-current-buffer (generate-new-buffer server-name)
-      (erc-mode)
-      (setq erc-server-process (start-process server-name (current-buffer)
-                                              "sleep" "10")
-            erc-frame-alist (cons `(name . ,server-name) default-frame-alist)
-            erc-network (make-symbol server-name)
-            erc-server-current-nick "tester"
-            erc-networks--id (erc-networks--id-create nil)
-            erc--server-last-reconnect-count 0)
-      (set-process-buffer erc-server-process (current-buffer))
-      (set-process-query-on-exit-flag erc-server-process nil)
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should-not (equal server-name (frame-parameter (window-frame) 'name)))
-      ;; New server buffer window appears in split below ERT/scratch
-      (should (get-buffer-window (current-buffer) t))))
-
-  (ert-info ("New channel shown in existing frame")
-    (with-current-buffer (generate-new-buffer chan-name)
-      (erc-mode)
-      (erc-tests--servars server-name 'erc-server-process 'erc-networks--id
-                          'erc-network)
-      (setq erc-frame-alist (cons `(name . ,chan-name) default-frame-alist)
-            erc-default-recipients (list chan-name))
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should-not (equal chan-name (frame-parameter (window-frame) 'name)))
-      ;; New channel buffer replaces server in lower window
-      (should (get-buffer-window (current-buffer) t))
-      (should-not (get-buffer-window server-name t)))))
-
-(ert-deftest erc-reuse-frames--displayed-single ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (let ((erc-buffer-display #'erc-display-buffer-in-existing-frame))
-       (erc-tests--erc-reuse-frames--displayed-single orig-frame
-                                                      "server" "#chan")
-       (should-not (cdr (frame-list))))
-     (dolist (b '("server" "#chan"))
-       (kill-buffer b)))))
-
-(defun erc-tests--assert-server-split (buffer-or-name frame-name)
-  ;; Assert current buffer resides on one side of a horizontal split
-  ;; in the "server" frame but is not selected.
-  (let* ((buffer-window (get-buffer-window buffer-or-name t))
-         (buffer-frame (window-frame buffer-window)))
-    (should (equal frame-name (frame-parameter buffer-frame 'name)))
-    (should (memq buffer-window (car-safe (window-tree buffer-frame))))
-    (should-not (eq buffer-window (frame-selected-window)))
-    buffer-frame))
-
-(defun erc-tests--erc-reuse-frames--displayed-double (_)
-  (should (eq erc-buffer-display #'erc-display-buffer-in-existing-frame))
-
-  (make-frame '((name . "other")))
-  (select-frame (make-frame '((name . "server"))) 'no-record)
-  (set-window-buffer (selected-window) "*scratch*") ; invokes `erc'
-
-  ;; A user invokes an entry point and switches immediately to a new
-  ;; frame before autojoin kicks in (bug#55540).
-
-  (ert-info ("New server buffer shown in selected frame")
-    (with-current-buffer (generate-new-buffer "server")
-      (erc-mode)
-      (setq erc-server-process (start-process "server" (current-buffer)
-                                              "sleep" "10")
-            erc-network 'foonet
-            erc-server-current-nick "tester"
-            erc-networks--id (erc-networks--id-create nil)
-            erc--server-last-reconnect-count 0)
-      (set-process-buffer erc-server-process (current-buffer))
-      (set-process-query-on-exit-flag erc-server-process nil)
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should (equal "server" (frame-parameter (window-frame) 'name)))
-      (should (get-buffer-window (current-buffer) t))))
-
-  (select-frame-by-name "other")
-
-  (ert-info ("New channel shown in dedicated frame")
-    (with-current-buffer (generate-new-buffer "#chan")
-      (erc-mode)
-      (erc-tests--servars "server" 'erc-server-process 'erc-networks--id
-                          'erc-network)
-      (setq erc-frame-alist (cons '(name . "#chan") default-frame-alist)
-            erc-default-recipients '("#chan"))
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (erc-tests--assert-server-split (current-buffer) "server")
-      ;; New channel buffer replaces server in lower window of other frame
-      (should-not (get-buffer-window "server" t)))))
-
-(ert-deftest erc-reuse-frames--displayed-double ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (let ((erc-buffer-display #'erc-display-buffer-in-existing-frame))
-       (erc-tests--erc-reuse-frames--displayed-double orig-frame))
-     (dolist (b '("server" "#chan"))
-       (kill-buffer b)))))
-
-;; If a frame showing ERC buffers exists among other frames, new,
-;; additional connections will use the existing IRC frame.  However,
-;; if two or more frames exist with ERC buffers unique to a particular
-;; connection, the correct frame will be found.
-
-(defun erc-tests--erc-reuse-frames--displayed-full (orig-frame)
-  (erc-tests--erc-reuse-frames--displayed-double orig-frame)
-  ;; Server buffer is not displayed because #chan has replaced it in
-  ;; the "server" frame, which is not selected.
-  (should (equal "other" (frame-parameter (window-frame) 'name)))
-  (erc-tests--erc-reuse-frames--displayed-single orig-frame "ircd" "#spam")
-  (should (equal "other" (frame-parameter (window-frame) 'name)))
-
-  ;; Buffer "#spam" has replaced "ircd", which earlier replaced
-  ;; "#chan" in frame "server".  But this is confusing, so...
-  (ert-info ("Arrange windows for second connection in other frame")
-    (set-window-buffer (selected-window) "ircd")
-    (split-window-below)
-    (set-window-buffer (next-window) "#spam")
-    (should (equal (cddar (window-tree))
-                   (list (get-buffer-window "ircd" t)
-                         (get-buffer-window "#spam" t)))))
-
-  (ert-info ("Arrange windows for first connection in server frame")
-    (select-frame-by-name "server")
-    (set-window-buffer (selected-window) "server")
-    (set-window-buffer (next-window) "#chan")
-    (should (equal (cddar (window-tree))
-                   (list (get-buffer-window "server" t)
-                         (get-buffer-window "#chan" t)))))
-
-  ;; Select original ERT frame
-  (ert-info ("New target for connection server finds appropriate frame")
-    (select-frame orig-frame 'no-record)
-    (with-current-buffer (window-buffer (selected-window))
-      (should (member (buffer-name) '("*ert*" "*scratch*")))
-      (with-current-buffer (generate-new-buffer "alice")
-        (erc-mode)
-        (erc-tests--servars "server" 'erc-server-process 'erc-networks--id)
-        (setq erc-default-recipients '("alice"))
-        (should-not (get-buffer-window (current-buffer) t))
-        (erc-setup-buffer (current-buffer))
-        ;; Window created in frame "server"
-        (should (eq (selected-frame) orig-frame))
-        (erc-tests--assert-server-split (current-buffer) "server"))))
-
-  (ert-info ("New target for connection ircd finds appropriate frame")
-    (select-frame orig-frame 'no-record)
-    (with-current-buffer (window-buffer (selected-window))
-      (should (member (buffer-name) '("*ert*" "*scratch*")))
-      (with-current-buffer (generate-new-buffer "bob")
-        (erc-mode)
-        (erc-tests--servars "ircd" 'erc-server-process 'erc-networks--id)
-        (setq erc-default-recipients '("bob"))
-        (should-not (get-buffer-window (current-buffer) t))
-        (erc-setup-buffer (current-buffer))
-        ;; Window created in frame "other"
-        (should (eq (selected-frame) orig-frame))
-        (erc-tests--assert-server-split (current-buffer) "other")))))
-
-(ert-deftest erc-reuse-frames--displayed-full ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (let ((erc-buffer-display #'erc-display-buffer-in-existing-frame))
-       (erc-tests--erc-reuse-frames--displayed-full orig-frame))
-     (dolist (b '("server" "ircd" "bob" "alice" "#spam" "#chan"))
-       (kill-buffer b)))))
-
 (ert-deftest erc-setup-buffer--custom-action ()
   (erc-mode)
   (erc-tests--set-fake-server-process "sleep" "1")
@@ -832,7 +529,7 @@ erc-setup-buffer--custom-action
       (let ((erc--display-context '((erc-buffer-display . 1)))
             (erc-join-buffer 'erc--test-fun))
         (erc-setup-buffer mbuf)
-        (should (equal `(erc--test-fun ,mbuf ((erc-buffer-display . 1)))
+        (should (equal `(erc--test-fun ,mbuf (nil (erc-buffer-display . 1)))
                        (pop calls)))
         (should-not calls))
 
@@ -841,8 +538,8 @@ erc-setup-buffer--custom-action
              (erc--display-context '((erc-buffer-display . 1)))
              (erc-reconnect-display 'erc--test-fun))
         (erc-setup-buffer mbuf)
-        (should (equal `(erc--test-fun ,mbuf ((erc-reconnect-display . t)
-                                              (erc-buffer-display . 1)))
+        (should (equal `(erc--test-fun ,mbuf (nil (erc-reconnect-display . t)
+                                                  (erc-buffer-display . 1)))
                        (pop calls)))
         (should-not calls)))
 
-- 
2.40.1

>From 17c1c7b9c3e2c1708e300638ec351bbdfc1776f5 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Mon, 19 Jun 2023 23:14:40 -0700
Subject: [PATCH 1/2] Revert "Allow erc-reuse-frames to favor connections"

This (mostly) reverts commit 0e4c07dc7448aafd2aa5f6e101d7b7aac23d8a6b.

* etc/ERC-NEWS: Also revert hunk from 52c8d537 "* etc/ERC-NEWS: Add
section for ERC 5.6." because it announced this feature, which no
longer exists.
* lisp/erc/erc.el (erc-reuse-frames): Revise doc string instead of
reverting completely.  (Bug#62833)
---
 etc/ERC-NEWS               |   8 -
 lisp/erc/erc.el            |  64 ++------
 test/lisp/erc/erc-tests.el | 303 -------------------------------------
 3 files changed, 10 insertions(+), 365 deletions(-)

diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 68f1083621c..68cf0e2d6ca 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -82,14 +82,6 @@ connectivity before attempting to reconnect in earnest.  See options
 'erc-server-reconnect-function' and 'erc-nickname-in-use-functions' to
 get started.
 
-** Easily constrain all ERC-related business to a dedicated frame.
-The option 'erc-reuse-frames' can now be set to 'displayed', which
-tells ERC to show new buffers in frames already occupied by buffers
-from the same connection.  This customization depends on the option
-'erc-buffer-display' (formerly 'erc-join-buffer') being set to
-'frame'.  If you find the name 'displayed' unhelpful, please suggest
-an alternative by writing to the mailing list.
-
 ** Module 'fill' can add a bit of space between messages.
 On graphical displays, it's now possible to add some breathing room
 around certain messages via the new option 'erc-fill-line-spacing'.
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index a1538962602..70adbb15b5f 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1626,23 +1626,14 @@ erc-frame-dedicated-flag
 
 (defcustom erc-reuse-frames t
   "Determines whether new frames are always created.
-
-A value of t means only create a frame for undisplayed buffers.
-`displayed' means use any existing, potentially hidden frame
-already displaying a buffer from the same network context or,
-failing that, a frame showing any ERC buffer.  As a last resort,
-`displayed' defaults to the selected frame, except for brand new
-connections, for which the invoking frame is always used.  When
-this option is nil, a new frame is always created.
-
-Regardless of its value, this option is ignored unless
-`erc-join-buffer' is set to `frame'.  And like most options in
-the `erc-buffer' customize group, this has no effect on server
-buffers while reconnecting because those are always buried."
-  :package-version '(ERC . "5.6") ; FIXME sync on release
+Non-nil means only create a frame for undisplayed buffers.  Nil
+means always create a new frame.  Regardless of its value, ERC
+ignores this option unless `erc-join-buffer' is `frame'.  And
+like most options in the `erc-buffer' customize group, this has
+no effect on server buffers while reconnecting because ERC always
+buries those."
   :group 'erc-buffers
-  :type '(choice boolean
-                 (const displayed)))
+  :type 'boolean)
 
 (defun erc-channel-p (channel)
   "Return non-nil if CHANNEL seems to be an IRC channel name."
@@ -2095,35 +2086,6 @@ erc--updating-modules-p
 confidently call (erc-foo-mode 1) without having to learn
 anything about the dependency's implementation.")
 
-(defun erc--setup-buffer-first-window (frame a b)
-  (catch 'found
-    (walk-window-tree
-     (lambda (w)
-       (when (cond ((functionp a) (with-current-buffer (window-buffer w)
-                                    (funcall a b)))
-                   (t (eq (buffer-local-value a (window-buffer w)) b)))
-         (throw 'found t)))
-     frame nil 0)))
-
-(defun erc--display-buffer-use-some-frame (buffer alist)
-  "Maybe display BUFFER in an existing frame for the same connection.
-If performed, return window used; otherwise, return nil.  Forward ALIST
-to display-buffer machinery."
-  (when-let*
-      ((idp (lambda (value)
-              (and erc-networks--id
-                   (erc-networks--id-equal-p erc-networks--id value))))
-       (procp (lambda (frame)
-                (erc--setup-buffer-first-window frame idp erc-networks--id)))
-       (ercp (lambda (frame)
-               (erc--setup-buffer-first-window frame 'major-mode 'erc-mode)))
-       ((or (cdr (frame-list)) (funcall ercp (selected-frame)))))
-    ;; Workaround to avoid calling `window--display-buffer' directly
-    (or (display-buffer-use-some-frame buffer
-                                       `((frame-predicate . ,procp) ,@alist))
-        (display-buffer-use-some-frame buffer
-                                       `((frame-predicate . ,ercp) ,@alist)))))
-
 (defvar erc--setup-buffer-hook nil
   "Internal hook for module setup involving windows and frames.")
 
@@ -2142,21 +2104,15 @@ erc-setup-buffer
     ('bury
      nil)
     ('frame
-     (cond
-      ((and (eq erc-reuse-frames 'displayed)
-            (not (get-buffer-window buffer t)))
-       (display-buffer buffer '((erc--display-buffer-use-some-frame)
-                                (inhibit-switch-frame . t)
-                                (inhibit-same-window . t))))
-      ((or (not erc-reuse-frames)
-           (not (get-buffer-window buffer t)))
+     (when (or (not erc-reuse-frames)
+               (not (get-buffer-window buffer t)))
        (let ((frame (make-frame (or erc-frame-alist
                                     default-frame-alist))))
          (raise-frame frame)
          (select-frame frame))
        (switch-to-buffer buffer)
        (when erc-frame-dedicated-flag
-         (set-window-dedicated-p (selected-window) t)))))
+         (set-window-dedicated-p (selected-window) t))))
     (_
      (if (active-minibuffer-window)
          (display-buffer buffer)
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index f3489a16386..b751ef50520 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -503,309 +503,6 @@ erc--switch-to-buffer
     (dolist (b '("server" "other" "#chan" "#foo" "#fake"))
       (kill-buffer b))))
 
-(defun erc-tests--run-in-term (&optional debug)
-  (let* ((default-directory (getenv "EMACS_TEST_DIRECTORY"))
-         (emacs (expand-file-name invocation-name invocation-directory))
-         (process-environment (cons "ERC_TESTS_SUBPROCESS=1"
-                                    process-environment))
-         (name (ert-test-name (ert-running-test)))
-         (temp-file (make-temp-file "erc-term-test-"))
-         (cmd `(let ((stats 1))
-                 (setq enable-dir-local-variables nil)
-                 (unwind-protect
-                     (setq stats (ert-run-tests-batch ',name))
-                   (unless ',debug
-                     (let ((buf (with-current-buffer (messages-buffer)
-                                  (buffer-string))))
-                       (with-temp-file ,temp-file
-                         (insert buf)))
-                     (kill-emacs (ert-stats-completed-unexpected stats))))))
-         ;; `ert-test' object in Emacs 29 has a `file-name' field
-         (file-name (symbol-file name 'ert--test))
-         (default-directory (expand-file-name (file-name-directory file-name)))
-         (package (if-let* ((found (getenv "ERC_PACKAGE_NAME"))
-                            ((string-prefix-p "erc-" found)))
-                      (intern found)
-                    'erc))
-         (setup (and (featurep 'compat)
-                     `(progn
-                        (require 'package)
-                        (let ((package-load-list '((compat t) (,package t))))
-                          (package-initialize)))))
-         ;; Make subprocess terminal bigger than controlling.
-         (buf (cl-letf (((symbol-function 'window-screen-lines)
-                         (lambda () 20))
-                        ((symbol-function 'window-max-chars-per-line)
-                         (lambda () 40)))
-                (make-term (symbol-name name) emacs nil "-Q" "-nw"
-                           "-eval" (prin1-to-string setup)
-                           "-l" file-name "-eval" (format "%S" cmd))))
-         (proc (get-buffer-process buf))
-         (err (lambda ()
-                (with-temp-buffer
-                  (insert-file-contents temp-file)
-                  (message "Subprocess: %s" (buffer-string))
-                  (delete-file temp-file)))))
-    (with-current-buffer buf
-      (set-process-query-on-exit-flag proc nil)
-      (with-timeout (10 (funcall err) (error "Timed out awaiting result"))
-        (while (process-live-p proc)
-          (accept-process-output proc 0.1)))
-      (while (accept-process-output proc))
-      (goto-char (point-min))
-      ;; Otherwise gives process exited abnormally with exit-code >0
-      (unless (search-forward (format "Process %s finished" name) nil t)
-        (funcall err)
-        (ert-fail (when (search-forward "exited" nil t)
-                    (buffer-substring-no-properties (line-beginning-position)
-                                                    (line-end-position)))))
-      (delete-file temp-file)
-      (when noninteractive
-        (kill-buffer)))))
-
-(defun erc-tests--servars (source &rest vars)
-  (unless (bufferp source)
-    (setq source (get-buffer source)))
-  (dolist (var vars)
-    (should (local-variable-if-set-p var))
-    (set var (buffer-local-value var source))))
-
-(defun erc-tests--erc-reuse-frames (test &optional debug)
-  (if (and (or debug noninteractive) (not (getenv "ERC_TESTS_SUBPROCESS")))
-      (progn
-        (when (memq system-type '(windows-nt ms-dos))
-          (ert-skip "System must be UNIX"))
-        (erc-tests--run-in-term debug))
-    (should-not erc-frame-dedicated-flag)
-    (should (eq erc-reuse-frames t))
-    (let ((erc-join-buffer 'frame)
-          (erc-reuse-frames t)
-          (erc-frame-alist nil)
-          (orig-frame (selected-frame))
-          erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
-      (delete-other-frames)
-      (delete-other-windows)
-      (set-window-buffer (selected-window) "*scratch*")
-      (funcall test orig-frame)
-      (delete-other-frames orig-frame)
-      (delete-other-windows))))
-
-;; TODO add cases for frame-display behavior while reconnecting
-
-(defun erc-tests--erc-reuse-frames--t (_)
-  (ert-info ("New server buffer creates and raises second frame")
-    (with-current-buffer (generate-new-buffer "server")
-      (erc-mode)
-      (setq erc-server-process (start-process "server"
-                                              (current-buffer) "sleep" "10")
-            erc-frame-alist (cons '(name . "server") default-frame-alist)
-            erc-network 'foonet
-            erc-networks--id (erc-networks--id-create nil)
-            erc--server-last-reconnect-count 0)
-      (set-process-buffer erc-server-process (current-buffer))
-      (set-process-query-on-exit-flag erc-server-process nil)
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should (equal "server" (frame-parameter (window-frame) 'name)))
-      (should (get-buffer-window (current-buffer) t))))
-
-  (ert-info ("New channel creates and raises third frame")
-    (with-current-buffer (generate-new-buffer "#chan")
-      (erc-mode)
-      (erc-tests--servars "server" 'erc-server-process 'erc-networks--id
-                          'erc-network)
-      (setq erc-frame-alist (cons '(name . "#chan") default-frame-alist)
-            erc-default-recipients '("#chan"))
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should (equal "#chan" (frame-parameter (window-frame) 'name)))
-      (should (get-buffer-window (current-buffer) t))
-      (should (cddr (frame-list))))))
-
-(ert-deftest erc-reuse-frames--t ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (erc-tests--erc-reuse-frames--t orig-frame)
-     (dolist (b '("server" "#chan"))
-       (kill-buffer b)))))
-
-(defun erc-tests--erc-reuse-frames--displayed-single (_ server-name chan-name)
-
-  (should (eq erc-reuse-frames 'displayed))
-
-  (ert-info ("New server buffer shown in existing frame")
-    (with-current-buffer (generate-new-buffer server-name)
-      (erc-mode)
-      (setq erc-server-process (start-process server-name (current-buffer)
-                                              "sleep" "10")
-            erc-frame-alist (cons `(name . ,server-name) default-frame-alist)
-            erc-network (make-symbol server-name)
-            erc-server-current-nick "tester"
-            erc-networks--id (erc-networks--id-create nil)
-            erc--server-last-reconnect-count 0)
-      (set-process-buffer erc-server-process (current-buffer))
-      (set-process-query-on-exit-flag erc-server-process nil)
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should-not (equal server-name (frame-parameter (window-frame) 'name)))
-      ;; New server buffer window appears in split below ERT/scratch
-      (should (get-buffer-window (current-buffer) t))))
-
-  (ert-info ("New channel shown in existing frame")
-    (with-current-buffer (generate-new-buffer chan-name)
-      (erc-mode)
-      (erc-tests--servars server-name 'erc-server-process 'erc-networks--id
-                          'erc-network)
-      (setq erc-frame-alist (cons `(name . ,chan-name) default-frame-alist)
-            erc-default-recipients (list chan-name))
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should-not (equal chan-name (frame-parameter (window-frame) 'name)))
-      ;; New channel buffer replaces server in lower window
-      (should (get-buffer-window (current-buffer) t))
-      (should-not (get-buffer-window server-name t)))))
-
-(ert-deftest erc-reuse-frames--displayed-single ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (let ((erc-reuse-frames 'displayed))
-       (erc-tests--erc-reuse-frames--displayed-single orig-frame
-                                                      "server" "#chan")
-       (should-not (cdr (frame-list))))
-     (dolist (b '("server" "#chan"))
-       (kill-buffer b)))))
-
-(defun erc-tests--assert-server-split (buffer-or-name frame-name)
-  ;; Assert current buffer resides on one side of a horizontal split
-  ;; in the "server" frame but is not selected.
-  (let* ((buffer-window (get-buffer-window buffer-or-name t))
-         (buffer-frame (window-frame buffer-window)))
-    (should (equal frame-name (frame-parameter buffer-frame 'name)))
-    (should (memq buffer-window (car-safe (window-tree buffer-frame))))
-    (should-not (eq buffer-window (frame-selected-window)))
-    buffer-frame))
-
-(defun erc-tests--erc-reuse-frames--displayed-double (_)
-  (should (eq erc-reuse-frames 'displayed))
-
-  (make-frame '((name . "other")))
-  (select-frame (make-frame '((name . "server"))) 'no-record)
-  (set-window-buffer (selected-window) "*scratch*") ; invokes `erc'
-
-  ;; A user invokes an entry point and switches immediately to a new
-  ;; frame before autojoin kicks in (bug#55540).
-
-  (ert-info ("New server buffer shown in selected frame")
-    (with-current-buffer (generate-new-buffer "server")
-      (erc-mode)
-      (setq erc-server-process (start-process "server" (current-buffer)
-                                              "sleep" "10")
-            erc-network 'foonet
-            erc-server-current-nick "tester"
-            erc-networks--id (erc-networks--id-create nil)
-            erc--server-last-reconnect-count 0)
-      (set-process-buffer erc-server-process (current-buffer))
-      (set-process-query-on-exit-flag erc-server-process nil)
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (should (equal "server" (frame-parameter (window-frame) 'name)))
-      (should (get-buffer-window (current-buffer) t))))
-
-  (select-frame-by-name "other")
-
-  (ert-info ("New channel shown in dedicated frame")
-    (with-current-buffer (generate-new-buffer "#chan")
-      (erc-mode)
-      (erc-tests--servars "server" 'erc-server-process 'erc-networks--id
-                          'erc-network)
-      (setq erc-frame-alist (cons '(name . "#chan") default-frame-alist)
-            erc-default-recipients '("#chan"))
-      (should-not (get-buffer-window (current-buffer) t))
-      (erc-setup-buffer (current-buffer))
-      (erc-tests--assert-server-split (current-buffer) "server")
-      ;; New channel buffer replaces server in lower window of other frame
-      (should-not (get-buffer-window "server" t)))))
-
-(ert-deftest erc-reuse-frames--displayed-double ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (let ((erc-reuse-frames 'displayed))
-       (erc-tests--erc-reuse-frames--displayed-double orig-frame))
-     (dolist (b '("server" "#chan"))
-       (kill-buffer b)))))
-
-;; If a frame showing ERC buffers exists among other frames, new,
-;; additional connections will use the existing IRC frame.  However,
-;; if two or more frames exist with ERC buffers unique to a particular
-;; connection, the correct frame will be found.
-
-(defun erc-tests--erc-reuse-frames--displayed-full (orig-frame)
-  (erc-tests--erc-reuse-frames--displayed-double orig-frame)
-  ;; Server buffer is not displayed because #chan has replaced it in
-  ;; the "server" frame, which is not selected.
-  (should (equal "other" (frame-parameter (window-frame) 'name)))
-  (erc-tests--erc-reuse-frames--displayed-single orig-frame "ircd" "#spam")
-  (should (equal "other" (frame-parameter (window-frame) 'name)))
-
-  ;; Buffer "#spam" has replaced "ircd", which earlier replaced
-  ;; "#chan" in frame "server".  But this is confusing, so...
-  (ert-info ("Arrange windows for second connection in other frame")
-    (set-window-buffer (selected-window) "ircd")
-    (split-window-below)
-    (set-window-buffer (next-window) "#spam")
-    (should (equal (cddar (window-tree))
-                   (list (get-buffer-window "ircd" t)
-                         (get-buffer-window "#spam" t)))))
-
-  (ert-info ("Arrange windows for first connection in server frame")
-    (select-frame-by-name "server")
-    (set-window-buffer (selected-window) "server")
-    (set-window-buffer (next-window) "#chan")
-    (should (equal (cddar (window-tree))
-                   (list (get-buffer-window "server" t)
-                         (get-buffer-window "#chan" t)))))
-
-  ;; Select original ERT frame
-  (ert-info ("New target for connection server finds appropriate frame")
-    (select-frame orig-frame 'no-record)
-    (with-current-buffer (window-buffer (selected-window))
-      (should (member (buffer-name) '("*ert*" "*scratch*")))
-      (with-current-buffer (generate-new-buffer "alice")
-        (erc-mode)
-        (erc-tests--servars "server" 'erc-server-process 'erc-networks--id)
-        (setq erc-default-recipients '("alice"))
-        (should-not (get-buffer-window (current-buffer) t))
-        (erc-setup-buffer (current-buffer))
-        ;; Window created in frame "server"
-        (should (eq (selected-frame) orig-frame))
-        (erc-tests--assert-server-split (current-buffer) "server"))))
-
-  (ert-info ("New target for connection ircd finds appropriate frame")
-    (select-frame orig-frame 'no-record)
-    (with-current-buffer (window-buffer (selected-window))
-      (should (member (buffer-name) '("*ert*" "*scratch*")))
-      (with-current-buffer (generate-new-buffer "bob")
-        (erc-mode)
-        (erc-tests--servars "ircd" 'erc-server-process 'erc-networks--id)
-        (setq erc-default-recipients '("bob"))
-        (should-not (get-buffer-window (current-buffer) t))
-        (erc-setup-buffer (current-buffer))
-        ;; Window created in frame "other"
-        (should (eq (selected-frame) orig-frame))
-        (erc-tests--assert-server-split (current-buffer) "other")))))
-
-(ert-deftest erc-reuse-frames--displayed-full ()
-  :tags '(:unstable :expensive-test)
-  (erc-tests--erc-reuse-frames
-   (lambda (orig-frame)
-     (let ((erc-reuse-frames 'displayed))
-       (erc-tests--erc-reuse-frames--displayed-full orig-frame))
-     (dolist (b '("server" "ircd" "bob" "alice" "#spam" "#chan"))
-       (kill-buffer b)))))
-
 (ert-deftest erc-lurker-maybe-trim ()
   (let (erc-lurker-trim-nicks
         (erc-lurker-ignore-chars "_`"))
-- 
2.40.1

>From 78bba39e65b168a117c077518f2aee2a8465e470 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Tue, 30 May 2023 23:27:12 -0700
Subject: [PATCH 2/2] [5.6] Allow custom display-buffer actions in ERC

* etc/ERC-NEWS: Mention new `display-buffer' "action" variant for all
buffer-display options.
* lisp/erc/erc-backend.el (erc-server-JOIN, erc-server-PRIVMSG,
erc-server-NOTICE): Set `erc--display-context' to a symbol for the IRC
command, like `JOIN' in order to influence `erc-setup-buffer' by way
of `erc--open-target'.
* lisp/erc/erc.el (erc--buffer-display-choices): New helper for
defining common `:type' for all buffer-display options.
(erc-buffer-display): Add new choice of either `display-buffer' or
`pop-to-buffer' paired with an "action alist".
(erc-buffer-display, erc-interactive-display, erc-reconnect-display,
erc-receive-query-display): Use helper `erc--buffer-display-choices'
for defining `:type'.
(erc-skip-displaying-selected-window-buffer): New variable, deprecated
at birth, to act as an escape hatch for folks who don't want to skip
the displaying of buffers already showing in the selected window.
(erc--display-buffer-action): Local variable allowing modules to
influence the displaying of new ERC buffers independently of user
options.
(erc-open): Bind `display-buffer-overriding-action' to the value of
`erc--display-buffer-action' around calls to `erc-setup-buffer'.
(erc-setup-buffer): Do nothing when the selected window already shows
current buffer unless user has provided a custom action.  Accommodate
new choice values `display-buffer' and `pop-to-buffer'.
(erc-select-read-args): Add `erc--display-context' to environment.
(erc, erc-tls): Bind `erc--display-context' around calls to
`erc-select-read-args' and main body.
(erc-cmd-JOIN, erc-cmd-QUERY, erc-handle-irc-url): Add item for
`erc-interactive-display' to `erc--display-context'.
* test/lisp/erc/erc-tests.el (erc-setup-buffer--custom-action): New
test.
(erc-select-read-args, erc-tls, erc--interactive): Expect new
environment binding for `erc--display-context'.  (Bug#62833)
---
 etc/ERC-NEWS               |  12 ++-
 lisp/erc/erc-backend.el    |   9 ++-
 lisp/erc/erc.el            | 153 ++++++++++++++++++++++++++++---------
 test/lisp/erc/erc-tests.el |  81 +++++++++++++++++---
 4 files changed, 206 insertions(+), 49 deletions(-)

diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 68cf0e2d6ca..9177f61f8cc 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -37,7 +37,7 @@ decade overdue, this is no longer the case.  Other UX improvements in
 this area aim to make the process of connecting interactively slightly
 more streamlined and less repetitive, even for veteran users.
 
-** Revised buffer-display handling for interactive commands.
+** Revised buffer-display handling.
 A point of friction for new users and one only just introduced with
 ERC 5.5 has been the lack of visual feedback when first connecting via
 M-x erc or when issuing a "/JOIN" command at the prompt.  As explained
@@ -58,6 +58,16 @@ option (now known as 'erc-receive-query-display') is nil, ERC uses
 'erc-interactive-display'.  The old nil behavior can still be gotten
 via the new compatibility flag 'erc-receive-query-display-defer'.
 
+This release also introduces a few subtleties affecting the display of
+new or reassociated buffers.  One involves buffers that already occupy
+the selected window.  ERC now treats these as deserving of an implicit
+'bury'.  An escape hatch for this and most other baked-in behaviors is
+now available in the form of a new type variant recognized by all such
+options.  That is, users can now specify their own 'display-buffer'
+function to exercise full control over nearly all buffer-display
+related decisions.  See the newly expanded doc strings of
+'erc-buffer-display' and friends for details.
+
 ** Setting a module's mode variable via Customize earns a warning.
 Trying and failing to activate a module via its minor mode's Custom
 widget has been an age-old annoyance for new users.  Previously
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index b5bd96c189d..3bcda27444d 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -101,6 +101,7 @@
 (eval-when-compile (require 'cl-lib))
 (require 'erc-common)
 
+(defvar erc--display-context)
 (defvar erc--target)
 (defvar erc--user-from-nick-function)
 (defvar erc-channel-list)
@@ -1686,7 +1687,9 @@ define-erc-response-handler
   "Handle join messages."
   nil
   (let ((chnl (erc-response.contents parsed))
-        (buffer nil))
+        (buffer nil)
+        (erc--display-context `((erc-buffer-display . JOIN)
+                                ,@erc--display-context)))
     (pcase-let ((`(,nick ,login ,host)
                  (erc-parse-user (erc-response.sender parsed))))
       ;; strip the stupid combined JOIN facility (IRC 2.9)
@@ -1885,6 +1888,8 @@ define-erc-response-handler
              (noticep (string= cmd "NOTICE"))
              ;; S.B. downcase *both* tgt and current nick
              (privp (erc-current-nick-p tgt))
+             (erc--display-context `((erc-buffer-display . ,(intern cmd))
+                                     ,@erc--display-context))
              s buffer
              fnick)
         (setf (erc-response.contents parsed) msg)
@@ -1899,6 +1904,8 @@ define-erc-response-handler
                               (and erc-ensure-target-buffer-on-privmsg
                                    (or erc-receive-query-display
                                        erc-join-buffer)))))
+                (push `(erc-receive-query-display . ,(intern cmd))
+                      erc--display-context)
                 (setq buffer (erc--open-target nick)))
             ;; A channel buffer has been killed but is still joined.
             (when erc-ensure-target-buffer-on-privmsg
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 70adbb15b5f..f1dafd0dbf8 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1548,9 +1548,26 @@ erc-default-port-tls
   "IRC port to use for encrypted connections if it cannot be \
 detected otherwise.")
 
+(defconst erc--buffer-display-choices
+  `(choice (const :tag "Use value of `erc-buffer-display'" nil)
+           (const :tag "Split window and select" window)
+           (const :tag "Split window but don't select" window-noselect)
+           (const :tag "New frame" frame)
+           (const :tag "Don't display" bury)
+           (const :tag "Use current window" buffer)
+           (choice :tag "Defer to a display function"
+                   (function-item display-buffer)
+                   (function-item pop-to-buffer)
+                   (function :tag "User-defined")))
+  "Common choices for buffer-display options.")
+
 (defvaralias 'erc-join-buffer 'erc-buffer-display)
 (defcustom erc-buffer-display 'bury
   "How to display a newly created ERC buffer.
+This determines the baseline, \"catch-all\" display behavior.  It
+takes a backseat to more context-specific display options, like
+`erc-interactive-display', `erc-reconnect-display', and
+`erc-receive-query-display'.
 
 The available choices are:
 
@@ -1559,17 +1576,32 @@ erc-buffer-display
   `frame'           - in another frame,
   `bury'            - bury it in a new buffer,
   `buffer'          - in place of the current buffer,
-
-See related options `erc-interactive-display',
-`erc-reconnect-display', and `erc-receive-query-display'."
+  DISPLAY-FUNCTION  - a `display-buffer'-like function
+
+Here, DISPLAY-FUNCTION should accept a buffer and an ACTION of
+the kind described by the Info node `(elisp) Choosing Window'.
+At times, ERC may add hints about the calling context to the
+ACTION's alist.  Keys are symbols of user options, like
+`erc-buffer-display', and values are predefined constants
+specific to each.  For this particular option, possible values
+include the symbols
+
+  `JOIN', `PRIVMSG', `NOTICE', `erc', and `erc-tls'.
+
+The first three signify IRC commands received from the server and
+the rest entry-point commands responsible for the connection.
+When dealing with the latter two, users may prefer to call
+DISPLAY-FUNCTION directly on (server) buffers returned by these
+entry points because the context leading to their creation is
+plainly obvious.
+
+Note that when the selected window already shows the current
+buffer, ERC pretends this option's value is `bury' unless the
+variable `erc-skip-displaying-selected-window-buffer' is nil or
+the value of this option is DISPLAY-FUNCTION."
   :package-version '(ERC . "5.5")
   :group 'erc-buffers
-  :type '(choice (const :tag "Split window and select" window)
-                 (const :tag "Split window, don't select" window-noselect)
-                 (const :tag "New frame" frame)
-                 (const :tag "Bury in new buffer" bury)
-                 (const :tag "Use current buffer" buffer)
-                 (const :tag "Use current buffer" t)))
+  :type (cons 'choice (nthcdr 2 erc--buffer-display-choices)))
 
 (defvaralias 'erc-query-display 'erc-interactive-display)
 (defcustom erc-interactive-display 'window
@@ -1578,30 +1610,36 @@ erc-interactive-display
 interactively at the prompt.  It does not apply when calling a
 handler for such a command, like `erc-cmd-JOIN', from lisp code.
 See `erc-buffer-display' for a full description of available
-values."
+values.
+
+When the value is a user-provided function, ERC may inject a hint
+about the invocation context as an extra item in the \"action
+alist\" included as part of the second argument.  The item's key
+is the symbol `erc-interactive-display' and its value one of
+
+  `/QUERY', `/JOIN', `url', `erc', or `erc-tls'.
+
+All are symbols indicating an inciting user action, such as the
+issuance of a slash command, the clicking of a URL hyperlink, or
+the invocation of an entry-point command."
   :package-version '(ERC . "5.6") ; FIXME sync on release
   :group 'erc-buffers
-  :type '(choice (const :tag "Use value of `erc-buffer-display'" nil)
-                 (const :tag "Split window and select" window)
-                 (const :tag "Split window, don't select" window-noselect)
-                 (const :tag "New frame" frame)
-                 (const :tag "Bury new and don't display existing" bury)
-                 (const :tag "Use current buffer" buffer)))
+  :type erc--buffer-display-choices)
 
 (defcustom erc-reconnect-display nil
   "How and whether to display a channel buffer when auto-reconnecting.
 This only affects automatic reconnections and is ignored, like
 all other buffer-display options, when issuing a /RECONNECT or
 successfully reinvoking `erc-tls' with similar arguments.  See
-`erc-buffer-display' for a description of possible values."
+`erc-buffer-display' for a description of possible values.
+
+When the value is function, ERC may inject a hint about the
+calling context as an extra item in the alist making up the tail
+of the second, \"action\" argument.  The item's key is the symbol
+`erc-reconnect-display' and its value something non-nil."
   :package-version '(ERC . "5.5")
   :group 'erc-buffers
-  :type '(choice (const :tag "Use value of `erc-buffer-display'" nil)
-                 (const :tag "Split window and select" window)
-                 (const :tag "Split window, don't select" window-noselect)
-                 (const :tag "New frame" frame)
-                 (const :tag "Bury in new buffer" bury)
-                 (const :tag "Use current buffer" buffer)))
+  :type erc--buffer-display-choices)
 
 (defcustom erc-reconnect-display-timeout 10
   "Duration `erc-reconnect-display' remains active.
@@ -2089,12 +2127,37 @@ erc--updating-modules-p
 (defvar erc--setup-buffer-hook nil
   "Internal hook for module setup involving windows and frames.")
 
+(defvar erc--display-context nil
+  "Extra action alist items passed to `display-buffer'.
+Non-nil when a user specifies a custom display action for certain
+display-options, like `erc-reconnect-display'.  ERC pairs the
+option's symbol with a context-dependent value and adds the entry
+to the user-provided alist when calling `pop-to-buffer' or
+`display-buffer'.")
+
+(defvar erc-skip-displaying-selected-window-buffer t
+  "Whether to forgo showing a buffer that's already being displayed.
+But only in the selected window.")
+(make-obsolete 'erc-show-already-displayed-buffer
+               "non-nil behavior to be made permanent" "30.1")
+
+(defvar-local erc--display-buffer-action nil
+  "The value of `display-buffer-overriding-action' when non-nil.
+Influences the displaying of new or reassociated ERC buffers.
+Reserved for use by built-in modules.")
+
 (defun erc-setup-buffer (buffer)
   "Consults `erc-join-buffer' to find out how to display `BUFFER'."
   (pcase (if (zerop (erc-with-server-buffer
                       erc--server-last-reconnect-count))
              erc-join-buffer
            (or erc-reconnect-display erc-join-buffer))
+    ((and (pred functionp) disp-fn (let context erc--display-context))
+     (unless (zerop erc--server-last-reconnect-count)
+       (push '(erc-reconnect-display . t) context))
+     (funcall disp-fn buffer (cons nil context)))
+    ((guard (and erc-skip-displaying-selected-window-buffer
+                 (eq (window-buffer) buffer))))
     ('window
      (if (active-minibuffer-window)
          (display-buffer buffer)
@@ -2292,8 +2355,10 @@ erc-open
         ;; we can't log to debug buffer, it may not exist yet
         (message "erc: old buffer %s, switching to %s"
                  old-buffer buffer))
-      (erc-setup-buffer buffer)
-      (run-hooks 'erc--setup-buffer-hook))
+      (let ((display-buffer-overriding-action
+             (or erc--display-buffer-action display-buffer-overriding-action)))
+        (erc-setup-buffer buffer)
+        (run-hooks 'erc--setup-buffer-hook)))
 
     buffer))
 
@@ -2401,6 +2466,8 @@ erc-select-read-args
          env)
     (when erc-interactive-display
       (push `(erc-join-buffer . ,erc-interactive-display) env))
+    (when erc--display-context
+      (push `(erc--display-context . ,erc--display-context) env))
     (when opener
       (push `(erc-server-connect-function . ,opener) env))
     (when (and passwd (string= "" passwd))
@@ -2454,7 +2521,12 @@ erc
 See `erc-tls' for the meaning of ID.
 
 \(fn &key SERVER PORT NICK USER PASSWORD FULL-NAME ID)"
-  (interactive (erc-select-read-args))
+  (interactive (let ((erc--display-context `((erc-interactive-display . erc)
+                                             ,@erc--display-context)))
+                 (erc-select-read-args)))
+  (unless (assq 'erc--display-context --interactive-env--)
+    (push '(erc--display-context . ((erc-buffer-display . erc)))
+          --interactive-env--))
   (erc--with-entrypoint-environment --interactive-env--
     (erc-open server port nick full-name t password nil nil nil nil user id)))
 
@@ -2519,8 +2591,11 @@ erc-tls
 interactively.
 
 \(fn &key SERVER PORT NICK USER PASSWORD FULL-NAME CLIENT-CERTIFICATE ID)"
-  (interactive (let ((erc-default-port erc-default-port-tls))
-		 (erc-select-read-args)))
+  (interactive
+   (let ((erc-default-port erc-default-port-tls)
+         (erc--display-context `((erc-interactive-display . erc-tls)
+                                 ,@erc--display-context)))
+     (erc-select-read-args)))
   ;; Bind `erc-server-connect-function' to `erc-open-tls-stream'
   ;; around `erc-open' when a non-default value hasn't been specified
   ;; by the user or the interactive form.  And don't bother checking
@@ -2529,6 +2604,9 @@ erc-tls
               (not (eq erc-server-connect-function #'erc-open-network-stream)))
     (push '(erc-server-connect-function . erc-open-tls-stream)
           --interactive-env--))
+  (unless (assq 'erc--display-context --interactive-env--)
+    (push '(erc--display-context . ((erc-buffer-display . erc-tls)))
+          --interactive-env--))
   (erc--with-entrypoint-environment --interactive-env--
     (erc-open server port nick full-name t password
               nil nil nil client-certificate user id)))
@@ -3683,7 +3761,10 @@ erc-cmd-JOIN
                         (sn (erc-extract-nick (erc-response.sender parsed)))
                         ((erc-nick-equal-p sn (erc-current-nick)))
                         (erc-join-buffer (or erc-interactive-display
-                                             erc-join-buffer)))
+                                             erc-join-buffer))
+                        (erc--display-context `((erc-interactive-display
+                                                 . /JOIN)
+                                                ,@erc--display-context)))
                      (run-hook-with-args-until-success
                       'erc-server-JOIN-functions proc parsed)
                      t))))
@@ -4067,7 +4148,9 @@ erc-cmd-QUERY
       ;; currently broken, evil hack to display help anyway
                                         ;(erc-delete-query))))
     (signal 'wrong-number-of-arguments '(erc-cmd-QUERY 0)))
-  (let ((erc-join-buffer erc-interactive-display))
+  (let ((erc-join-buffer erc-interactive-display)
+        (erc--display-context `((erc-interactive-display . /QUERY)
+                                ,@erc--display-context)))
     (erc-with-server-buffer
      (erc--open-target user))))
 
@@ -4851,13 +4934,7 @@ erc-receive-query-display
   :package-version '(ERC . "5.6")
   :group 'erc-buffers
   :group 'erc-query
-  :type '(choice (const :tag "Defer to value of `erc-buffer-display'" nil)
-                 (const :tag "Split window and select" window)
-                 (const :tag "Split window, don't select" window-noselect)
-                 (const :tag "New frame" frame)
-                 (const :tag "Bury in new buffer" bury)
-                 (const :tag "Use current buffer" buffer)
-                 (const :tag "Use current buffer" t)))
+  :type erc--buffer-display-choices)
 
 (defvar erc-receive-query-display-defer t
   "How to interpret a null `erc-receive-query-display'.
@@ -7853,6 +7930,8 @@ erc-handle-irc-url
 Customize `erc-url-connect-function' to override this."
   (when (eql port 0) (setq port nil))
   (let* ((net (erc-networks--determine host))
+         (erc--display-context `((erc-interactive-display . url)
+                                 ,@erc--display-context))
          (server-buffer
           ;; Viable matches may slip through the cracks for unknown
           ;; networks.  Additional passes could likely improve things.
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index b751ef50520..6dbd0d4704f 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -503,6 +503,49 @@ erc--switch-to-buffer
     (dolist (b '("server" "other" "#chan" "#foo" "#fake"))
       (kill-buffer b))))
 
+(ert-deftest erc-setup-buffer--custom-action ()
+  (erc-mode)
+  (erc-tests--set-fake-server-process "sleep" "1")
+  (setq erc--server-last-reconnect-count 0)
+  (let ((owin (selected-window))
+        (obuf (window-buffer))
+        (mbuf (messages-buffer))
+        calls)
+    (cl-letf (((symbol-function 'switch-to-buffer) ; regression
+               (lambda (&rest r) (push (cons 'switch-to-buffer r) calls)))
+              ((symbol-function 'erc--test-fun)
+               (lambda (&rest r) (push (cons 'erc--test-fun r) calls)))
+              ((symbol-function 'display-buffer)
+               (lambda (&rest r) (push (cons 'display-buffer r) calls))))
+
+      ;; Baseline
+      (let ((erc-join-buffer 'bury))
+        (erc-setup-buffer mbuf)
+        (should-not calls))
+
+      (should-not erc--display-context)
+
+      ;; `display-buffer'
+      (let ((erc--display-context '((erc-buffer-display . 1)))
+            (erc-join-buffer 'erc--test-fun))
+        (erc-setup-buffer mbuf)
+        (should (equal `(erc--test-fun ,mbuf (nil (erc-buffer-display . 1)))
+                       (pop calls)))
+        (should-not calls))
+
+      ;; `pop-to-buffer' with `erc-reconnect-display'
+      (let* ((erc--server-last-reconnect-count 1)
+             (erc--display-context '((erc-buffer-display . 1)))
+             (erc-reconnect-display 'erc--test-fun))
+        (erc-setup-buffer mbuf)
+        (should (equal `(erc--test-fun ,mbuf (nil (erc-reconnect-display . t)
+                                                  (erc-buffer-display . 1)))
+                       (pop calls)))
+        (should-not calls)))
+
+    (should (eq owin (selected-window)))
+    (should (eq obuf (window-buffer)))))
+
 (ert-deftest erc-lurker-maybe-trim ()
   (let (erc-lurker-trim-nicks
         (erc-lurker-ignore-chars "_`"))
@@ -1439,14 +1482,18 @@ erc-select-read-args
                            (erc-join-buffer . window))))))
 
   (ert-info ("Switches to TLS when URL is ircs://")
-    (should (equal (ert-simulate-keys "ircs://irc.gnu.org\r\r\r\r"
-                     (erc-select-read-args))
-                   (list :server "irc.gnu.org"
-                         :port 6697
-                         :nick (user-login-name)
-                         '&interactive-env
-                         '((erc-server-connect-function . erc-open-tls-stream)
-                           (erc-join-buffer . window))))))
+    (let ((erc--display-context '((erc-interactive-display . erc))))
+      (should (equal (ert-simulate-keys "ircs://irc.gnu.org\r\r\r\r"
+                       (erc-select-read-args))
+                     (list :server "irc.gnu.org"
+                           :port 6697
+                           :nick (user-login-name)
+                           '&interactive-env
+                           '((erc-server-connect-function
+                              . erc-open-tls-stream)
+                             (erc--display-context
+                              . ((erc-interactive-display . erc)))
+                             (erc-join-buffer . window)))))))
 
   (setq-local erc-interactive-display nil) ; cheat to save space
 
@@ -1526,6 +1573,7 @@ erc-tls
               ((symbol-function 'erc-open)
                (lambda (&rest r)
                  (push `((erc-join-buffer ,erc-join-buffer)
+                         (erc--display-context ,@erc--display-context)
                          (erc-server-connect-function
                           ,erc-server-connect-function))
                        env)
@@ -1538,6 +1586,7 @@ erc-tls
                          nil nil nil nil nil "user" nil)))
         (should (equal (pop env)
                        '((erc-join-buffer bury)
+                         (erc--display-context (erc-buffer-display . erc-tls))
                          (erc-server-connect-function erc-open-tls-stream)))))
 
       (ert-info ("Full")
@@ -1554,6 +1603,7 @@ erc-tls
                          "bob:changeme" nil nil nil t "bobo" GNU.org)))
         (should (equal (pop env)
                        '((erc-join-buffer bury)
+                         (erc--display-context (erc-buffer-display . erc-tls))
                          (erc-server-connect-function erc-open-tls-stream)))))
 
       ;; Values are often nil when called by lisp code, which leads to
@@ -1573,6 +1623,7 @@ erc-tls
                              "bob:changeme" nil nil nil nil "bobo" nil)))
         (should (equal (pop env)
                        '((erc-join-buffer bury)
+                         (erc--display-context (erc-buffer-display . erc-tls))
                          (erc-server-connect-function erc-open-tls-stream)))))
 
       (ert-info ("Interactive")
@@ -1583,6 +1634,8 @@ erc-tls
                          nil nil nil nil "user" nil)))
         (should (equal (pop env)
                        '((erc-join-buffer window)
+                         (erc--display-context
+                          (erc-interactive-display . erc-tls))
                          (erc-server-connect-function erc-open-tls-stream)))))
 
       (ert-info ("Custom connect function")
@@ -1593,6 +1646,8 @@ erc-tls
                            nil nil nil nil nil "user" nil)))
           (should (equal (pop env)
                          '((erc-join-buffer bury)
+                           (erc--display-context
+                            (erc-buffer-display . erc-tls))
                            (erc-server-connect-function my-connect-func))))))
 
       (ert-info ("Advised default function overlooked") ; intentional
@@ -1604,6 +1659,7 @@ erc-tls
                          nil nil nil nil nil "user" nil)))
         (should (equal (pop env)
                        '((erc-join-buffer bury)
+                         (erc--display-context (erc-buffer-display . erc-tls))
                          (erc-server-connect-function erc-open-tls-stream))))
         (advice-remove 'erc-server-connect-function 'erc-tests--erc-tls))
 
@@ -1617,6 +1673,8 @@ erc-tls
                            '("irc.libera.chat" 6697 "tester" "unknown" t
                              nil nil nil nil nil "user" nil)))
             (should (equal (pop env) `((erc-join-buffer bury)
+                                       (erc--display-context
+                                        (erc-buffer-display . erc-tls))
                                        (erc-server-connect-function ,f))))
             (advice-remove 'erc-server-connect-function
                            'erc-tests--erc-tls)))))))
@@ -1631,6 +1689,7 @@ erc--interactive
               ((symbol-function 'erc-open)
                (lambda (&rest r)
                  (push `((erc-join-buffer ,erc-join-buffer)
+                         (erc--display-context ,@erc--display-context)
                          (erc-server-connect-function
                           ,erc-server-connect-function))
                        env)
@@ -1643,8 +1702,9 @@ erc--interactive
                        '("irc.libera.chat" 6697 "tester" "unknown" t nil
                          nil nil nil nil "user" nil)))
         (should (equal (pop env)
-                       '((erc-join-buffer window) (erc-server-connect-function
-                                                   erc-open-tls-stream)))))
+                       '((erc-join-buffer window)
+                         (erc--display-context (erc-interactive-display . erc))
+                         (erc-server-connect-function erc-open-tls-stream)))))
 
       (ert-info ("Nick supplied, decline TLS upgrade")
         (ert-simulate-keys "\r\rdummy\r\rn\r"
@@ -1654,6 +1714,7 @@ erc--interactive
                          nil nil nil nil "user" nil)))
         (should (equal (pop env)
                        '((erc-join-buffer window)
+                         (erc--display-context (erc-interactive-display . erc))
                          (erc-server-connect-function
                           erc-open-network-stream))))))))
 
-- 
2.40.1