>From cd4222ba2636bed57c4fe27b25b0e840f376c304 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Sun, 26 Nov 2023 18:24:48 -0800 Subject: [PATCH 11/11] [5.6] Use templates for formatting chat messages in ERC * doc/misc/erc.texi: Replace option `erc-format-nick-function' with `erc-show-speaker-membership-status'. * etc/ERC-NEWS: Mention shift to template-based speaker formatting. * lisp/erc/erc-backend.el (erc--determine-speaker-message-format-args): Add forward-declaration. (erc--statusmsg-target): New utility function for detecting whether the current target is status-prefixed. (erc-current-message-catalog): Move here from lisp/erc/erc.el. (erc--message-speaker-catalog): New variable. (erc--speaker-status-prefix-wanted-p): New variable specifically for the function `erc-format-@nick' to signal it wants status-prefixes prepended to the displayed nick. (erc-server-PRIVMSG): Bind `erc--msg-prop-overrides' and `erc-current-message-catalog'. Detect status messages and inform formatting function of verdict. Call `erc--determine-speaker-message-format-args' instead of `erc-format-privmessage' when possible, and pass a "catalog key" instead of a pre-formatted message to `erc-display-message'. * lisp/erc/erc-common.el (erc--ctcp-response): New "subsclass" of `erc-response' for smuggling extra information to CTCP query handlers in a mostly backwards-compatible way. * lisp/erc/erc-dcc.el (erc-dcc-chat-filter): Add `erc--spkr' property and `erc-speaker' property even though these chat buffers are not `erc-mode' buffers. * lisp/erc/erc-fill.el (erc-fill--wrap-continued-message-p): Rework to look for `erc--spkr' `erc--msg' combinations as indicators of message "mergeability". (erc-fill--wrap-rejigger-region): Remove reference to `erc-stamp-type'. Instead use the `erc--msg' property combined with the `erc-timestamp' field to detect date stamps because, at the moment, all are left-sided. * lisp/erc/erc-stamp.el (erc-stamp--propertize-left-date-stamp): Don't add `erc-stamp-type' property. * lisp/erc/erc.el (erc--msg-props): Revise definition of `erc--msg', removing ambiguous `msg' value and replacing with catalog keys, `erc-display-message' "type" parameters, and `unknown'. (erc--use-language-catalog-for-ctcp-action-p): New variable, a compatibility switch to help transition from the `ACTION' entry of the language catalog to the corresponding `ctcp-action' entries of the new `speaker' catalog. (erc--send-action-display): Restore pre-5.6 behavior when compatibility flag is enabled. Otherwise, use new `speaker' template for formatting inserted message. (erc-display-message): Don't add null-valued overrides. (erc--send-message-external): Overhaul to behave more faithfully in mimicking a line submitted at the prompt of the current target buffer. (erc--own-property-names): Remove `erc-stamp-type'. (erc-ensure-target-buffer-on-privmsg): Add new choice variant and slightly change meaning of default. (erc-format-nick-function, erc-speaker-from-channel-member-function): Alias to latter, and redefine purpose slightly. (erc--message-speaker-statusmsg, erc--message-speaker-statusmsg-input, erc--message-speaker-input, erc--message-speaker-input-chan-privmsg, erc--message-speaker-input-chan-notice, erc--message-speaker-input-query-privmsg, erc--message-speaker-input-query-notice, erc--message-speaker-chan-privmsg, erc--message-speaker-query-privmsg, erc--message-speaker-chan-notice, erc--message-speaker-query-notice, erc--message-speaker-ctcp-action, erc--message-speaker-ctcp-action-input, erc--message-speaker-ctcp-action-statusmsg, erc--message-speaker-ctcp-action-input-statusmsg): New variables for new `speaker' format-template catalog. (erc--speakerize-nick): New helper function. (erc--determine-speaker-message-format-args): New function to find the appropriate format key from various contextual parameters. Could become the default of a function-valued variable for internal use. (erc-show-speaker-membership-status): New option. (erc-format-nick-function, erc-determine-speaker-from-user): Rename former to latter and obsolete the old name. (erc-format-nick, erc-determine-speaker-from-user): Rename former to latter and obsolete old name. (erc-format-@nick): Deprecate and adapt for use with new template-based paradigm. (erc-format-my-nick): Move `erc-speaker' text prop toward head of list. (erc--format-speaker-input-message): New function to replace `erc-format-my-nick' in-tree. (erc-process-ctcp-query): Don't bind `erc--msg' to `msg'. Instead, rely on `erc-display-message' to set it to the current template key. (erc-ctcp-query-ACTION): Prefer using formatting template, but attempt to supply pre-5.6 behavior when compatibility flag enabled. (erc-display-msg): Use `erc--format-speaker-input-message' instead of `erc-format-my-nick'. (erc-current-message-catalog): Move to erc-backend.el. * test/lisp/erc/erc-scenarios-stamp.el (erc-scenarios-stamp--left/display-margin-mode): Expect format catalog key instead of unhelpful `msg' as value of `erc--msg' prop. * test/lisp/erc/erc-tests.el (erc-message): Render format template in mock function and expect string in assertions. (erc-tests--format-privmessage): New function, a helper for the following test. (erc-format-privmessage, erc--determine-message-format-args): Rename former to latter and suppress deprecation warning. (erc--determine-speaker-message-format-args/queries, erc--determine-speaker-message-format-args/queries-as-channel): New tests. (erc-tests--format-my-nick): New helper function for the following test. (erc--format-speaker-input-message): New test. * test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld: Update. * test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld: Update. * test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld: Update. --- doc/misc/erc.texi | 11 +- etc/ERC-NEWS | 53 +++ lisp/erc/erc-backend.el | 87 +++-- lisp/erc/erc-common.el | 17 + lisp/erc/erc-dcc.el | 6 +- lisp/erc/erc-fill.el | 69 ++-- lisp/erc/erc-stamp.el | 3 +- lisp/erc/erc.el | 366 +++++++++++++++--- test/lisp/erc/erc-scenarios-stamp.el | 2 +- test/lisp/erc/erc-tests.el | 231 +++++++++-- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../merge-wrap-indicator-post-01.eld | 2 +- .../snapshots/merge-wrap-indicator-pre-01.eld | 2 +- 13 files changed, 687 insertions(+), 164 deletions(-) diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index d7260ffa329..0eb2ae69aef 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -918,16 +918,11 @@ Connecting other nicks are tried in the list order. @end defopt -@defopt erc-format-nick-function -A function to format a nickname for message display - -You can set this to @code{erc-format-@@nick} to display user mode prefix +@defopt erc-show-speaker-membership-status +A boolean for including a channel member's @dfn{status prefix} in +their display name when they speak. @end defopt -@example -(setq erc-format-nick-function 'erc-format-@@nick) -@end example - @defopt erc-nick-uniquifier The string to append to the nick if it is already in use. @end defopt diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 4fdfe7a9dcb..56d62cd63bd 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -275,6 +275,26 @@ buffers. In channels, it's grown to include all letters and their possibly truncated arguments, with the exception of stateful list modes, like "b". +** In-buffer "status messages" are now a thing. +The ancient option 'erc-ensure-target-buffer-on-privmsg' has been +repurposed slightly to express a third state denoted by the symbol +'status', which tells ERC to revert to the old default behavior in +which separate, "pseudo" target buffers for status-prefixed conversing +co-exist alongside actual target buffers. Instead of this awkward +arrangement, ERC now acts like other clients by default and inserts +so-called "status messages" in situ, right next to other messages. +Similar insertion-routing behavior now also applies to CTCP ACTIONs +directed at status-prefixed channels. Unfortunately, outgoing "/msg +@#chan hi" messages aren't yet shown in the same fashion, but the +groundwork has been laid, making such an addition almost trivial. + +** An easier way get channel-membership prefixes on speakers. +The option 'erc-format-@nick' has been deprecated in favor of the new +boolean option 'erc-show-speaker-membership-status', a simple switch +to enable the displaying of status prefixes on the speaker nicks of +incoming chat messages. Prefixes on your speaker nick for outgoing +chat messages continue to always be present. + ** Miscellaneous UX changes. Some minor quality-of-life niceties have finally made their way to ERC. For example, fool visibility has become togglable with the new @@ -526,6 +546,39 @@ The functions 'erc-define-catalog-entry' and 'erc-define-catalog' have been deprecated in favor of 'erc-define-message-format-catalog', a new macro for defining template "catalogs" at the top level of libraries. +*** Interface for determining display names renamed. +The option 'erc-format-nick-function' has been renamed to +'erc-speaker-from-channel-member-function' to better reflect its +actual role. So too has the related function 'erc-format-nick', which +is now 'erc-determine-speaker-from user'. + +*** A template-based approach to formatting inserted chat messages. +Predicting and influencing how ERC formats messages containing a +leading "" has never been straightforward. The characters +bracketing the speaker and the faces used for each component have +always been hard-coded, with 'erc-format-query-as-channel-p' being the +only knob of any consequence. With this release, ERC begins its +transition to a unified formatting paradigm that builds upon the +already familiar "language catalog" templating system. Using a +separate "speaker catalog" keyed by contextual symbols, like +'query-privmsg', ERC (and eventually everyone) will more easily be +able to influence how inserted messages take shape in buffers. + +*** New formatting templates for inserted CTCP ACTION messages. +In 5.5 and earlier, ERC displayed outgoing CTCP ACTION messages in +'erc-input-face' alone (before buttonizing). Incoming ACTION messages +mirrored this, except with 'erc-action-face' throughout. Going +forward, inserted outgoing "/ME" messages will also incorporate +'erc-action-face', only underneath 'erc-input-face', with +'erc-my-nick-face' sitting atop both in the bracketed "speaker" +(nickname) portion (again, pre-buttonizing). This new behavior +sidesteps the traditional format template 'erc-message-english-ACTION' +from the default "language catalog" in favor of an entry from the new +internal "speaker catalog". Users needing to access the old behavior +can do so by tweaking the latter two variables or by toggling a +provided compatibility switch. See source code around the function +'erc-send-action' for details. + *** Miscellaneous changes Two helper macros from GNU ELPA's Compat library are now available to third-party modules as 'erc-compat-call' and 'erc-compat-function'. diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 0f6f7e2d4c3..438d7e0c00a 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -142,7 +142,6 @@ erc-verbose-server-ping (declare-function erc-display-server-message "erc" (_proc parsed)) (declare-function erc-emacs-time-to-erc-time "erc" (&optional specified-time)) (declare-function erc-format-message "erc" (msg &rest args)) -(declare-function erc-format-privmessage "erc" (nick msg privp msgp)) (declare-function erc-get-buffer "erc" (target &optional proc)) (declare-function erc-handle-login "erc" nil) (declare-function erc-handle-user-status-change "erc" (type nlh &optional l)) @@ -173,6 +172,9 @@ erc-verbose-server-ping (declare-function erc-update-mode-line-buffer "erc" (buffer)) (declare-function erc-wash-quit-reason "erc" (reason nick login host)) +(declare-function erc--determine-speaker-message-format-args "erc" + (nick target message queryp privmsgp statusmsgp inputp + &optional prefix disp-nick)) (declare-function erc-display-message "erc" (parsed type buffer msg &rest args)) (declare-function erc-get-buffer-create "erc" @@ -1906,6 +1908,29 @@ erc--server-determine-join-display-context ?s (if (/= erc-server-lag 1) "s" ""))) (erc-update-mode-line)))) +(defun erc--statusmsg-target (target) + (and-let* ((erc-ensure-target-buffer-on-privmsg) + ((not (eq erc-ensure-target-buffer-on-privmsg 'status))) + ((not (erc-channel-p target))) + (chars (erc--get-isupport-entry 'STATUSMSG 'single)) + ((string-search (string (aref target 0)) chars)) + (trimmed (substring target 1)) + ((erc-channel-p trimmed))) + trimmed)) + +;; Moved to this file from erc.el in ERC 5.6. +(defvar-local erc-current-message-catalog 'english + "Current language or context catalog for formatting inserted messages. +See `erc-format-message'.") + +;; This variable can be converted into a user option if the current +;; design proves hospitable enough to user expectations. +(defvar erc--message-speaker-catalog '-speaker + "The \"speaker\" catalog used to format PRIVMSGs and NOTICEs.") + +(defvar erc--speaker-status-prefix-wanted-p (gensym "erc-") + "Sentinel to detect whether `erc-format-@nick' has just run.") + (define-erc-response-handler (PRIVMSG NOTICE) "Handle private messages, including messages in channels." nil (let ((sender-spec (erc-response.sender parsed)) @@ -1927,12 +1952,14 @@ erc--server-determine-join-display-context (msgp (string= cmd "PRIVMSG")) (noticep (string= cmd "NOTICE")) ;; S.B. downcase *both* tgt and current nick - (privp (erc-current-nick-p tgt)) + (medown (erc-downcase (erc-current-nick))) + (privp (string= (erc-downcase tgt) medown)) (erc--display-context `((erc-buffer-display . ,(intern cmd)) ,@erc--display-context)) - (erc--msg-prop-overrides `((erc--msg . msg) - ,@erc--msg-prop-overrides)) - s buffer + (erc--msg-prop-overrides `((erc--tmp) ,@erc--msg-prop-overrides)) + (erc--speaker-status-prefix-wanted-p nil) + (erc-current-message-catalog erc--message-speaker-catalog) + s buffer statusmsgp status fnick) (setq buffer (erc-get-buffer (if privp nick tgt) proc)) ;; Even worth checking for empty target here? (invalid anyway) @@ -1950,9 +1977,14 @@ erc--server-determine-join-display-context (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 - (setq buffer (erc--open-target tgt))))) + (cond + ;; Target is a channel and contains leading @+ chars. + ((and-let* ((trimmed (erc--statusmsg-target tgt))) + (setq buffer (erc-get-buffer trimmed proc) + statusmsgp (and buffer t)))) + ;; A channel buffer has been killed but is still joined. + (erc-ensure-target-buffer-on-privmsg + (setq buffer (erc--open-target tgt)))))) (when buffer (with-current-buffer buffer (when privp (erc--unhide-prompt)) @@ -1963,36 +1995,47 @@ erc--server-determine-join-display-context privp nil nil nil nil nil host login nil nil t) (defvar erc--cmem-from-nick-function) (defvar erc-format-nick-function) + (defvar erc-show-speaker-membership-status) + (defvar erc-speaker-from-channel-member-function) (let ((cdata (funcall erc--cmem-from-nick-function (erc-downcase nick) sndr parsed))) - (setq fnick (funcall erc-format-nick-function - (car cdata) (cdr cdata)))))) + (setq fnick (funcall erc-speaker-from-channel-member-function + (car cdata) (cdr cdata)) + status (and (or erc--speaker-status-prefix-wanted-p + erc-show-speaker-membership-status) + (cdr cdata)))))) (cond ((erc-is-message-ctcp-p msg) - (setq s (if msgp + ;; FIXME explain undefined return values being assigned to `s'. + (setq s (if-let ((parsed + (erc--ctcp-response-from-parsed + :parsed parsed :target tgt :buffer buffer + :dispname fnick :statusmsgp statusmsgp)) + (msgp)) (erc-process-ctcp-query proc parsed nick login host) (erc-process-ctcp-reply proc parsed nick login host (match-string 1 msg))))) (t (setq erc-server-last-peers (cons nick (cdr erc-server-last-peers))) - (defvar erc-format-query-as-channel-p) - (setq s (erc-format-privmessage - (or fnick nick) msg - ;; If buffer is a query buffer, - ;; format the nick as for a channel. - (and (not (and buffer - (erc-query-buffer-p buffer) - erc-format-query-as-channel-p)) - privp) - msgp)))) + (with-current-buffer (or buffer (current-buffer)) + ;; Re-bind in case either buffer has a local value. + (let ((erc-current-message-catalog erc--message-speaker-catalog)) + (setq s (erc--determine-speaker-message-format-args + nick tgt msg privp msgp statusmsgp + (string= medown (erc-downcase nick)) status fnick)))))) (when s (if (and noticep privp) (progn + (push (cons 'erc--msg (car s)) erc--msg-prop-overrides) + (setq s (apply #'erc-format-message s)) (run-hook-with-args 'erc-echo-notice-always-hook s parsed buffer nick) (run-hook-with-args-until-success 'erc-echo-notice-hook s parsed buffer nick)) - (erc-display-message parsed nil buffer s))))))) + ;; Redo text props for "echoed messages" (could instead + ;; add new method for `erc--format-privmsg') + (apply #'erc-display-message parsed nil buffer + (ensure-list s)))))))) (define-erc-response-handler (QUIT) "Another user has quit IRC." nil diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index d343a148afc..c1fb522fb5d 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -100,6 +100,23 @@ erc--target (contents "" :type string) (tags '() :type list)) +(cl-defstruct (erc--ctcp-response + (:include erc-response) + (:constructor + erc--ctcp-response-from-parsed + (&key parsed target buffer dispname statusmsgp + &aux (unparsed (erc-response.unparsed parsed)) + (sender (erc-response.sender parsed)) + (command (erc-response.command parsed)) + (command-args (erc-response.command-args parsed)) + (contents (erc-response.contents parsed)) + (tags (erc-response.tags parsed))))) + "Data for a processed CTCP query or reply." + (target nil :type string) + (buffer nil :type (or buffer null)) + (dispname nil :type (or string null)) + (statusmsgp nil :type boolean)) + (cl-defstruct erc--isupport-data "Abstract \"class\" for parsed ISUPPORT data. For use with the macro `erc--with-isupport-data'." diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el index ac7fc817cb9..d12ebd33a86 100644 --- a/lisp/erc/erc-dcc.el +++ b/lisp/erc/erc-dcc.el @@ -1251,14 +1251,16 @@ erc-dcc-chat-filter (defun erc-dcc-chat-parse-output (proc str) (save-match-data (let ((posn 0) + (erc--msg-prop-overrides `((erc--spkr . ,erc-dcc-from))) + (nick (propertize (erc--speakerize-nick erc-dcc-from) + 'font-lock-face 'erc-nick-default-face)) line) (while (string-match "\n" str posn) (setq line (substring str posn (match-beginning 0))) (setq posn (match-end 0)) (erc-display-message nil nil proc - 'dcc-chat-privmsg ?n (propertize erc-dcc-from 'font-lock-face - 'erc-nick-default-face) ?m line)) + 'dcc-chat-privmsg ?n nick ?m line)) (setq erc-dcc-unprocessed-output (substring str posn))))) (defun erc-dcc-chat-buffer-killed () diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index de6cd581fec..32a0db29cf5 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -546,42 +546,38 @@ erc-fill--wrap-length-function variable can be converted to a public one if needed by third parties.") -(defvar-local erc-fill--wrap-last-msg nil) -(defvar erc-fill--wrap-max-lull (* 24 60 60)) +(defvar-local erc-fill--wrap-last-msg nil "Marker for merging speakers.") +(defvar erc-fill--wrap-max-lull (* 24 60 60) "Max secs for merging speakers.") (defun erc-fill--wrap-continued-message-p () "Return non-nil when the current speaker hasn't changed. -That is, indicate whether the text just inserted is from the same -sender as that of the previous \"PRIVMSG\". As a side effect, -advance `erc-fill--wrap-last-msg' unless the message has been -marked as being ephemeral." - (and - (not (erc--check-msg-prop 'erc--ephemeral)) - (progn ; preserve blame for now, unprogn on next major change - (prog1 - (and-let* - ((m (or erc-fill--wrap-last-msg - (setq erc-fill--wrap-last-msg (point-min-marker)) - nil)) - ((< (1+ (point-min)) (- (point) 2))) - (props (save-restriction - (widen) - (and-let* - ((speaker (get-text-property m 'erc--spkr)) - ((not (eq (get-text-property m 'erc--ctcp) - 'ACTION))) - ((not (invisible-p m)))) - (cons (get-text-property m 'erc--ts) speaker)))) - (ts (pop props)) - (props) - ((not (time-less-p (erc-stamp--current-time) ts))) - ((time-less-p (time-subtract (erc-stamp--current-time) ts) - erc-fill--wrap-max-lull)) - ;; Assume presence of leading angle bracket or hyphen. - (nick (erc--check-msg-prop 'erc--spkr)) - ((not (erc--check-msg-prop 'erc--ctcp 'ACTION))) - ((erc-nick-equal-p props nick)))) - (set-marker erc-fill--wrap-last-msg (point-min)))))) +But only if the `erc--msg' text property also hasn't. That is, +indicate whether the chat message just inserted is from the same +person as the prior one and is formatted in the same manner. As +a side effect, advance `erc-fill--wrap-last-msg' unless the +message has been marked `erc--ephemeral'." + (and-let* + (((not (erc--check-msg-prop 'erc--ephemeral))) + ;; Always set/move `erc-fill--wrap-last-msg' from here on down. + (m (or (and erc-fill--wrap-last-msg + (prog1 (marker-position erc-fill--wrap-last-msg) + (set-marker erc-fill--wrap-last-msg (point-min)))) + (ignore (setq erc-fill--wrap-last-msg (point-min-marker))))) + ((>= (point) 4)) ; skip the first message + (props (save-restriction + (widen) + (and-let* ((speaker (get-text-property m 'erc--spkr)) + (type (get-text-property m 'erc--msg)) + ((not (invisible-p m)))) + (list (get-text-property m 'erc--ts) type speaker)))) + (ts (nth 0 props)) + (type (nth 1 props)) + (speaker (nth 2 props)) + ((not (time-less-p (erc-stamp--current-time) ts))) + ((time-less-p (time-subtract (erc-stamp--current-time) ts) + erc-fill--wrap-max-lull)) + ((erc--check-msg-prop 'erc--msg type)) + ((erc-nick-equal-p speaker (erc--check-msg-prop 'erc--spkr)))))) (defun erc-fill--wrap-measure (beg end) "Return display spec width for inserted region between BEG and END. @@ -747,8 +743,11 @@ erc-fill--wrap-rejigger-region ((equal "" dval))) (remove-text-properties dbeg (text-property-not-all dbeg end 'display dval) '(display))) - (let* ((pos (if (eq 'date-left (get-text-property beg 'erc-stamp-type)) - (field-beginning beg) + ;; This "should" work w/o `front-sticky' and `rear-nonsticky'. + (let* ((pos (if-let (((eq 'erc-timestamp (field-at-pos beg))) + (b (field-beginning beg)) + ((eq 'datestamp (get-text-property b 'erc--msg)))) + b beg)) (erc--msg-props (map-into (text-properties-at pos) 'hash-table)) (erc-stamp--current-time (gethash 'erc--ts erc--msg-props))) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index a6efa3b5151..9ca3ea320a0 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -660,8 +660,7 @@ erc-stamp--date-format-end value of t means the option's value doesn't require trimming.") (defun erc-stamp--propertize-left-date-stamp () - (add-text-properties (point-min) (1- (point-max)) - '(field erc-timestamp erc-stamp-type date-left)) + (add-text-properties (point-min) (1- (point-max)) '(field erc-timestamp)) (erc--hide-message 'timestamp) (run-hooks 'erc-stamp--insert-date-hook)) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 4c56bc8e058..0c7a2835c7a 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -154,11 +154,10 @@ erc--msg-props their markers accordingly. The following properties have meaning as of ERC 5.6: - - `erc--msg': a symbol, guaranteed present; values include: - `msg', signifying a `PRIVMSG' or an incoming `NOTICE'; - `unknown', a fallback for `erc-display-message'; a catalog - key, such as `s401' or `finished'; an `erc-display-message' - TYPE parameter, like `notice' + - `erc--msg': a symbol, guaranteed present; possible values + include `unknown', a fallback used by `erc-display-message'; a + catalog key, such as `s401' or `finished'; an + `erc-display-message' TYPE parameter, like `notice' - `erc--cmd': a message's associated IRC command, as read by `erc--get-eq-comparable-cmd'; currently either a symbol, like @@ -3017,20 +3016,32 @@ erc--send-action-perform-ctcp "Send STRING to TARGET, possibly immediately, with FORCE." (erc-send-ctcp-message target (format "ACTION %s" string) force)) +(defvar erc--use-language-catalog-for-ctcp-action-p nil + "When non-nil, use `ACTION' entry from language catalog for /ME's. +Otherwise, use `ctcp-action' or `ctcp-action-input' from the +`speaker' catalog. This is an escape hatch to restore pre-5.6 +behavior for the `font-lock-face' property of incoming and +outgoing \"CTCP ACTION\" messages, which displayed entire +pre-buttonized messages in either `erc-input-face' or +`erc-action-face'. If you use this, please ask ERC to expose it +as a public variable via \\[erc-bug] or similar.") + (defun erc--send-action-display (string) - "Display STRING as an outgoing \"CTCP ACTION\" message." + "Display STRING as an outgoing \"CTCP ACTION\" message. +Propertize the message according to the compatibility flag +`erc--use-language-catalog-for-ctcp-action-p'." ;; Allow hooks acting on inserted PRIVMSG and NOTICES to process us. - (defvar erc--merge-prop-behind-p) - (let* ((nick (erc-current-nick)) - (erc--msg-prop-overrides `((erc--msg . msg) - (erc--ctcp . ACTION) - (erc--spkr . ,nick) - ,@erc--msg-prop-overrides)) - (erc--merge-prop-behind-p t)) - (setq nick (propertize nick 'erc-speaker nick - 'font-lock-face 'erc-my-nick-face)) - (erc-display-message nil '(t input action) (current-buffer) - 'ACTION ?n nick ?a string ?u "" ?h ""))) + (let ((erc--msg-prop-overrides `((erc--ctcp . ACTION) + ,@erc--msg-prop-overrides)) + (nick (erc-current-nick))) + (if erc--use-language-catalog-for-ctcp-action-p + (progn (push (cons 'erc--spkr nick) erc--msg-prop-overrides) + (erc-display-message nil 'input (current-buffer) 'ACTION + ?n (propertize nick 'erc-speaker nick) + ?a string ?u "" ?h "")) + (let ((erc-current-message-catalog erc--message-speaker-catalog)) + (erc-display-message nil nil (current-buffer) 'ctcp-action-input + ?n (erc--speakerize-nick nick) ?m string))))) (defun erc--send-action (target string force) "Display STRING, then send to TARGET as a \"CTCP ACTION\" message." @@ -3763,7 +3774,7 @@ erc-display-message (puthash 'erc--cmd cmd table)) (when erc--msg-prop-overrides (pcase-dolist (`(,k . ,v) (reverse erc--msg-prop-overrides)) - (puthash k v table))) + (when v (puthash k v table)))) table))) (erc-message-parsed parsed)) (setq string @@ -4661,15 +4672,25 @@ erc-send-message (funcall erc--send-message-nested-function line force) (erc--send-message-external line force))) -;; FIXME fully simulate `erc-display-msg'. This doesn't currently add -;; the correct text properties. For example, the LINE should have -;; `erc-default-face'. (defun erc--send-message-external (line force) - (erc-message "PRIVMSG" (concat (erc-default-target) " " line) force) - (erc-display-line - (concat (erc-format-my-nick) line) - (current-buffer)) + "Send a \"PRIVMSG\" to the default target with optional FORCE. +Expect caller to bind `erc-default-recipients' if needing to +specify a status-prefixed target." + ;; Almost like an echoed message, but without the `erc--cmd'. + (let* ((erc-current-message-catalog erc--message-speaker-catalog) + (target (erc-default-target)) + (erc--msg-prop-overrides `((erc--tmp) ,@erc--msg-prop-overrides)) + ;; This util sets the `erc--spkr' property in ^. + (statusmsgp (erc--statusmsg-target target)) + (args (erc--determine-speaker-message-format-args + (erc-current-nick) target line + (and erc--target (not (erc--target-channel-p erc--target))) + 'privmsgp statusmsgp 'inputp t))) + (erc-message "PRIVMSG" (concat target " " line) force) + (push (cons 'erc--msg (car args)) erc--msg-prop-overrides) + (apply #'erc-display-message nil nil (current-buffer) args)) ;; FIXME - treat multiline, run hooks, or remove me? + ;; FIXME explain this ^ in more detail or remove. t) (defun erc--send-message-nested (input-line force) @@ -5284,7 +5305,6 @@ erc--own-property-names rear-nonsticky erc-prompt field front-sticky read-only ;; stamp cursor-intangible cursor-sensor-functions isearch-open-invisible - erc-stamp-type ;; match invisible intangible ;; button @@ -5628,7 +5648,9 @@ erc-ensure-target-buffer-on-privmsg :package-version '(ERC . "5.6") ; revived :group 'erc-buffers :group 'erc-query - :type 'boolean) + :type '(choice boolean + (choice :tag "Create pseudo queries for STATUSMSGs" + status))) (defcustom erc-format-query-as-channel-p t "If non-nil, format text from others in a query buffer like in a channel. @@ -5805,14 +5827,207 @@ erc-format-privmessage 'font-lock-face msg-face str) str)) -(defcustom erc-format-nick-function 'erc-format-nick - "Function to format a nickname for message display." +;; Format strings in the following `-speaker' catalog shouldn't +;; contain any non-protocol words so they make sense in any language. + +(defvar erc--message-speaker-statusmsg + #("(%p%n) %t: %m" + 0 1 (font-lock-face erc-default-face) + 1 3 (font-lock-face erc-nick-prefix-face) + 3 5 (font-lock-face erc-nick-default-face) + 5 7 (font-lock-face erc-default-face) + 7 9 (font-lock-face erc-notice-face) + 9 13 (font-lock-face erc-default-face)) + "Message template for in-channel status messages.") + +(defvar erc--message-speaker-statusmsg-input + #("(%p%n) %t: %m" + 0 1 (font-lock-face erc-default-face) + 1 3 (font-lock-face erc-my-nick-prefix-face) + 3 5 (font-lock-face erc-my-nick-face) + 5 7 (font-lock-face erc-default-face) + 7 9 (font-lock-face erc-notice-face) + 9 13 (font-lock-face erc-input-face)) + "Message template for echoed status messages.") + +(defvaralias 'erc--message-speaker-input + 'erc--message-speaker-input-chan-privmsg) +(defvar erc--message-speaker-input-chan-privmsg + #("<%p%n> %m" + 0 1 (font-lock-face erc-default-face) + 1 3 (font-lock-face erc-my-nick-prefix-face) + 3 5 (font-lock-face erc-my-nick-face) + 5 7 (font-lock-face erc-default-face) + 7 9 (font-lock-face erc-input-face)) + "Message template for prompt input or echoed PRIVMSG from own nick.") + +(defvar erc--message-speaker-input-query-privmsg + #("*%n* %m" + 0 1 (font-lock-face erc-direct-msg-face) + 1 3 (font-lock-face erc-my-nick-face) + 3 5 (font-lock-face erc-direct-msg-face) + 5 7 (font-lock-face erc-input-face)) + "Message template for prompt input or echoed PRIVMSG query from own nick.") + +(defvar erc--message-speaker-input-query-notice + #("-%n- %m" + 0 1 (font-lock-face erc-direct-msg-face) + 1 3 (font-lock-face erc-my-nick-face) + 3 5 (font-lock-face erc-direct-msg-face) + 5 7 (font-lock-face erc-input-face)) + "Message template for echoed or spoofed query NOTICE from own nick.") + +(defvar erc--message-speaker-input-chan-notice + #("-%p%n- %m" + 0 1 (font-lock-face erc-default-face) + 1 3 (font-lock-face erc-my-nick-prefix-face) + 3 5 (font-lock-face erc-my-nick-face) + 5 7 (font-lock-face erc-default-face) + 7 9 (font-lock-face erc-input-face)) + "Message template for prompt input or echoed NOTICE from own nick.") + +(defvar erc--message-speaker-chan-privmsg + #("<%p%n> %m" + 0 1 (font-lock-face erc-default-face) + 1 3 (font-lock-face erc-nick-prefix-face) + 3 5 (font-lock-face erc-nick-default-face) + 5 9 (font-lock-face erc-default-face)) + "Message template for a PRIVMSG in a channel.") + +(defvar erc--message-speaker-query-privmsg + #("*%n* %m" + 0 1 (font-lock-face erc-direct-msg-face) + 1 3 (font-lock-face erc-nick-msg-face) + 3 7 (font-lock-face erc-direct-msg-face)) + "Message template for a PRIVMSG in query buffer.") + +(defvar erc--message-speaker-chan-notice + #("-%p%n- %m" + 0 1 (font-lock-face erc-default-face) + 1 3 (font-lock-face erc-nick-prefix-face) + 3 5 (font-lock-face erc-nick-default-face) + 5 9 (font-lock-face erc-default-face)) + "Message template for a NOTICE in a channel.") + +(defvar erc--message-speaker-query-notice + #("-%n- %m" + 0 1 (font-lock-face erc-direct-msg-face) + 1 3 (font-lock-face erc-nick-msg-face) + 3 7 (font-lock-face erc-direct-msg-face)) + "Message template for a NOTICE in a query buffer.") + +(defvar erc--message-speaker-ctcp-action + #("* %n %m" + 0 7 (font-lock-face erc-action-face)) + "Message template for a CTCP ACTION from another user.") + +(defvar erc--message-speaker-ctcp-action-input + #("* %n %m" + 0 2 (font-lock-face #1=(erc-input-face erc-action-face)) + 2 4 (font-lock-face (erc-my-nick-face . #1#)) + 4 7 (font-lock-face #1#)) + "Message template for a CTCP ACTION from current client.") + +(defvar erc--message-speaker-ctcp-action-statusmsg + #("* (%n) %t: %m" + 0 7 (font-lock-face erc-action-face) + 7 9 (font-lock-face (erc-notice-face erc-action-face)) + 9 13 (font-lock-face erc-action-face)) + "Template for a CTCP ACTION status message from another chan op.") + +(defvar erc--message-speaker-ctcp-action-input-statusmsg + #("* (%n) %t: %m" + 0 3 (font-lock-face #1=(erc-input-face erc-action-face)) + 3 5 (font-lock-face (erc-my-nick-face . #1#)) + 5 7 (font-lock-face #1#) + 7 9 (font-lock-face (erc-notice-face . #1#)) + 9 13 (font-lock-face #1#)) + "Template for a CTCP ACTION status message from current client.") + +(define-inline erc--speakerize-nick (nick &optional disp) + "If NICK is without a`erc-speaker' property, return a copy with it present. +Propertize DISP instead, if given, but still assign NICK as the +text property's value." + (inline-letevals (nick disp) + (inline-quote + (let ((plain-nick (substring-no-properties ,nick))) + (cond (erc--msg-props + (puthash 'erc--spkr plain-nick erc--msg-props) + (dolist (entry (get erc--message-speaker-catalog + 'erc--msg-prop-overrides)) + (puthash (car entry) (cdr entry) erc--msg-props))) + (erc--msg-prop-overrides + (setq erc--msg-prop-overrides + (append (cons (cons 'erc--spkr plain-nick) + (get erc--message-speaker-catalog + 'erc--msg-prop-overrides)) + erc--msg-prop-overrides)))) + (if (text-property-not-all 0 (length (or ,disp ,nick)) + 'erc-speaker nil (or ,disp ,nick)) + (or ,disp ,nick) + (propertize (or ,disp ,nick) 'erc-speaker plain-nick)))))) + +(defun erc--determine-speaker-message-format-args + (nick target message queryp privmsgp statusmsgp inputp + &optional prefix disp-nick) + "Return a key for a `speaker' format template along with spec args. +Consider the flags QUERYP, PRIVMSGP, STATUSMSGP, and INPUTP, +which describe a newly arrived \"PRIVMSG\"'s message's context, +and return a key for the appropriate `speaker' catalog, along +with spec args from the other arguments. Interpret QUERYP to +mean the original target (not necessarily TARGET) matched the +client's own nick after case-folding. Expect NICK to be the +nickname of the speaker, TARGET to be the channel or query +target, and MESSAGE the body of a chat message. When non-nil, +expect DISP-NICK to be a possibly phony display name. When +PREFIX is non-nil, look up NICK's channel-membership status, +possibly using PREFIX itself if it's an `erc-channel-user' +object, which is mandatory outside of channel buffers." + ;; At the moment, TARGET and STATUSMSG are only used together in + ;; practice. + (when prefix + (setq prefix (erc-get-channel-membership-prefix + (if (erc-channel-user-p prefix) prefix nick)))) + (when (and queryp erc--target erc-format-query-as-channel-p + (not (erc--target-channel-p erc--target))) + (setq queryp nil)) + (list (cond (statusmsgp (if inputp 'statusmsg-input 'statusmsg)) + (privmsgp (if queryp + (if inputp 'input-query-privmsg 'query-privmsg) + (if inputp 'input-chan-privmsg 'chan-privmsg))) + (t (if queryp + (if inputp 'input-query-notice 'query-notice) + (if inputp 'input-chan-notice 'chan-notice)))) + ?p (or prefix "") ?n (erc--speakerize-nick nick disp-nick) + ?t (or target "") ?m message)) + +(defcustom erc-show-speaker-membership-status nil + "Whether to prefix speakers with their channel status. +For example, when this option is non-nil and some nick \"Alice\" +has operator status in the current channel, ERC displays their +leading \"speaker\" label as <@Alice> instead of ." + :package-version '(ERC . "5.6") + :group 'erc-display + :type 'boolean) + +(define-obsolete-variable-alias 'erc-format-nick-function + 'erc-speaker-from-channel-member-function "30.1") +(defcustom erc-speaker-from-channel-member-function + #'erc-determine-speaker-from-user + "Function to determine a message's displayed \"speaker\" label. +Called with an `erc-server-user' object and an `erc-channel-user' +object, both possibly nil. Use this option to do things like +provide localized display names. To ask ERC to prepend +channel-membership \"status\" prefixes, like \"@\", to the +returned name, see `erc-show-speaker-membership-status'." + :package-version '(ERC . "5.6") :group 'erc-display - :type 'function) + :type '(choice (function-item erc-determine-speaker-from-user) function)) -(defun erc-format-nick (&optional user _channel-data) - "Return the nickname of USER. -See also `erc-format-nick-function'." +(define-obsolete-function-alias 'erc-format-nick + #'erc-determine-speaker-from-user "30.1") +(defun erc-determine-speaker-from-user (&optional user _channel-data) + "Return nickname slot of `erc-server-user' USER, when non-nil." (when user (erc-server-user-nickname user))) (define-obsolete-function-alias 'erc-get-user-mode-prefix @@ -5843,14 +6058,17 @@ erc-format-@nick "Format the nickname of USER showing if USER has a voice, is an operator, half-op, admin or owner. Owners have \"~\", admins have \"&\", operators have \"@\" and users with voice have \"+\" as a -prefix. Use CHANNEL-DATA to determine op and voice status. See -also `erc-format-nick-function'." +prefix. Use CHANNEL-DATA to determine op and voice status." + (declare (obsolete "see option `erc-show-speaker-membership-status'" "30.1")) (when user (let ((nick (erc-server-user-nickname user))) - (concat (propertize - (erc-get-channel-membership-prefix channel-data) - 'font-lock-face 'erc-nick-prefix-face) - nick)))) + (if (not erc--speaker-status-prefix-wanted-p) + (prog1 nick + (setq erc--speaker-status-prefix-wanted-p 'erc-format-@nick)) + (concat (propertize + (erc-get-channel-membership-prefix channel-data) + 'font-lock-face 'erc-nick-prefix-face) + nick))))) (defun erc-format-my-nick () "Return the beginning of this user's message, correctly propertized." @@ -5863,11 +6081,34 @@ erc-format-my-nick (concat (propertize open 'font-lock-face 'erc-default-face) (propertize mode 'font-lock-face 'erc-my-nick-prefix-face) - (propertize nick 'font-lock-face 'erc-my-nick-face 'erc-speaker nick) + (propertize nick 'erc-speaker nick 'font-lock-face 'erc-my-nick-face) (propertize close 'font-lock-face 'erc-default-face))) (let ((prefix "> ")) (propertize prefix 'font-lock-face 'erc-default-face)))) +(defun erc--format-speaker-input-message (message) + "Assemble outgoing message entered at the prompt for insertion. +Here \"input\" refers to prompt input and the name of the +`speaker' catalog key. Format the speaker portion like +`erc-format-my-nick', but use `erc--message-speaker-input' as a +template. Use MESSAGE for the actual message body. Return a +copy with possibly shared text-property values." + (if-let ((erc-show-my-nick) + (nick (erc-current-nick)) + (pfx (erc-get-channel-membership-prefix nick)) + (erc-current-message-catalog erc--message-speaker-catalog) + (key (if (or erc-format-query-as-channel-p + (erc--target-channel-p erc--target)) + 'input-chan-privmsg + 'input-query-privmsg))) + (progn + (cond (erc--msg-props (puthash 'erc--msg key erc--msg-props)) + (erc--msg-prop-overrides (push (cons 'erc--msg key) + erc--msg-prop-overrides))) + (erc-format-message key ?p pfx ?n (erc--speakerize-nick nick) + ?m message)) + (propertize (concat "> " message) 'font-lock-face 'erc-input-face))) + (defun erc-echo-notice-in-default-buffer (s parsed buffer _sender) "Echo a private notice in the default buffer, namely the target buffer specified by BUFFER, or there is no target buffer, @@ -6107,8 +6348,7 @@ erc-process-ctcp-query (while queries (let* ((type (upcase (car (split-string (car queries))))) (hook (intern-soft (concat "erc-ctcp-query-" type "-hook"))) - (erc--msg-prop-overrides `((erc--msg . msg) - (erc--ctcp . ,(intern type)) + (erc--msg-prop-overrides `((erc--ctcp . ,(intern type)) ,@erc--msg-prop-overrides))) (if (and hook (boundp hook)) (if (string-equal type "ACTION") @@ -6143,12 +6383,27 @@ erc-ctcp-query-ACTION (let ((s (match-string 1 msg)) (buf (or (erc-get-buffer to proc) (erc-get-buffer nick proc) - (process-buffer proc)))) - (erc--ensure-spkr-prop nick) - (setq nick (propertize nick 'erc-speaker nick)) - (erc-display-message - parsed 'action buf - 'ACTION ?n nick ?u login ?h host ?a s)))) + (process-buffer proc))) + (selfp (erc-current-nick-p nick))) + (if erc--use-language-catalog-for-ctcp-action-p + (progn + (setq nick (propertize nick 'erc-speaker nick)) + (erc-display-message parsed (if selfp 'input 'action) buf + 'ACTION ?n nick ?u login ?h host ?a s)) + (let* ((obj (and (erc--ctcp-response-p parsed) parsed)) + (buffer (and obj (erc--ctcp-response-buffer obj))) + (target (and obj (erc--ctcp-response-target obj))) + (dispnm (and obj (erc--ctcp-response-dispname obj))) + (stmsgp (and obj (erc--ctcp-response-statusmsgp obj))) + (erc-current-message-catalog erc--message-speaker-catalog)) + (erc-display-message + parsed nil (or buffer buf) + (if selfp + (if stmsgp 'ctcp-action-input-statusmsg 'ctcp-action-input) + (if stmsgp 'ctcp-action-statusmsg 'ctcp-action)) + ?t (or target to) + ?n (erc--speakerize-nick nick dispnm) + ?m s)))))) (defvar erc-ctcp-query-CLIENTINFO-hook '(erc-ctcp-query-CLIENTINFO)) @@ -7584,15 +7839,11 @@ erc-display-msg (erc--assert-input-bounds) (let ((insert-position (marker-position (goto-char erc-insert-marker))) (erc--msg-props (or erc--msg-props - (let ((ovs erc--msg-prop-overrides)) + (let ((ovs (seq-filter + #'cdr erc--msg-prop-overrides))) (map-into `((erc--msg . msg) ,@(reverse ovs)) - 'hash-table)))) - beg) - (insert (erc-format-my-nick)) - (setq beg (point)) - (insert line) - (erc-put-text-property beg (point) 'font-lock-face 'erc-input-face) - (insert "\n") + 'hash-table))))) + (insert (erc--format-speaker-input-message line) "\n") (save-restriction (narrow-to-region insert-position (point)) (run-hooks 'erc-send-modify-hook) @@ -8947,9 +9198,6 @@ erc-message-english-PART (string-replace "%" "%%" reason)) ""))))) - -(defvar-local erc-current-message-catalog 'english) - (defun erc-retrieve-catalog-entry (entry &optional catalog) "Retrieve `format-spec' for symbol key ENTRY in CATALOG. Without CATALOG, use `erc-current-message-catalog'. If lookup diff --git a/test/lisp/erc/erc-scenarios-stamp.el b/test/lisp/erc/erc-scenarios-stamp.el index 68769e203ff..d8309984d5d 100644 --- a/test/lisp/erc/erc-scenarios-stamp.el +++ b/test/lisp/erc/erc-scenarios-stamp.el @@ -68,7 +68,7 @@ erc-scenarios-stamp--left/display-margin-mode (ert-info ("Stamps appear in left margin and are invisible") (should (eq 'erc-timestamp (field-at-pos (pos-bol)))) (should (= (pos-bol) (field-beginning (pos-bol)))) - (should (eq 'msg (get-text-property (pos-bol) 'erc--msg))) + (should (eq 'query-notice (get-text-property (pos-bol) 'erc--msg))) (should (eq 'NOTICE (get-text-property (pos-bol) 'erc--cmd))) (should (= ?- (char-after (field-end (pos-bol))))) (should (equal (get-text-property (1+ (field-end (pos-bol))) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index eb954112ce8..ac05a63deee 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -2285,7 +2285,8 @@ erc-message calls erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) (cl-letf (((symbol-function 'erc-display-message) - (lambda (_ _ _ line) (push line calls))) + (lambda (_ _ _ msg &rest args) + (push (apply #'erc-format-message msg args) calls))) ((symbol-function 'erc-server-send) (lambda (line _) (push line calls))) ((symbol-function 'erc-server-buffer) @@ -2327,7 +2328,7 @@ erc-message (should-not erc-server-last-peers) (erc-message "PRIVMSG" ". hi") (should-not erc-server-last-peers) - (should (eq 'no-target (pop calls))) + (should (equal "No target" (pop calls))) (erc-message "PRIVMSG" ", hi") (should-not erc-server-last-peers) (should (string-match "alice :hi" (pop calls))))) @@ -2360,42 +2361,208 @@ erc-message (kill-buffer "ExampleNet") (kill-buffer "#chan"))) -(ert-deftest erc-format-privmessage () - ;; Basic PRIVMSG - (should (erc-tests--equal-including-properties - (erc-format-privmessage (copy-sequence "bob") - (copy-sequence "oh my") - nil 'msgp) - #(" oh my" - 0 1 (font-lock-face erc-default-face) - 1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face) - 4 11 (font-lock-face erc-default-face)))) - - ;; Basic NOTICE - (should (erc-tests--equal-including-properties - (erc-format-privmessage (copy-sequence "bob") - (copy-sequence "oh my") - nil nil) - #("-bob- oh my" - 0 1 (font-lock-face erc-default-face) - 1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face) - 4 11 (font-lock-face erc-default-face)))) - - ;; Prefixed PRIVMSG - (let* ((user (make-erc-server-user :nickname (copy-sequence "Bob"))) +;; This is an adapter that uses formatting templates from the +;; `-speaker' catalog to mimic `erc-format-privmessage', for testing +;; purposes. +(defun erc-tests--format-privmessage (nick msg privp msgp &optional inputp pfx) + (let ((erc-current-message-catalog erc--message-speaker-catalog)) + (apply #'erc-format-message + (erc--determine-speaker-message-format-args nick nil msg privp msgp + nil inputp pfx)))) + +;; This asserts that `erc--determine-speaker-message-format-args' +;; behaves identically to `erc-format-privmessage', the function whose +;; role it basically replaced. +(ert-deftest erc--determine-speaker-message-format-args () + ;; Basic PRIVMSG. + (let ((expect #(" oh my" + 0 1 (font-lock-face erc-default-face) + 1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face) + 4 11 (font-lock-face erc-default-face))) + (args (list (concat "bob") (concat "oh my") nil 'msgp))) + (should (erc-tests--equal-including-properties + (apply #'erc-format-privmessage args) + expect)) + (should (erc-tests--equal-including-properties + (apply #'erc-tests--format-privmessage args) + expect))) + + ;; Basic NOTICE. + (let ((expect #("-bob- oh my" + 0 1 (font-lock-face erc-default-face) + 1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face) + 4 11 (font-lock-face erc-default-face))) + (args (list (copy-sequence "bob") (copy-sequence "oh my") nil nil))) + (should (erc-tests--equal-including-properties + (apply #'erc-format-privmessage args) + expect)) + (should (erc-tests--equal-including-properties + (apply #'erc-tests--format-privmessage args) + expect))) + + ;; Status-prefixed PRIVMSG. + (let* ((expect + #("<@Bob> oh my" + 0 1 (font-lock-face erc-default-face) + 1 2 (font-lock-face erc-nick-prefix-face help-echo "operator") + 2 5 (erc-speaker "Bob" font-lock-face erc-nick-default-face) + 5 12 (font-lock-face erc-default-face))) + (user (make-erc-server-user :nickname (copy-sequence "Bob"))) (cuser (make-erc-channel-user :op t)) (erc-channel-users (make-hash-table :test #'equal))) (puthash "bob" (cons user cuser) erc-channel-users) + (with-suppressed-warnings ((obsolete erc-format-@nick)) + (should (erc-tests--equal-including-properties + (erc-format-privmessage (erc-format-@nick user cuser) + (copy-sequence "oh my") + nil 'msgp) + expect))) + (let ((nick "Bob") + (msg "oh my")) + (should (erc-tests--equal-including-properties + (erc-tests--format-privmessage nick msg nil 'msgp nil cuser) + expect)) ; overloaded on PREFIX arg + (should (erc-tests--equal-including-properties + (erc-tests--format-privmessage nick msg nil 'msgp nil t) + expect)) + ;; The new version makes a copy instead of adding properties to + ;; the input. + (should-not + (text-property-not-all 0 (length nick) 'font-lock-face nil nick)) + (should-not + (text-property-not-all 0 (length msg) 'font-lock-face nil msg))))) + +(ert-deftest erc--determine-speaker-message-format-args/queries-as-channel () + (should erc-format-query-as-channel-p) + + (with-current-buffer (get-buffer-create "bob") + (erc-mode) + (setq erc--target (erc--target-from-string "alice")) + + (insert "PRIVMSG\n" + (erc-tests--format-privmessage "bob" "oh my" 'queryp 'msgp)) + (should (erc-tests--equal-including-properties + #(" oh my" + 0 1 (font-lock-face erc-default-face) + 1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face) + 4 11 (font-lock-face erc-default-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (insert "\nNOTICE\n" + (erc-tests--format-privmessage "bob" "oh my" 'queryp nil)) + (should (erc-tests--equal-including-properties + #("-bob- oh my" + 0 1 (font-lock-face erc-default-face) + 1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face) + 4 11 (font-lock-face erc-default-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (insert "\nInput PRIVMSG\n" + (erc-tests--format-privmessage "bob" "oh my" + 'queryp 'privmsgp 'inputp)) + (should (erc-tests--equal-including-properties + #(" oh my" + 0 1 (font-lock-face erc-default-face) + 1 4 (erc-speaker "bob" font-lock-face erc-my-nick-face) + 4 6 (font-lock-face erc-default-face) + 6 11 (font-lock-face erc-input-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (insert "\nInput NOTICE\n" + (erc-tests--format-privmessage "bob" "oh my" 'queryp nil 'inputp)) (should (erc-tests--equal-including-properties - (erc-format-privmessage (erc-format-@nick user cuser) - (copy-sequence "oh my") - nil 'msgp) - #("<@Bob> oh my" + #("-bob- oh my" 0 1 (font-lock-face erc-default-face) - 1 2 (font-lock-face erc-nick-prefix-face help-echo "operator") - 2 5 (erc-speaker "Bob" font-lock-face erc-nick-default-face) - 5 12 (font-lock-face erc-default-face)))))) + 1 4 (erc-speaker "bob" font-lock-face erc-my-nick-face) + 4 6 (font-lock-face erc-default-face) + 6 11 (font-lock-face erc-input-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (when noninteractive (kill-buffer)))) + +(ert-deftest erc--determine-speaker-message-format-args/queries () + (should erc-format-query-as-channel-p) + + (with-current-buffer (get-buffer-create "bob") + (erc-mode) + (setq-local erc-format-query-as-channel-p nil) + (setq erc--target (erc--target-from-string "alice")) + + (insert "PRIVMSG\n" + (erc-tests--format-privmessage "bob" "oh my" 'queryp 'msgp)) + (should (erc-tests--equal-including-properties + #("*bob* oh my" + 0 1 (font-lock-face erc-direct-msg-face) + 1 4 (erc-speaker "bob" font-lock-face erc-nick-msg-face) + 4 11 (font-lock-face erc-direct-msg-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (insert "\nNOTICE\n" + (erc-tests--format-privmessage "bob" "oh my" 'queryp nil)) + (should (erc-tests--equal-including-properties + #("-bob- oh my" + 0 1 (font-lock-face erc-direct-msg-face) + 1 4 (erc-speaker "bob" font-lock-face erc-nick-msg-face) + 4 11 (font-lock-face erc-direct-msg-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (insert "\nInput PRIVMSG\n" + (erc-tests--format-privmessage "bob" "oh my" + 'queryp 'privmsgp 'inputp)) + (should (erc-tests--equal-including-properties + #("*bob* oh my" + 0 1 (font-lock-face erc-direct-msg-face) + 1 4 (erc-speaker "bob" font-lock-face erc-my-nick-face) + 4 6 (font-lock-face erc-direct-msg-face) + 6 11 (font-lock-face erc-input-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (insert "\nInput NOTICE\n" + (erc-tests--format-privmessage "bob" "oh my" 'queryp nil 'inputp)) + (should (erc-tests--equal-including-properties + #("-bob- oh my" + 0 1 (font-lock-face erc-direct-msg-face) + 1 4 (erc-speaker "bob" font-lock-face erc-my-nick-face) + 4 6 (font-lock-face erc-direct-msg-face) + 6 11 (font-lock-face erc-input-face)) + (buffer-substring (pos-bol) (pos-eol)))) + + (when noninteractive (kill-buffer)))) + +(defun erc-tests--format-my-nick (message) + (concat (erc-format-my-nick) + (propertize message 'font-lock-face 'erc-input-face))) + +;; This tests that the default behavior of the replacement formatting +;; function for prompt input, `erc--format-speaker-input-message' +;; matches that of the original being replaced, `erc-format-my-nick', +;; though it only handled the speaker portion. +(ert-deftest erc--format-speaker-input-message () + ;; No status prefix. + (let ((erc-server-current-nick "tester") + (expect #(" oh my" + 0 1 (font-lock-face erc-default-face) + 1 7 (font-lock-face erc-my-nick-face erc-speaker "tester") + 7 9 (font-lock-face erc-default-face) + 9 14 (font-lock-face erc-input-face)))) + (should (equal (erc-tests--format-my-nick "oh my") expect)) + (should (equal (erc--format-speaker-input-message "oh my") expect))) + + ;; With channel-operator status prefix. + (let* ((erc-server-current-nick "tester") + (cmem (cons (make-erc-server-user :nickname "tester") + (make-erc-channel-user :op t))) + (erc-channel-users (map-into (list "tester" cmem) + '(hash-table :test equal))) + (expect #("<@tester> oh my" + 0 1 (font-lock-face erc-default-face) + 1 2 (font-lock-face erc-my-nick-prefix-face) + 2 5 (font-lock-face erc-my-nick-face erc-speaker "bob") + 5 7 (font-lock-face erc-default-face) + 7 12 (font-lock-face erc-input-face)))) + (should (equal (erc-tests--format-my-nick "oh my") expect)) + (should (equal (erc--format-speaker-input-message "oh my") expect)))) (ert-deftest erc--route-insertion () (erc-tests--send-prep) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index 9f648915d5c..feaba85ec90 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** 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.[00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero.[07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--spkr "alice" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 0)) display #8="") 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-prefix #10#) 499 505 (wrap-prefix #1# line-prefix #10#) 506 507 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) display #8#) 507 510 (wrap-prefix #1# line-prefix #11# display #8#) 510 512 (wrap-prefix #1# line-prefix #11# display #8#) 512 515 (wrap-prefix #1# line-prefix #11#) 516 517 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #12=(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #12#) 518 521 (wrap-prefix #1# line-prefix #12#) 521 527 (wrap-prefix #1# line-prefix #12#) 528 529 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** 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.[00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero.[07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 0)) display #8="") 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-prefix #10#) 499 505 (wrap-prefix #1# line-prefix #10#) 506 507 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) display #8#) 507 510 (wrap-prefix #1# line-prefix #11# display #8#) 510 512 (wrap-prefix #1# line-prefix #11# display #8#) 512 515 (wrap-prefix #1# line-prefix #11#) 516 517 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #12=(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #12#) 518 521 (wrap-prefix #1# line-prefix #12#) 521 527 (wrap-prefix #1# line-prefix #12#) 528 529 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld index a63fcad3d38..ed1488c8595 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** 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.[00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero.[07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--spkr "alice" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 0)) display #8="") 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-prefix #10#) 499 505 (wrap-prefix #1# line-prefix #10#) 505 506 (display #("~\n" 0 2 (font-lock-face shadow))) 506 507 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) display #8#) 507 510 (wrap-prefix #1# line-prefix #11# display #8#) 510 512 (wrap-prefix #1# line-prefix #11# display #8#) 512 515 (wrap-prefix #1# line-prefix #11#) 516 517 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #12=(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #12#) 518 521 (wrap-prefix #1# line-prefix #12#) 521 527 (wrap-prefix #1# line-prefix #12#) 528 529 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** 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.[00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero.[07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 0)) display #8="") 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-prefix #10#) 499 505 (wrap-prefix #1# line-prefix #10#) 505 506 (display #("~\n" 0 2 (font-lock-face shadow))) 506 507 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) display #8#) 507 510 (wrap-prefix #1# line-prefix #11# display #8#) 510 512 (wrap-prefix #1# line-prefix #11# display #8#) 512 515 (wrap-prefix #1# line-prefix #11#) 516 517 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #12=(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #12#) 518 521 (wrap-prefix #1# line-prefix #12#) 521 527 (wrap-prefix #1# line-prefix #12#) 528 529 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld index 7cbabfd0581..a3530a6c44d 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** 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.[00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero.[07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--spkr "alice" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 #10=(2))) display #8=#("> " 0 1 (font-lock-face shadow))) 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-prefix #11#) 499 505 (wrap-prefix #1# line-prefix #11#) 506 507 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=(space :width (- 27 #10#)) display #8#) 507 510 (wrap-prefix #1# line-prefix #12# display #8#) 510 512 (wrap-prefix #1# line-prefix #12# display #8#) 512 515 (wrap-prefix #1# line-prefix #12#) 516 517 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #13=(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #13#) 518 521 (wrap-prefix #1# line-prefix #13#) 521 527 (wrap-prefix #1# line-prefix #13#) 528 529 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #14=(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #14#) 532 539 (wrap-prefix #1# line-prefix #14#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** 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.[00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero.[07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 #10=(2))) display #8=#("> " 0 1 (font-lock-face shadow))) 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-prefix #11#) 499 505 (wrap-prefix #1# line-prefix #11#) 506 507 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=(space :width (- 27 #10#)) display #8#) 507 510 (wrap-prefix #1# line-prefix #12# display #8#) 510 512 (wrap-prefix #1# line-prefix #12# display #8#) 512 515 (wrap-prefix #1# line-prefix #12#) 516 517 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #13=(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #13#) 518 521 (wrap-prefix #1# line-prefix #13#) 521 527 (wrap-prefix #1# line-prefix #13#) 528 529 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #14=(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #14#) 532 539 (wrap-prefix #1# line-prefix #14#)) \ No newline at end of file -- 2.42.0