ERC supports the “action” interface used by display-buffer
and friends from window.el. See Displaying Buffers in Emacs Lisp, for specifics. When ERC displays a new or
“reassociated” buffer, it consults its various buffer-display
options, such as erc-buffer-display, to decide whether and how
the buffer ought to appear in a window. Exactly which one it consults
depends on the context in which the buffer is being manifested.
For some buffer-display options, the context is pretty cut and dry.
For instance, in the case of erc-receive-query-display, you’re
receiving a query from someone you haven’t yet chatted with in the
current session. For other options, like
erc-interactive-display, the precise context varies. For
example, you might be opening a query buffer with the command
/QUERY bob RET or joining a new channel with /JOIN
#chan RET. Power users wishing to distinguish between such
nuanced contexts or just exercise more control over buffer-display
behavior generally can elect to override these options by setting one
or more to a “display-buffer-like” function that accepts a
buffer and an action argument.
In this first example, a user-provided buffer-display function
displays new server buffers in the current window when issuing an
M-x erc-tls RET and in a split window for all other
interactve contexts covered by the option
erc-interactive-display, like clicking an ‘irc://’-style
URL (see URL).
(defun my-erc-interactive-display-buffer (buffer action)
"Pop to BUFFER when running \\[erc-tls], clicking a link, etc."
(when-let ((alist (cdr action))
(found (alist-get 'erc-interactive-display alist)))
(if (eq found 'erc-tls)
(pop-to-buffer-same-window buffer action)
(pop-to-buffer buffer action))))
(setopt erc-interactive-display #'my-erc-interactive-display-buffer)
Observe that ERC supplies the names of buffer-display options as action alist keys and pairs them with contextual constants, like the symbols ‘erc-tls’ or ‘url’, the full lineup of which are listed below.
In this second example, for Emacs 29 and above, the user writes three
predicates that somewhat resemble the “display-buffer-like”
function above. These too look for action alist keys sharing
the names of ERC’s buffer-display options (and, in one case, a
module’s minor mode).
(defun my-erc-disp-entry-p (_ action)
(memq (cdr (or (assq 'erc-buffer-display action)
(assq 'erc-interactive-display action)))
'(erc-tls url)))
(defun my-erc-disp-query-p (_ action)
(or (eq (cdr (assq 'erc-interactive-display action)) '/QUERY)
(and (eq (cdr (assq 'erc-receive-query-display action)) 'PRIVMSG)
(member (erc-default-target) '("bob" "alice")))))
(defun my-erc-disp-chan-p (_ action)
(or (assq 'erc-autojoin-mode action)
(and (eq (cdr (assq 'erc-buffer-display action)) 'JOIN)
(member (erc-default-target) '("#emacs" "#fsf")))))
You’ll notice we ignore the buffer parameter of these predicates
because ERC ensures that buffer is already current (which is why
we can freely call erc-default-target). Note also that we
cheat a little by treating the action parameter like an alist
when it’s really a cons of one or more functions and an alist.
To complement our predicates, we set all three buffer-display options
referenced in their action-alist lookups to
display-buffer. This tells ERC to defer to that function in
the display contexts covered by these options.
(setopt erc-buffer-display #'display-buffer
erc-interactive-display #'display-buffer
erc-receive-query-display #'display-buffer
;;
erc-auto-reconnect-display 'bury)
The last option above just tells ERC to avoid any buffer-display
machinery when auto-reconnecting. (For historical reasons, ERC’s
buffer-display options use the term “bury” to mean “ignore” rather
than bury-buffer.)
Finally, we compose our predicates into buffer-match-p
conditions and pair them with various well known display-buffer
action functions and action-alist members.
(setopt display-buffer-alist
;; Create new frame with M-x erc-tls RET or (erc-tls ...)
'(((and (major-mode . erc-mode) my-erc-disp-entry-p)
display-buffer-pop-up-frame
(reusable-frames . visible))
;; Show important chans and queries in a split.
((and (major-mode . erc-mode)
(or my-erc-disp-chan-p my-erc-disp-query-p))
display-buffer-pop-up-window)
;; Ignore everything else.
((major-mode . erc-mode)
display-buffer-no-window
(allow-no-window . t))))
Of course, we could just as well set our buffer-display options to one
or more homespun functions instead of bothering with
display-buffer-alist at all (in what would make for a more
complicated version of our first example). But perhaps we already
have a growing menagerie of similar predicates and like to keep
everything in one place in our init.el.
All keys are symbols, as are values, unless otherwise noted.
erc-buffer-display
erc-interactive-display
erc-receive-query-display
erc-auto-reconnect-display
nil
erc-autojoin-mode
"#chan"