From 94b5f02dc92b6600f14ab207464558c5de8969d8 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Wed, 8 May 2024 19:03:58 -0700 Subject: [PATCH 1/2] [5.6] Reconcile erc-stamp--date-stamps when merging buffers * etc/ERC-NEWS: Mention new face `erc-info'. * lisp/erc/erc-button.el (erc-button-add-buttons): Skip buttonization when the "msg prop" `erc--skip' is present and contains the symbol `button'. * lisp/erc/erc-networks.el (erc--insert-admin-message-before): Forward declaration. (erc-networks--insert-transplanted-content) (erc-networks--transplant-buffer-content): Rename former to latter. Change signature to take source and destination buffers as parameters. (erc-networks--transplant-target-buffer-function): New function-valued variable. (erc-networks--reclaim-orphaned-target-buffers): Call `erc-networks--transplant-target-buffer-function' to handle transplant business. (erc-networks--copy-over-server-buffer-contents): Pass old and new buffers to `erc-networks--insert-transplanted-content'. * lisp/erc/erc-stamp.el (erc-stamp--defer-date-insertion-on-post-modify): Set `fn' slot of `erc-stamp--date' instance to `ignore' when running the actual callback in order to conserve a little space. (erc-stamp--date-mode): Add and remove hook members for `erc-networks--copy-server-buffer-functions' and `erc-networks--transplant-target-buffer-function'. (erc-insert-timestamp-left-and-right): Always clear `erc-timestamp-last-inserted-right' to ensure a right stamp accompanies every date stamp. (erc-stamp--dedupe-date-stamps) (erc-stamp--dedupe-date-stamps-from-buffer) (erc-stamp--dedupe-date-stamps-from-target-buffer): New functions. Date stamps were revamped as part of bug#60936. * lisp/erc/erc.el (erc-informational): New face. (erc--insert-admin-message-before): New function to hide some "msg prop" complexity from "upstream" libraries, like erc-networks and thus avoid more forward-declarations. A less smelly approach would be to devise a general interface owned by such libraries that `erc-mode' could then hook into on init. (erc-display-message-highlight): Make face-matching more limber. (erc-message-english-grafted): New variable. * test/lisp/erc/erc-networks-tests.el (erc-networks--rename-server-buffer--no-existing--orphan) (erc-networks--rename-server-buffer--existing--reuse) (erc-networks--rename-server-buffer--local-match) (erc-networks--rename-server-buffer--local-nomatch): Use helper to initialize markers. * test/lisp/erc/erc-stamp-tests.el (erc-stamp--dedupe-date-stamps): New test. --- etc/ERC-NEWS | 7 ++ lisp/erc/erc-button.el | 4 +- lisp/erc/erc-networks.el | 91 ++++++++++++---------- lisp/erc/erc-stamp.el | 60 ++++++++++++++ lisp/erc/erc.el | 22 +++++- test/lisp/erc/erc-networks-tests.el | 4 + test/lisp/erc/erc-stamp-tests.el | 116 ++++++++++++++++++++++++++++ 7 files changed, 259 insertions(+), 45 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index b66ea6a7a02..4562e8a8117 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -339,6 +339,13 @@ Also available as the library functions 'erc-cmd-AME', 'erc-cmd-GME', and 'erc-cmd-GMSG', these new slash commands can prove handy in test environments. +** New face 'erc-informational' for local administrative messages. +Messages that don't originate from a server have historically been +shown in a combination of 'erc-notice-face' and 'erc-error-face', +which can be distracting for those of low to moderate importance. +Such messages now look more subdued and retain the familiar +'erc-notice-prefix' stars. + ** 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 diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index 1f9d6fd64c0..8cf8991e57c 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -309,7 +309,9 @@ erc-button-add-buttons regexp) (erc-button-remove-old-buttons) (unless (or erc-button--has-nickname-entry - (not erc-button-buttonize-nicks)) + (not erc-button-buttonize-nicks) + (and (erc--memq-msg-prop 'erc--skip 'button) + (not (setq alist nil)))) (erc-button-add-nickname-buttons `(_ _ erc-button--modify-nick-function ,erc-button-nickname-callback-function))) diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 1b26afa1164..9c8cdf3b0e4 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el @@ -50,6 +50,7 @@ erc-server-connected (defvar erc-server-process) (declare-function erc--get-isupport-entry "erc-backend" (key &optional single)) +(declare-function erc--insert-admin-message-before "erc" (&rest args)) (declare-function erc-buffer-filter "erc" (predicate &optional proc)) (declare-function erc-current-nick "erc" nil) (declare-function erc-display-error-notice "erc" (parsed string)) @@ -1345,24 +1346,35 @@ erc-unset-network-name (setq erc-network nil) nil) -;; TODO add note in Commentary saying that this module is considered a -;; core module and that it's as much about buffer naming and network -;; identity as anything else. - -(defun erc-networks--insert-transplanted-content (content) - (let ((inhibit-read-only t) - (buffer-undo-list t)) - (save-excursion - (save-restriction - (widen) - (goto-char (point-min)) - (insert-before-markers content))))) +(defun erc-networks--transplant-buffer-content (src dest) + "Insert buffer SRC's contents into DEST, above its contents." + (with-silent-modifications + (let ((content (with-current-buffer src + (cl-assert (not (buffer-narrowed-p))) + (erc--insert-admin-message-before 'grafted ?n dest ?o src) + (buffer-substring (point-min) erc-insert-marker)))) + (with-current-buffer dest + (save-excursion + (save-restriction + (cl-assert (not (buffer-narrowed-p))) + (goto-char (point-min)) + (while (and (eql ?\n (char-after (point))) + (null (text-properties-at (point)))) + (delete-char 1)) + (insert-before-markers content))))))) + +(defvar erc-networks--transplant-target-buffer-function + #'erc-networks--transplant-buffer-content + "Function to rename and merge the contents of two target buffers. +Called with the donating buffer to be killed and buffer to receive the +transplant. Consuming modules can leave a marker at the beginning of +the latter buffer to access the insertion point, if needing to do things +like adjust invisibility properties, etc.") ;; This should run whenever a network identity is updated. - (defun erc-networks--reclaim-orphaned-target-buffers (new-proc nid announced) "Visit disowned buffers for same NID and associate with NEW-PROC. -ANNOUNCED is the server's reported host name." +Expect ANNOUNCED to be the server's reported host name." (erc-buffer-filter (lambda () (when (and erc--target @@ -1372,20 +1384,25 @@ erc-networks--reclaim-orphaned-target-buffers (string= erc-server-announced-name announced))) ;; If a target buffer exists for the current process, kill this ;; stale one after transplanting its content; else reinstate. - (if-let ((existing (erc-get-buffer - (erc--target-string erc--target) new-proc))) + (if-let ((actual (erc-get-buffer (erc--target-string erc--target) + new-proc))) (progn - (widen) - (let ((content (buffer-substring (point-min) - erc-insert-marker))) - (kill-buffer) ; allow target-buf renaming hook to run - (with-current-buffer existing - (erc-networks--ensure-unique-target-buffer-name) - (erc-networks--insert-transplanted-content content)))) + (funcall erc-networks--transplant-target-buffer-function + (current-buffer) actual) + (kill-buffer (current-buffer)) + (with-current-buffer actual + (erc-networks--ensure-unique-target-buffer-name))) (setq erc-server-process new-proc erc-server-connected t erc-networks--id nid)))))) +;; For existing buffers, `erc-open' reinitializes a core set of local +;; variables in addition to some text, such as the prompt. It expects +;; module activation functions to do the same for assets they manage. +;; However, "stateful" modules, whose functionality depends on the +;; evolution of a buffer's content, may need to reconcile state during +;; a merge. An example might be a module that provides consistent +;; timestamps: it should ensure time values don't decrease. (defvar erc-networks--copy-server-buffer-functions nil "Abnormal hook run in new server buffers when deduping. Passed the existing buffer to be killed, whose contents have @@ -1393,26 +1410,18 @@ erc-networks--copy-server-buffer-functions (defun erc-networks--copy-over-server-buffer-contents (existing name) "Kill off existing server buffer after copying its contents. -Must be called from the replacement buffer." +Expect to be called from the replacement buffer." (defvar erc-kill-buffer-hook) (defvar erc-kill-server-hook) - ;; ERC expects `erc-open' to be idempotent when setting up local - ;; vars and other context properties for a new identity. Thus, it's - ;; unlikely we'll have to copy anything else over besides text. And - ;; no reconciling of user tables, etc. happens during a normal - ;; reconnect, so we should be fine just sticking to text. (Right?) - (let ((text (with-current-buffer existing - ;; This `erc-networks--id' should be - ;; `erc-networks--id-equal-p' to caller's network - ;; identity and older if not eq. - ;; - ;; `erc-server-process' should be set but dead - ;; and eq `get-buffer-process' unless latter nil - (delete-process erc-server-process) - (buffer-substring (point-min) erc-insert-marker))) - erc-kill-server-hook - erc-kill-buffer-hook) - (erc-networks--insert-transplanted-content text) + ;; The following observations from ERC 5.5 regarding the buffer + ;; `existing' were thought at the time to be invariants: + ;; - `erc-networks--id' is `erc-networks--id-equal-p' to the + ;; caller's network identity and older if not `eq'. + ;; - `erc-server-process' should be set (local) but dead and `eq' to + ;; the result of `get-buffer-process' unless the latter is nil. + (delete-process (buffer-local-value 'erc-server-process existing)) + (erc-networks--transplant-buffer-content existing (current-buffer)) + (let (erc-kill-server-hook erc-kill-buffer-hook) (run-hook-with-args 'erc-networks--copy-server-buffer-functions existing) (kill-buffer name))) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index fd137c0548a..8571c836ba2 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -730,6 +730,7 @@ erc-stamp--defer-date-insertion-on-post-modify (fset symbol (lambda (&rest _) (remove-hook hook-var symbol) + (setf (erc-stamp--date-fn data) #'ignore) (when (buffer-live-p buffer) (with-current-buffer buffer (setq erc-stamp--date-stamps @@ -773,11 +774,20 @@ erc-stamp--date-mode :interactive nil (if erc-stamp--date-mode (progn + (add-function :around + (local 'erc-networks--transplant-target-buffer-function) + #'erc-stamp--dedupe-date-stamps-from-target-buffer) + (add-hook 'erc-networks--copy-server-buffer-functions + #'erc-stamp--dedupe-date-stamps-from-buffer 0 t) (add-hook 'erc-insert-post-hook #'erc-stamp--defer-date-insertion-on-post-insert 0 t) (add-hook 'erc-send-post-hook #'erc-stamp--defer-date-insertion-on-post-send 0 t)) (kill-local-variable 'erc-timestamp-last-inserted-left) + (remove-function (local 'erc-networks--transplant-target-buffer-function) + #'erc-stamp--dedupe-date-stamps-from-target-buffer) + (remove-hook 'erc-networks--copy-server-buffer-functions + #'erc-stamp--dedupe-date-stamps-from-buffer t) (remove-hook 'erc-insert-post-hook #'erc-stamp--defer-date-insertion-on-post-insert t) (remove-hook 'erc-send-post-hook @@ -841,6 +851,8 @@ erc-insert-timestamp-left-and-right ((not (string-equal rendered erc-timestamp-last-inserted-left))) ((null (cl-find rendered erc-stamp--date-stamps :test #'string= :key #'erc-stamp--date-str)))) + ;; Force `erc-insert-timestamp-right' to stamp this message. + (setq erc-timestamp-last-inserted-right nil) (setq erc-stamp--deferred-date-stamp (make-erc-stamp--date :ts ct :str rendered)))) ;; insert right timestamp @@ -1040,6 +1052,54 @@ erc-stamp--reset-on-clear erc-timestamp-last-inserted-left nil erc-timestamp-last-inserted-right nil))) +(defun erc-stamp--dedupe-date-stamps (old-stamps) + "Update `erc-stamp--date-stamps' from its counterpart OLD-STAMPS. +Assume the contents of the buffer for OLD-STAMPS have just been inserted +above the current buffer's and that the old buffer still exists so that +markers still point somewhere. For each duplicate, update the existing +marker to match the transplanted timestamp with the same date. Also +copy non-duplicate `erc-stamp--date' objects from OLD-STAMPS to the +current buffer's, maintaining order." + (let (need) + (dolist (old old-stamps) + (cl-assert (marker-position (erc-stamp--date-marker old))) + (if-let ((new (cl-find (erc-stamp--date-str old) erc-stamp--date-stamps + :test #'string= :key #'erc-stamp--date-str)) + (new-marker (erc-stamp--date-marker new))) + ;; The new buffer now has a duplicate stamp, so remove the + ;; "newer" one from the buffer. + (progn + (erc--delete-inserted-message-naively new-marker) + (set-marker new-marker (erc-stamp--date-marker old))) + ;; The new buffer doesn't have this stamp, so add its data + ;; object to the sorted list. + (push old need) + ;; Update the old marker position to point to the new buffer. + (set-marker (erc-stamp--date-marker old) + (erc-stamp--date-marker old)))) + ;; These *should* already be sorted (right?). + (setq erc-stamp--date-stamps + (nconc (nreverse need) erc-stamp--date-stamps)) + (let ((last 0)) + (dolist (stamp erc-stamp--date-stamps) + (cl-assert (eq (current-buffer) + (marker-buffer (erc-stamp--date-marker stamp)))) + (cl-assert (< last (erc-stamp--date-marker stamp))) + (setq last (erc-stamp--date-marker stamp)))))) + +(defun erc-stamp--dedupe-date-stamps-from-buffer (old-buffer) + "Merge date stamps from OLD-BUFFER into in the current buffer." + (let ((old-stamps (buffer-local-value 'erc-stamp--date-stamps old-buffer))) + (erc-stamp--dedupe-date-stamps old-stamps))) + +(defun erc-stamp--dedupe-date-stamps-from-target-buffer (orig old-buffer + new-buffer) + "Merge date stamps from OLD-BUFFER into NEW-BUFFER after calling ORIG." + (let ((old-stamps (buffer-local-value 'erc-stamp--date-stamps old-buffer))) + (prog1 (funcall orig old-buffer new-buffer) + (with-current-buffer new-buffer + (erc-stamp--dedupe-date-stamps old-stamps))))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index c92fd42322a..7bc480c8a92 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1513,6 +1513,10 @@ erc-error-face "ERC face for errors." :group 'erc-faces) +(defface erc-informational '((t :inherit shadow)) + "Face for local administrative messages of low to moderate importance." + :group 'erc-faces) + ;; same default color as `erc-input-face' (defface erc-my-nick-face '((t :weight bold :foreground "brown")) "ERC face for your current nickname in messages sent by you. @@ -3518,6 +3522,14 @@ erc-display-line (push '(erc--msg . notice) erc--msg-prop-overrides))) (erc-display-message nil nil buffer string))) +(defun erc--insert-admin-message-before (msg &rest args) + "Call `erc-display-message' with MSG and ARGS, inserting before point. +Inhibit all buttonizing." + (let ((erc--msg-prop-overrides `((erc--skip . (stamp track button)) + ,@erc--msg-prop-overrides))) + (apply #'erc-display-message nil '(notice informational) + (current-buffer) msg args))) + (defvar erc--merge-text-properties-p nil "Non-nil when `erc-put-text-property' defers to `erc--merge-prop'.") @@ -3724,9 +3736,12 @@ erc-display-message-highlight (t (erc-put-text-property 0 (length string) - 'font-lock-face (or (intern-soft - (concat "erc-" (symbol-name type) "-face")) - 'erc-default-face) + 'font-lock-face + (let* ((name (symbol-name type)) + (symbol (or (intern-soft (concat "erc-" name "-face")) + (intern-soft (concat "erc-" name)) + type))) + (or (and (facep symbol) symbol) 'erc-default-face)) string) string))) @@ -9426,6 +9441,7 @@ english (finished . "\n\n*** ERC finished ***\n") (terminated . "\n\n*** ERC terminated: %e\n") (login . "Logging in as `%n'...") + (grafted . "Grafted buffer `%n' onto `%o'") (nick-in-use . "%n is in use. Choose new nickname: ") (nick-too-long . "WARNING: Nick length (%i) exceeds max NICKLEN(%l) defined by server") diff --git a/test/lisp/erc/erc-networks-tests.el b/test/lisp/erc/erc-networks-tests.el index 0d8861f2167..90d6f13f2f6 100644 --- a/test/lisp/erc/erc-networks-tests.el +++ b/test/lisp/erc/erc-networks-tests.el @@ -1243,6 +1243,7 @@ erc-networks--rename-server-buffer--no-existing--orphan (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-process (erc-networks-tests--create-live-proc) @@ -1282,6 +1283,7 @@ erc-networks--rename-server-buffer--existing--reuse (ert-info ("New buffer steals name, content") (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-process (erc-networks-tests--create-live-proc) @@ -1522,6 +1524,7 @@ erc-networks--rename-server-buffer--local-match (ert-info ("New server buffer steals name, content") (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-announced-name "us-east.foonet.org" @@ -1574,6 +1577,7 @@ erc-networks--rename-server-buffer--local-nomatch (ert-info ("New server buffer steals name, content") (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-announced-name "us-east.foonet.org" ; east diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 5fee21ec28f..f4209c5d668 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -349,4 +349,120 @@ erc--get-inserted-msg-bounds/readonly/stamp (lambda (arg) (should (equal '(3 . 19) (erc--get-inserted-msg-bounds arg)))))) +(ert-deftest erc-stamp--dedupe-date-stamps-from-target-buffer () + (let ((erc-modules erc-modules) + (erc-stamp--tz t)) + (erc-tests-common-make-server-buf) + (erc-stamp-mode +1) + + ;; Create two buffers with an overlapping date stamp. + (with-current-buffer (erc--open-target "#chan@old") + (let ((erc-stamp--current-time '(1690761600001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-07-31T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1690761601001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "0.0")) + + (let ((erc-stamp--current-time '(1690848000001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-01T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1690848001001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "1.0")) + (let ((erc-stamp--current-time '(1690848060001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "1.1")) + + (let ((erc-stamp--current-time '(1690934400001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-02T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1690934401001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "2.0")) + (let ((erc-stamp--current-time '(1690956000001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "2.6"))) + + (with-current-buffer (erc--open-target "#chan@new") + (let ((erc-stamp--current-time '(1690956001001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-02T06:00:01.001Z")) + (let ((erc-stamp--current-time '(1690963200001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "2.8")) + + (let ((erc-stamp--current-time '(1691020800001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-03T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1691020801001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "3.0")) + (let ((erc-stamp--current-time '(1691053200001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "3.9")) + + (let ((erc-stamp--current-time '(1691107200001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-04T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1691107201001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "4.0")) + (let ((erc-stamp--current-time '(1691110800001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "4.1"))) + + (erc-stamp--dedupe-date-stamps-from-target-buffer + #'erc-networks--transplant-buffer-content + (get-buffer "#chan@old") + (get-buffer "#chan@new")) + + ;; Ensure the "model", `erc-stamp--date-stamps', matches reality + ;; in the buffer's contents. + (with-current-buffer "#chan@new" + (let ((stamps erc-stamp--date-stamps)) + (goto-char 3) + (should (looking-at (rx "\n[Mon Jul 31 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-07-31T00:00:00.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 0.0"))) + (forward-line 1) + + (should (looking-at (rx "\n[Tue Aug 1 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-08-01T00:00:00.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 1.0"))) + (forward-line 1) + (should (looking-at (rx "*** 1.1"))) + (forward-line 1) + + (should (looking-at (rx "\n[Wed Aug 2 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-08-02T00:00:00.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 2.0"))) + (forward-line 1) + (should (looking-at (rx "*** 2.6"))) + (forward-line 1) + (should (looking-at + (rx "*** Grafted buffer `#chan@new' onto `#chan@old'"))) + (forward-line 1) + (should (looking-at (rx "*** 2023-08-02T06:00:01.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 2.8"))) + (forward-line 1) + + (should (looking-at (rx "\n[Thu Aug 3 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-08-03T00:00:00.001Z"))) + (forward-line 3) ; ... + + (should (looking-at (rx "\n[Fri Aug 4 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (should-not stamps)))) + + (when noninteractive + (erc-tests-common-kill-buffers))) + ;;; erc-stamp-tests.el ends here -- 2.44.0