emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 99d74dcd459 1/2: Account for leading timestamps in erc-match


From: F. Jason Park
Subject: master 99d74dcd459 1/2: Account for leading timestamps in erc-match
Date: Sat, 1 Jul 2023 10:25:35 -0400 (EDT)

branch: master
commit 99d74dcd45938e2686d93eb5649800e14a88cd84
Author: F. Jason Park <jp@neverwas.me>
Commit: F. Jason Park <jp@neverwas.me>

    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)
    * test/lisp/erc/erc-scenarios-match.el: New test file.
---
 lisp/erc/erc-match.el                |  41 ++++++++----
 test/lisp/erc/erc-scenarios-match.el | 120 +++++++++++++++++++++++++++++++++++
 2 files changed, 149 insertions(+), 12 deletions(-)

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 @@ for beeping to work."
                 (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 bob!~bob@example.org.  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 @@ In any of the following situations, MSG is directed at an 
entry FOOL:
        (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 @@ Use this defun with `erc-insert-modify-hook'."
                                        '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..49e6a3370fc
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-match.el
@@ -0,0 +1,120 @@
+;;; 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-stamp)
+(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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]