Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode

"J.P." <[email protected]>
Newsgroups gmane.emacs.erc.general
Message-ID <[email protected]>
A commit associated with this bug

  d880a08f "Cement ordering of essential hook members in ERC"

introduced a regression that basically nullifies the `match' module when
a certain `erc-stamp' option is customized to a certain value. To
reproduce from Emacs -Q:

  - Set `erc-insert-timestamp-function' to `erc-insert-timestamp-left'

  - Connect to any server

  - Find the first mention of your nickname in the text of some early
    numeric (often something like "Welcome to FooNet <nick>")

  - Notice that it appears in plain `erc-notice-face' rather than
    `erc-current-nick-face' (a "match" face)

The attached patch should fix the issue. Thanks to Libera.Chat user jrm
for reporting this bug.

While we're at it, I'm thinking the option `erc-fill-spaced-commands',
which has been on HEAD for a few months now, should be demoted to a
plain variable, maybe even an internal one, because there aren't any
obvious use cases for non-default values. Unless someone has a good
argument to the contrary, I will do this in an accompanying patch to be
installed along with this one. Thanks.
0001-5.6-Account-for-leading-timestamps-in-erc-match.patch (text/x-patch, 9 KB)
From 21a63c280c6f8e0f45dcf67d53e43db39473155e Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email protected]>
Date: Tue, 27 Jun 2023 20:47:26 -0700
Subject: [PATCH] [5.6] Account for leading timestamps in erc-match

* lisp/erc/erc-match.el (erc-text-matched-hook): Mention that stamps
may be present in the narrowed buffer but absent from the message
parameter.
(erc-match--message): New function containing what was the body of
`erc-match-message' as if the latter were simply renamed.
(erc-match-message): Move body to `erc-match--message' and call it
with more aggressive narrowing.  This fixes a regression stemming from
d880a08f "Cement ordering of essential hook members in ERC".  Special
thanks to Libera.Chat user jrm for reporting this bug.  (Bug#60936)
---
 lisp/erc/erc-match.el                |  41 ++++++---
 test/lisp/erc/erc-scenarios-match.el | 119 +++++++++++++++++++++++++++
 2 files changed, 148 insertions(+), 12 deletions(-)
 create mode 100644 test/lisp/erc/erc-scenarios-match.el

diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el
index 6ba524ef9a8..204bf14a1cf 100644
--- a/lisp/erc/erc-match.el
+++ b/lisp/erc/erc-match.el
@@ -233,10 +233,14 @@ erc-beep-match-types
 		 (const :tag "Don't beep" nil)))
 
 (defcustom erc-text-matched-hook '(erc-log-matches)
-  "Hook run when text matches a given match-type.
-Functions in this hook are passed as arguments:
-\(match-type nick!user@host message) where MATCH-TYPE is a symbol of:
-current-nick, keyword, pal, dangerous-host, fool."
+  "Abnormal hook for visiting text matching a predefined \"type\".
+ERC calls members with the arguments (MATCH-TYPE NUH MESSAGE),
+where MATCH-TYPE is one of the symbols `current-nick', `keyword',
+`pal', `dangerous-host', `fool', and NUH is an `erc-response'
+sender, like [email protected].  Users should keep in mind
+that MESSAGE may not include decorations, such as white space or
+time stamps, preceding the same text as inserted in the narrowed
+buffer."
   :options '(erc-log-matches erc-hide-fools erc-beep-on-match)
   :type 'hook)
 
@@ -458,8 +462,19 @@ erc-match-directed-at-fool-p
 	(erc-list-match fools-end msg))))
 
 (defun erc-match-message ()
-  "Mark certain keywords in a region.
-Use this defun with `erc-insert-modify-hook'."
+  "Add faces to matching text in inserted message."
+  ;; Exclude leading whitespace, stamps, etc.
+  (let ((omin (point-min))
+        (beg (or (and (not (get-text-property (point-min) 'erc-command))
+                      (next-single-property-change (point-min) 'erc-command))
+                 (point-min))))
+    ;; FIXME when ERC no longer supports 28, use `with-restriction'
+    ;; with `:label' here instead of passing `omin'.
+    (save-restriction
+      (narrow-to-region beg (point-max))
+      (erc-match--message omin))))
+
+(defun erc-match--message (unrestricted-point-min)
   ;; This needs some refactoring.
   (goto-char (point-min))
   (let* ((to-match-nick-dep '("pal" "fool" "dangerous-host"))
@@ -561,12 +576,14 @@ erc-match-message
 					'font-lock-face match-face)))
 	      ;; Else twiddle your thumbs.
 	      (t nil))
-	     (run-hook-with-args
-	      'erc-text-matched-hook
-	      (intern match-type)
-	      (or nickuserhost
-		  (concat "Server:" (erc-get-parsed-vector-type vector)))
-	      message))))
+             ;; FIXME use `without-restriction' after dropping 28.
+             (save-restriction
+               (narrow-to-region unrestricted-point-min (point-max))
+               (run-hook-with-args
+                'erc-text-matched-hook (intern match-type)
+                (or nickuserhost
+                    (concat "Server:" (erc-get-parsed-vector-type vector)))
+                message)))))
        (if nickuserhost
 	   (append to-match-nick-dep to-match-nick-indep)
 	 to-match-nick-indep)))))
diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scenarios-match.el
new file mode 100644
index 00000000000..92131f22fa4
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-match.el
@@ -0,0 +1,119 @@
+;;; erc-scenarios-match.el --- Misc `erc-match' scenarios -*- lexical-binding: t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(require 'erc-match)
+
+;; This defends against a regression in which all matching by the
+;; `erc-match-message' fails when `erc-add-timestamp' precedes it in
+;; `erc-insert-modify-hook'.  Basically, `erc-match-message' used to
+;; expect an `erc-parsed' text property on the first character in a
+;; message, which doesn't exist, when the message content is prefixed
+;; by a leading timestamp.
+
+(ert-deftest erc-scenarios-match--stamp-left-current-nick ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (dumb-server (erc-d-run "localhost" t 'unexpected-disconnect))
+       (port (process-contact dumb-server :service))
+       (erc-server-flood-penalty 0.1)
+       (erc-insert-timestamp-function 'erc-insert-timestamp-left)
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :full-name "tester"
+                                :nick "tester")
+        (should (memq 'erc-match-message
+                      (memq 'erc-add-timestamp erc-insert-modify-hook)))
+        ;; The "match type" is `current-nick'.
+        (funcall expect 5 "tester")
+        (should (eq (get-text-property (1- (point)) 'font-lock-face)
+                    'erc-current-nick-face))))))
+
+;; This asserts that when stamps appear before a message,
+;; some non-nil invisibility property spans the entire message.
+(ert-deftest erc-scenarios-match--stamp-left-fools-invisible ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "join/legacy")
+       (dumb-server (erc-d-run "localhost" t 'foonet))
+       (port (process-contact dumb-server :service))
+       (erc-server-flood-penalty 0.1)
+       (erc-insert-timestamp-function 'erc-insert-timestamp-left)
+       (erc-timestamp-only-if-changed-flag nil)
+       (erc-fools '("bob"))
+       (erc-text-matched-hook '(erc-hide-fools))
+       (erc-autojoin-channels-alist '((FooNet "#chan")))
+       (expect (erc-d-t-make-expecter))
+       (hiddenp (lambda ()
+                  (and (eq (field-at-pos (pos-bol)) 'erc-timestamp)
+                       (get-text-property (pos-bol) 'invisible)
+                       (>= (next-single-property-change (pos-bol)
+                                                        'invisible nil)
+                           (pos-eol))))))
+
+    (ert-info ("Connect")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :full-name "tester"
+                                :password "changeme"
+                                :nick "tester")
+        (should (memq 'erc-match-message
+                      (memq 'erc-add-timestamp erc-insert-modify-hook)))
+        (funcall expect 5 "This server is in debug mode")))
+
+    (ert-info ("Ensure lines featuring \"bob\" are invisible")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (should (funcall expect 10 "<bob> tester, welcome!"))
+        (should (funcall hiddenp))
+
+        ;; Alice's is the only one visible.
+        (should (funcall expect 10 "<alice> tester, welcome!"))
+        (should (eq (field-at-pos (pos-bol)) 'erc-timestamp))
+        (should (get-text-property (pos-bol) 'invisible))
+        (should-not (get-text-property (point) 'invisible))
+
+        (should (funcall expect 10 "<bob> alice: But, as it seems"))
+        (should (funcall hiddenp))
+
+        (should (funcall expect 10 "<alice> bob: Well, this is the forest"))
+        (should (funcall hiddenp))
+
+        (should (funcall expect 10 "<alice> bob: And will you"))
+        (should (funcall hiddenp))
+
+        (should (funcall expect 10 "<bob> alice: Live, and be prosperous"))
+        (should (funcall hiddenp))
+
+        (should (funcall expect 10 "ERC>"))
+        (should-not (get-text-property (pos-bol) 'invisible))
+        (should-not (get-text-property (point) 'invisible))))))
+
+(eval-when-compile (require 'erc-join))
+
+;;; erc-scenarios-match.el ends here
-- 
2.40.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.