From b354b3a53bfbb30dc4f98fe9947f3ba939e1436d Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Tue, 30 May 2023 23:27:12 -0700 Subject: [PATCH] Allow custom display-buffer actions in ERC * doc/misc/erc.texi: Add new section under "Integrations" chapter describing `display-buffer' Custom function choice for ERC's many buffer-display options. * etc/ERC-NEWS: Mention new function variant for all buffer-display options. * lisp/erc/erc-backend.el: Add forward declaration for `erc--called-as-input-p' and `erc--display-context'. (erc--server-reconnect-display-timer, erc--server-last-reconnect-display-reset): Use new name for option `erc-reconnect-display', now `erc-auto-reconnect-display'. (erc--server-determine-join-display-context): New generic function to determine value of `erc--display-context' during JOINs. (erc-server-JOIN, erc-server-PRIVMSG): Set `erc--display-context' to a symbol for the handler's IRC command, like `JOIN', for the benefit of custom `display-buffer'-like functions running in `erc-setup-buffer'. (erc-server-471, erc-server-471-functions, erc-server-473, erc-server-473-functions): New handlers for JOIN rejections. Also remove 471 and 473 from comment at bottom of file. (erc-server-475): Bind `erc--called-as-input-p' so that `erc-cmd-JOIN' sets `erc-interactive-display' context. * lisp/erc/erc-join.el (erc-autojoin-mode, erc-autojoin-enable, erc-autojoin-disable): Kill local variable `erc-join--requested-channels'. Add and remove `erc-join--remove-requested-channels' to/from various server-handler hooks for JOIN rejection numerics. (erc-join--requested-channels): New local variable to remember channels we've attempted to JOIN this session that haven't yet been confirmed by the server. (erc-join--remove-requested-channel): New JOIN rejection handler to stop tracking channel in `erc-join--requested-channels'. (erc--server-determine-join-display-context): module-specific implementation of generic function for `erc-autojoin-mode'. (erc-autojoin--join): Remember channels slated for JOIN'ing. * lisp/erc/erc.el (erc--buffer-display-choices): New helper constant for defining common `:type' for all buffer-display options. (erc-buffer-display, erc-interactive-display, erc-auto-reconnect-display, erc-receive-query-display): Use helper `erc--buffer-display-choices' for defining `:type', which includes a new choice for a `display-buffer'-like function. (erc-reconnect-display, erc-auto-reconnect-display): Alias former to latter, now the preferred name. (erc-reconnect-timeout, erc-auto-reconnect-timeout): Change name from former to latter. This option is new in ERC 5.6. (erc-reconnect-display-server-buffers): New option. (erc-buffer-do): Revise doc string. (erc--display-context): New variable, an alist of "context tokens" to be forwarded as the "action alist" to `erc-buffer-display' functions. (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-overriding-action): Local variable allowing modules to influence the displaying of new ERC buffers independently of user options. (erc-setup-buffer): Do nothing when the selected window already shows current buffer unless user has provided a custom display function. Accommodate new Custom choice function values, like `display-buffer' and `pop-to-buffer'. (erc-open): Run `erc-setup-buffer' when option `erc-reconnect-display-server-buffers' is non-nil, even for existing server buffers. Bind `display-buffer-overriding-action' to the value of `erc--display-buffer-overriding-action' around calls to `erc-setup-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--cmd-reconnect, erc-handle-irc-url): Add item for `erc-interactive-display' to `erc--display-context'. (erc-connection-established): Update name of `erc-reconnect-display-timeout' to `erc-auto-reconnect-display-timeout'. (erc-message-english-s471, erc-message-english-s473): New variables, format templates for JOIN rejection messages. * test/lisp/erc/erc-scenarios-base-buffer-display.el (erc-scenarios-base-buffer-display--defwin-recbury-intbuf, erc-scenarios-base-buffer-display--defwino-recbury-intbuf, erc-scenarios-base-buffer-display--count-reset-timeout): Use preferred name `erc-auto-reconnect-display' for `erc-reconnect-display'. * test/lisp/erc/erc-scenarios-join-display-context.el: New file. * test/lisp/erc/erc-tests.el (erc--initialize-markers): Fix unrealistic call to `erc-open'. (erc-setup-buffer--custom-action): New test. (erc-select-read-args, erc-tls, erc--interactive, erc-server-select): Expect new environment binding for `erc--display-context'. * test/lisp/erc/resources/join/buffer-display/mode-context.eld: New file. (Bug#62833) --- doc/misc/erc.texi | 181 +++++++++++++++ etc/ERC-NEWS | 16 +- lisp/erc/erc-backend.el | 36 ++- lisp/erc/erc-join.el | 39 +++- lisp/erc/erc.el | 212 +++++++++++++----- .../erc/erc-scenarios-base-buffer-display.el | 28 +-- .../erc/erc-scenarios-join-display-context.el | 66 ++++++ test/lisp/erc/erc-tests.el | 90 +++++++- .../join/buffer-display/mode-context.eld | 38 ++++ 9 files changed, 620 insertions(+), 86 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-join-display-context.el create mode 100644 test/lisp/erc/resources/join/buffer-display/mode-context.eld diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index ddfdb2e2b64..00aa34e51fa 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -613,6 +613,7 @@ Integrations * URL:: Opening IRC URLs in ERC. * SOCKS:: Connecting to IRC with a SOCKS proxy. * auth-source:: Retrieving auth-source entries with ERC. +* display-buffer:: Controlling how ERC displays buffers. @end detailmenu @end menu @@ -1226,6 +1227,7 @@ stuff, to the current ERC buffer." @menu * auth-source:: Retrieving auth-source entries with ERC. +* display-buffer:: Controlling how ERC displays buffers. @end menu @anchor{URL} @@ -1468,6 +1470,185 @@ required by certain channels you join. When modifying a traditional @samp{user} field (for example, @samp{login "#fsf"}, in netrc's case). The actual key goes in the @samp{password} (or @samp{secret}) field. +@node display-buffer +@subsection display-buffer +@cindex display-buffer + +ERC supports the ``action'' interface used by @code{display-buffer} +and friends from @file{window.el}. @xref{Displaying Buffers,,, elisp, +Emacs Lisp}, for specifics. When ERC displays a new or +``reassociated'' buffer, it consults its various buffer-display +options, such as @code{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 @code{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 +@code{erc-interactive-display}, the precise context varies. For +example, you might be opening a query buffer with the command +@kbd{/QUERY bob @key{RET}} or joining a new channel with @kbd{/JOIN +#chan @key{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 ``@code{display-buffer}-like'' function that accepts a +@var{buffer} and an @var{action} argument. + +@subsubheading Examples + +In this first example, a user-provided buffer-display function +displays new server buffers in the current window when issuing an +@kbd{M-x erc-tls @key{RET}} and in a split window for all other +interactve contexts covered by the option +@code{erc-interactive-display}, like clicking an @samp{irc://}-style +@acronym{URL} (@pxref{URL}). + +@lisp +(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) +@end lisp + +@noindent +Observe that ERC supplies the names of buffer-display options as +@var{action} alist keys and pairs them with contextual constants, like +the symbols @samp{erc-tls} or @samp{url}, the full lineup of which are +listed below. + +In this second example, the user writes three predicates that somewhat +resemble the ``@code{display-buffer}-like'' function above. These too +look for @var{action} alist keys sharing the names of buffer-display +options (and, in one case, a module's minor mode). + +@lisp +(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 (memq (cdr (assq 'erc-buffer-display alist)) 'JOIN) + (member (erc-default-target) '("#emacs" "#fsf"))))) +@end lisp + +@noindent +You'll notice we ignore the @var{buffer} parameter of these predicates +because ERC ensures that @var{buffer} is already current (which is why +we can freely call @code{erc-default-target}). Note also that we +cheat a little by treating the @var{action} parameter like an alist +when it's really a cons of one or more functions and an alist. + +@noindent +To complement our predicates, we set all three buffer-display options +referenced in their @var{action}-alist lookups to +@code{display-buffer}. This tells ERC to defer to that function in +the display contexts covered by these options. + +@lisp +(setopt erc-buffer-display #'display-buffer + erc-interactive-display #'display-buffer + erc-receive-query-display #'display-buffer + ;; + erc-auto-reconnect-display 'bury) +@end lisp + +@noindent +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 @code{bury-buffer}.) + +Finally, we compose our predicates into @code{buffer-match-p} +conditions and pair them with various well known @code{display-buffer} +action functions and action-alist members. + +@lisp +(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)))) +@end lisp + +@noindent +Of course, we could just as well set our buffer-display options to one +or more homespun functions instead of bothering with +@code{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 @file{init.el}. + +@subsubheading Action alist items + +@table @asis +@item Option-based keys: +All keys are symbols, as are values, unless otherwise noted. + +@itemize @bullet +@item @code{erc-buffer-display} +@itemize @minus +@item @samp{JOIN} +@item @samp{NOTICE} +@item @samp{PRIVMSG} +@item @samp{erc} (entry point called non-interactively) +@item @samp{erc-tls} +@end itemize + +@item @code{erc-interactive-display} +@itemize @minus +@item @samp{/QUERY} +@item @samp{/JOIN} +@item @samp{/RECONNECT} +@item @samp{url} (hyperlink clicked) +@item @samp{erc} (entry point called interactively) +@item @samp{erc-tls} +@end itemize + +@item @code{erc-receive-query-display} +@itemize @minus +@item @samp{NOTICE} +@item @samp{PRIVMSG} +@end itemize + +@item @code{erc-auto-reconnect-display} +@itemize @minus +@item something non-@code{nil} +@end itemize +@end itemize + +@item Module-based (minor-mode) keys: + +@itemize @bullet +@item @code{erc-autojoin-mode} +@itemize @minus +@item channel name as a string, e.g., @code{"#chan"} +@end itemize +@end itemize +@end table @node Options @section Options diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 9c94f68ce27..64d73ef7481 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 @@ -56,7 +56,19 @@ reported as being difficult to discover and remember. When the latter option (now known as 'erc-receive-query-display') is nil, ERC uses 'erc-join-buffer' in its place, much like it does for 'erc-interactive-display'. The old nil behavior can still be gotten -via the new compatibility flag 'erc-receive-query-display-defer'. +via the new compatibility flag 'erc-receive-query-display-defer'. The +relatively new option 'erc-reconnect-display' has likewise been +renamed, this time for clarity, to 'erc-auto-reconnect-display'. + +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 function to +exercise full control over nearly all buffer-display related +decisions. See the newly expanded doc strings of 'erc-buffer-display' +and friends, as well as Info node '(erc) display-buffer', 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 diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index f1b51f9234a..363509d17fa 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -101,6 +101,8 @@ (eval-when-compile (require 'cl-lib)) (require 'erc-common) +(defvar erc--called-as-input-p) +(defvar erc--display-context) (defvar erc--target) (defvar erc--user-from-nick-function) (defvar erc-channel-list) @@ -304,7 +306,7 @@ function `erc-server-process-alive' instead.") "Timer that resets `erc--server-last-reconnect-count' to zero. Becomes non-nil in all server buffers when an IRC connection is first \"established\" and carries out its duties -`erc-reconnect-display-timeout' seconds later.") +`erc-auto-reconnect-display-timeout' seconds later.") (defvar-local erc--server-last-reconnect-count 0 "Snapshot of reconnect count when the connection was established.") @@ -957,7 +959,7 @@ EVENT is the message received from the closed connection process." (erc--server-last-reconnect-display-reset (current-buffer))) (defun erc--server-last-reconnect-display-reset (buffer) - "Deactivate `erc-reconnect-display'." + "Deactivate `erc-auto-reconnect-display'." (when (buffer-live-p buffer) (with-current-buffer buffer (when erc--server-reconnect-display-timer @@ -1684,6 +1686,12 @@ add things to `%s' instead." parsed 'notice 'active 'INVITE ?n nick ?u login ?h host ?c chnl))))) +(cl-defmethod erc--server-determine-join-display-context (_channel alist) + "Determine `erc--display-context' for JOINs." + (if (assq 'erc-buffer-display alist) + alist + `((erc-buffer-display . JOIN) ,@alist))) + (define-erc-response-handler (JOIN) "Handle join messages." nil @@ -1698,7 +1706,11 @@ add things to `%s' instead." (let* ((str (cond ;; If I have joined a channel ((erc-current-nick-p nick) - (when (setq buffer (erc--open-target chnl)) + (let ((erc--display-context + (erc--server-determine-join-display-context + chnl erc--display-context))) + (setq buffer (erc--open-target chnl))) + (when buffer (set-buffer buffer) (with-suppressed-warnings ((obsolete erc-add-default-channel)) @@ -1887,6 +1899,8 @@ add things to `%s' instead." (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) @@ -1901,6 +1915,8 @@ add things to `%s' instead." (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 @@ -2486,6 +2502,17 @@ See `erc-display-server-message'." nil parsed (erc-response.contents parsed))) +(define-erc-response-handler (471) + "ERR_CHANNELISFULL: channel full." nil + (erc-display-message parsed '(notice error) nil 's471 + ?c (cadr (erc-response.command-args parsed)) + ?s (erc-response.contents parsed))) + +(define-erc-response-handler (473) + "ERR_INVITEONLYCHAN: channel invitation only." nil + (erc-display-message parsed '(notice error) nil 's473 + ?c (cadr (erc-response.command-args parsed)))) + (define-erc-response-handler (474) "Banned from channel errors." nil (erc-display-message parsed '(notice error) nil @@ -2499,6 +2526,7 @@ See `erc-display-server-message'." nil ?c (cadr (erc-response.command-args parsed))) (when erc-prompt-for-channel-key (let ((channel (cadr (erc-response.command-args parsed))) + (erc--called-as-input-p t) (key (read-from-minibuffer (format "Channel %s is mode +k. Enter key (RET to cancel): " (cadr (erc-response.command-args parsed)))))) @@ -2567,7 +2595,7 @@ See `erc-display-error-notice'." nil ;; 200 201 202 203 204 205 206 208 209 211 212 213 ;; 214 215 216 217 218 219 241 242 243 244 249 261 ;; 262 302 342 351 407 409 411 413 414 415 -;; 423 424 436 441 443 444 467 471 472 473 KILL) +;; 423 424 436 441 443 444 467 472 KILL) ;; nil nil ;; (ignore proc parsed)) diff --git a/lisp/erc/erc-join.el b/lisp/erc/erc-join.el index 45cfd565f89..2a57e77a622 100644 --- a/lisp/erc/erc-join.el +++ b/lisp/erc/erc-join.el @@ -44,11 +44,23 @@ ((add-hook 'erc-after-connect #'erc-autojoin-channels) (add-hook 'erc-nickserv-identified-hook #'erc-autojoin-after-ident) (add-hook 'erc-server-JOIN-functions #'erc-autojoin-add) - (add-hook 'erc-server-PART-functions #'erc-autojoin-remove)) + (add-hook 'erc-server-PART-functions #'erc-autojoin-remove) + (add-hook 'erc-server-405-functions #'erc-join--remove-requested-channel) + (add-hook 'erc-server-471-functions #'erc-join--remove-requested-channel) + (add-hook 'erc-server-473-functions #'erc-join--remove-requested-channel) + (add-hook 'erc-server-474-functions #'erc-join--remove-requested-channel) + (add-hook 'erc-server-475-functions #'erc-join--remove-requested-channel)) ((remove-hook 'erc-after-connect #'erc-autojoin-channels) (remove-hook 'erc-nickserv-identified-hook #'erc-autojoin-after-ident) (remove-hook 'erc-server-JOIN-functions #'erc-autojoin-add) - (remove-hook 'erc-server-PART-functions #'erc-autojoin-remove))) + (remove-hook 'erc-server-PART-functions #'erc-autojoin-remove) + (remove-hook 'erc-server-405-functions #'erc-join--remove-requested-channel) + (remove-hook 'erc-server-471-functions #'erc-join--remove-requested-channel) + (remove-hook 'erc-server-473-functions #'erc-join--remove-requested-channel) + (remove-hook 'erc-server-474-functions #'erc-join--remove-requested-channel) + (remove-hook 'erc-server-475-functions #'erc-join--remove-requested-channel) + (erc-buffer-do (lambda () + (kill-local-variable 'erc-join--requested-channels))))) (defcustom erc-autojoin-channels-alist nil "Alist of channels to autojoin on IRC networks. @@ -138,6 +150,28 @@ network or a network ID). Return nil on failure." (string-match-p candidate (or erc-server-announced-name erc-session-server))))) +(defvar-local erc-join--requested-channels nil + "List of channels for which an outgoing JOIN was sent.") + +;; Assume users will update their `erc-autojoin-channels-alist' when +;; encountering errors, like a 475 ERR_BADCHANNELKEY. +(defun erc-join--remove-requested-channel (_ parsed) + "Remove channel from `erc-join--requested-channels'." + (when-let ((channel (cadr (erc-response.command-args parsed))) + ((member channel erc-join--requested-channels))) + (setq erc-join--requested-channels + (delete channel erc-join--requested-channels))) + nil) + +(cl-defmethod erc--server-determine-join-display-context + (channel alist &context (erc-autojoin-mode (eql t))) + "Add item to `erc-display-context' ALIST if CHANNEL was autojoined." + (when (member channel erc-join--requested-channels) + (setq erc-join--requested-channels + (delete channel erc-join--requested-channels)) + (push (cons 'erc-autojoin-mode channel) alist)) + (cl-call-next-method channel alist)) + (defun erc-autojoin--join () ;; This is called in the server buffer (pcase-dolist (`(,name . ,channels) erc-autojoin-channels-alist) @@ -146,6 +180,7 @@ network or a network ID). Return nil on failure." (let ((buf (erc-get-buffer chan erc-server-process))) (unless (and buf (with-current-buffer buf (erc--current-buffer-joined-p))) + (push chan erc-join--requested-channels) (erc-server-join-channel nil chan))))))) (defun erc-autojoin-after-ident (_network _nick) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index f2ea69f6bba..d3bec98e14c 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1553,9 +1553,26 @@ Defaults to the server buffer." "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 ERC's baseline, \"catch-all\" buffer-display +behavior. It takes a backseat to more specific options, like +`erc-interactive-display', `erc-auto-reconnect-display', and +`erc-receive-query-display'. The available choices are: @@ -1564,17 +1581,34 @@ The available choices are: `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 such as user options, like +`erc-buffer-display', or module minor modes, like +`erc-autojoin-mode'. Values are non-nil 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 set this +option to `bury' and instead call DISPLAY-FUNCTION directly +on (server) buffers returned by these entry points because the +context leading to their creation is plainly obvious. For +additional details, see the Info node `(erc) display-buffer'. + +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 @@ -1583,38 +1617,58 @@ This affects commands like /QUERY and /JOIN when issued 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', `/RECONNECT', `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. See Info node `(erc) +display-buffer' for more." :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))) - -(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." + :type erc--buffer-display-choices) + +(defvaralias 'erc-reconnect-display 'erc-auto-reconnect-display) +(defcustom erc-auto-reconnect-display nil + "How to display a channel buffer when automatically reconnecting. +ERC ignores this option when a user issues a /RECONNECT or +successfully reinvokes `erc-tls' with similar arguments to those +from the prior connection. See `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-auto-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))) - -(defcustom erc-reconnect-display-timeout 10 - "Duration `erc-reconnect-display' remains active. + :type erc--buffer-display-choices) + +(defcustom erc-auto-reconnect-display-timeout 10 + "Duration `erc-auto-reconnect-display' remains active. The countdown starts on MOTD and is canceled early by any \"slash\" command." + :package-version '(ERC . "5.6") ; FIXME sync on release :type 'integer :group 'erc-buffers) +(defcustom erc-reconnect-display-server-buffers nil + "Apply buffer-display options to server buffers when reconnecting. +By default, ERC does not consider `erc-auto-reconnect-display' +for server buffers when automatically reconnecting, nor does it +consider `erc-interactive-display' when users issue a /RECONNECT. +Enabling this tells ERC to always display server buffers +according to those options." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type 'boolean + :group 'erc-buffers) + (defcustom erc-frame-alist nil "Alist of frame parameters for creating erc frames. A value of nil means to use `default-frame-alist'." @@ -1824,9 +1878,8 @@ server connection, or nil which means all open connections." (defalias 'erc-buffer-do 'erc-buffer-filter "Call FUNCTION in all ERC buffers or only those for PROC. -Expect users to prefer this alias to `erc-buffer-filter' in cases -where the latter would only be called for effect and its return -value thrown away. +Expect to be preferred over `erc-buffer-filter' in cases where +the return value goes unused. \(fn FUNCTION &optional PROC)") @@ -2094,12 +2147,43 @@ anything about the dependency's implementation.") (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 +buffer-display options, like `erc-auto-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. This is intended as a crutch +for non-user third-party code that might be slow to adopt the +`display-buffer' function variant available to all buffer-display +options starting in ERC 5.6. Users with rare requirements, like +wanting to change the window buffer to something other than the +one being processed, should see the Info node `(erc) +display-buffer'.") +(make-obsolete 'erc-show-already-displayed-buffer + "non-nil behavior to be made permanent" "30.1") + +(defvar-local erc--display-buffer-overriding-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)) + (or erc-auto-reconnect-display erc-join-buffer)) + ((and (pred functionp) disp-fn (let context erc--display-context)) + (unless (zerop erc--server-last-reconnect-count) + (push '(erc-auto-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,13 +2376,18 @@ Returns the buffer for the given server or channel." (erc-update-mode-line)) ;; Now display the buffer in a window as per user wishes. - (unless (eq buffer old-buffer) + (when (eq buffer old-buffer) (cl-assert (and connect (not target)))) + (unless (and (not erc-reconnect-display-server-buffers) + (eq buffer old-buffer)) (when erc-log-p ;; 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-overriding-action + display-buffer-overriding-action))) + (erc-setup-buffer buffer) + (run-hooks 'erc--setup-buffer-hook))) buffer)) @@ -2410,6 +2499,8 @@ With prefix arg, also prompt for user and full name." 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)) @@ -2471,7 +2562,12 @@ for the values of the other parameters. 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))) @@ -2536,8 +2632,11 @@ CLIENT-CERTIFICATE, this parameter cannot be specified 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 @@ -2546,6 +2645,9 @@ interactively. (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))) @@ -3769,7 +3871,10 @@ were most recently invited. See also `invitation'." (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)))) @@ -4153,7 +4258,9 @@ on the value of `erc-interactive-display'." ;; 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)))) @@ -4273,6 +4380,9 @@ the message given by REASON." (defun erc--cmd-reconnect () (let ((buffer (erc-server-buffer)) + (erc-join-buffer erc-interactive-display) + (erc--display-context `((erc-interactive-display . /RECONNECT) + ,@erc--display-context)) (process nil)) (unless (buffer-live-p buffer) (setq buffer (current-buffer))) @@ -4937,13 +5047,7 @@ compatibility flag `erc-receive-query-display-defer' to nil. Use :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'. @@ -5389,7 +5493,7 @@ Set user modes and run `erc-after-connect' hook." (setq erc--server-last-reconnect-count erc-server-reconnect-count erc-server-reconnect-count 0) (setq erc--server-reconnect-display-timer - (run-at-time erc-reconnect-display-timeout nil + (run-at-time erc-auto-reconnect-display-timeout nil #'erc--server-last-reconnect-display-reset (current-buffer))) (add-hook 'erc-disconnected-hook @@ -7769,6 +7873,8 @@ All windows are opened in the current frame." (s463 . "Your host isn't among the privileged") (s464 . "Password incorrect") (s465 . "You are banned from this server") + (s471 . "Max occupancy for channel %c exceeded: %s") + (s473 . "Channel %c is invitation only") (s474 . "You can't join %c because you're banned (+b)") (s475 . "You must specify the correct channel key (+k) to join %c") (s481 . "Permission Denied - You're not an IRC operator") @@ -7970,6 +8076,8 @@ Beginning with ERC 5.5, new connections require human intervention. 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-scenarios-base-buffer-display.el b/test/lisp/erc/erc-scenarios-base-buffer-display.el index 548ad00e2d9..df292a8c113 100644 --- a/test/lisp/erc/erc-scenarios-base-buffer-display.el +++ b/test/lisp/erc/erc-scenarios-base-buffer-display.el @@ -26,8 +26,8 @@ (eval-when-compile (require 'erc-join)) -;; These first couple `erc-reconnect-display' tests used to live in -;; erc-scenarios-base-reconnect but have since been renamed. +;; These first couple `erc-auto-reconnect-display' tests used to live +;; in erc-scenarios-base-reconnect but have since been renamed. (defun erc-scenarios-base-buffer-display--reconnect-common (assert-server assert-chan assert-rest) @@ -80,11 +80,11 @@ :tags '(:expensive-test) (should (eq erc-buffer-display 'bury)) (should (eq erc-interactive-display 'window)) - (should-not erc-reconnect-display) + (should-not erc-auto-reconnect-display) (let ((erc-buffer-display 'window) (erc-interactive-display 'buffer) - (erc-reconnect-display 'bury)) + (erc-auto-reconnect-display 'bury)) (erc-scenarios-base-buffer-display--reconnect-common @@ -104,7 +104,7 @@ ;; A manual /JOIN command tells ERC we're done auto-reconnecting (with-current-buffer "FooNet" (erc-scenarios-common-say "/JOIN #spam")) - (ert-info ("#spam ignores `erc-reconnect-display'") + (ert-info ("#spam ignores `erc-auto-reconnect-display'") ;; Uses `erc-interactive-display' instead. (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam")) (should (eq (window-buffer) (get-buffer "#spam"))) @@ -115,10 +115,10 @@ :tags '(:expensive-test) (should (eq erc-buffer-display 'bury)) (should (eq erc-interactive-display 'window)) - (should-not erc-reconnect-display) + (should-not erc-auto-reconnect-display) (let ((erc-buffer-display 'window-noselect) - (erc-reconnect-display 'bury) + (erc-auto-reconnect-display 'bury) (erc-interactive-display 'buffer)) (erc-scenarios-base-buffer-display--reconnect-common @@ -155,7 +155,7 @@ (should (eq (window-buffer) (get-buffer "bob"))) (should (frame-root-window-p (selected-window))))) - (ert-info ("Newly joined chan ignores `erc-reconnect-display'") + (ert-info ("Newly joined chan ignores `erc-auto-reconnect-display'") (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam")) (should (eq (window-buffer) (get-buffer "bob"))) (should-not (frame-root-window-p (selected-window))) @@ -165,13 +165,13 @@ :tags '(:expensive-test) (should (eq erc-buffer-display 'bury)) (should (eq erc-interactive-display 'window)) - (should (eq erc-reconnect-display-timeout 10)) - (should-not erc-reconnect-display) + (should (eq erc-auto-reconnect-display-timeout 10)) + (should-not erc-auto-reconnect-display) (let ((erc-buffer-display 'window-noselect) - (erc-reconnect-display 'bury) + (erc-auto-reconnect-display 'bury) (erc-interactive-display 'buffer) - (erc-reconnect-display-timeout 0.5)) + (erc-auto-reconnect-display-timeout 0.5)) (erc-scenarios-base-buffer-display--reconnect-common #'ignore #'ignore ; These two are identical to the previous test. @@ -188,10 +188,10 @@ (erc-d-t-wait-for 1 (null erc--server-reconnect-display-timer)) (erc-cmd-JOIN "#spam"))) - (ert-info ("Newly joined chan ignores `erc-reconnect-display'") + (ert-info ("Newly joined chan ignores `erc-auto-reconnect-display'") (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam")) (should (eq (window-buffer) (messages-buffer))) - ;; If `erc-reconnect-display-timeout' were left alone, this + ;; If `erc-auto-reconnect-display-timeout' were left alone, this ;; would be (frame-root-window-p #). (should-not (frame-root-window-p (selected-window))) (should (eq (current-buffer) (window-buffer (next-window)))))))))) diff --git a/test/lisp/erc/erc-scenarios-join-display-context.el b/test/lisp/erc/erc-scenarios-join-display-context.el new file mode 100644 index 00000000000..32b782d2af1 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-join-display-context.el @@ -0,0 +1,66 @@ +;;; erc-scenarios-join-display-context.el --- buffer-display autojoin ctx -*- lexical-binding: t -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(ert-deftest erc-scenarios-join-display-context--errors () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "join/buffer-display") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'mode-context)) + (port (process-contact dumb-server :service)) + (erc-buffer-display (lambda (buf action) + (when (equal + (alist-get 'erc-autojoin-mode action) + "#chan") + (pop-to-buffer buf)))) + (erc-autojoin-channels-alist '((foonet "#chan" "#spam" "#foo"))) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect without password") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :full-name "tester") + (should (string= (buffer-name) (format "127.0.0.1:%d" port))) + ;; FIXME test for effect rather than inspecting interval variables. + (erc-d-t-wait-for 10 (equal erc-join--requested-channels + '("#foo" "#spam" "#chan"))) + (funcall expect 10 "Max occupancy for channel #spam exceeded") + (funcall expect 10 "Channel #foo is invitation only"))) + + (ert-info ("New #chan buffer displayed in new window") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (should (eq (window-buffer) (current-buffer))) + (funcall expect 10 "#chan was created on"))) + + ;; FIXME find a less dishonest way to do this than inspecting + ;; interval variables. + (ert-info ("Ensure channels no longer tracked") + (should-not erc-join--requested-channels)))) + +;;; erc-scenarios-join-display-context.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index fed25056b42..0e4ea1b1db6 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -427,8 +427,9 @@ (should (looking-at-p (regexp-quote "*** Welcome")))) (ert-info ("Reconnect") - (erc-open "localhost" 6667 "tester" "Tester" nil - "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (erc-server-buffer) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil)) (should-not (get-buffer "#chan<2>"))) (ert-info ("Existing prompt respected") @@ -512,6 +513,50 @@ (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-auto-reconnect-display' + (let* ((erc--server-last-reconnect-count 1) + (erc--display-context '((erc-buffer-display . 1))) + (erc-auto-reconnect-display 'erc--test-fun)) + (erc-setup-buffer mbuf) + (should (equal `(erc--test-fun ,mbuf + (nil (erc-auto-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 "_`")) @@ -1537,14 +1582,18 @@ (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 @@ -1624,6 +1673,7 @@ ((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) @@ -1636,6 +1686,7 @@ 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") @@ -1652,6 +1703,7 @@ "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 @@ -1671,6 +1723,7 @@ "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") @@ -1681,6 +1734,8 @@ 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") @@ -1691,6 +1746,8 @@ 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 @@ -1702,6 +1759,7 @@ 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)) @@ -1715,6 +1773,8 @@ '("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))))))) @@ -1729,6 +1789,7 @@ ((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) @@ -1741,8 +1802,9 @@ '("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" @@ -1752,6 +1814,7 @@ 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)))))))) @@ -1762,6 +1825,7 @@ ((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) @@ -1776,6 +1840,7 @@ 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-tls-stream))))) (ert-info ("Selects entry that doesn't support TLS") @@ -1787,6 +1852,7 @@ 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)))))))) diff --git a/test/lisp/erc/resources/join/buffer-display/mode-context.eld b/test/lisp/erc/resources/join/buffer-display/mode-context.eld new file mode 100644 index 00000000000..6ebbdc7e824 --- /dev/null +++ b/test/lisp/erc/resources/join/buffer-display/mode-context.eld @@ -0,0 +1,38 @@ +;; -*- mode: lisp-data; -*- +((nick 1 "NICK tester")) +((user 1 "USER user 0 * :tester") + (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") + (0.01 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version ergo-v2.8.0") + (0.00 ":irc.foonet.org 003 tester :This server was created Tue, 24 May 2022 05:28:42 UTC") + (0.00 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.8.0 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv") + (0.00 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this server") + (0.01 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server") + (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this server") + (0.00 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 server(s)") + (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online") + (0.00 ":irc.foonet.org 253 tester 0 :unregistered connections") + (0.00 ":irc.foonet.org 254 tester 2 :channels formed") + (0.00 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers") + (0.00 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4") + (0.00 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4") + (0.00 ":irc.foonet.org 422 tester :MOTD File is missing")) + +((mode 6 "MODE tester +i") + (0.00 ":irc.foonet.org 221 tester +i") + (0.00 ":irc.foonet.org NOTICE tester :This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect.") + (0.02 ":irc.foonet.org 221 tester +i")) + +((join-chan 10 "JOIN #chan") + (0.03 ":tester!~u@w9rfqveugz722.irc JOIN #chan")) + +((~mode-chan 10 "MODE #chan") + (0.01 ":irc.foonet.org 353 tester = #chan :@tester") + (0.00 ":irc.foonet.org 366 tester #chan :End of NAMES list") + (0.01 ":irc.foonet.org 324 tester #chan +nt") + (0.03 ":irc.foonet.org 329 tester #chan 1653370308")) + +((~join-spam 10 "JOIN #spam") + (0.03 ":irc.foonet.org 471 tester #spam :Cannot join channel (+l)")) + +((~join-foo 10 "JOIN #foo") + (0.03 ":irc.foonet.org 473 tester #foo :Cannot join channel (+i)")) -- 2.39.2