From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: "J.P." Newsgroups: gmane.emacs.bugs Subject: bug#64301: 30.0.50; ERC 5.6: Make speaker labels easier to work with Date: Sat, 15 Jul 2023 07:05:51 -0700 Message-ID: <87cz0tnubk.fsf__41639.9129129545$1689430055$gmane$org@neverwas.me> References: <87bkh21gfa.fsf@neverwas.me> <87sf9y32q9.fsf@neverwas.me> <87zg3zqlnr.fsf@neverwas.me> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="10840"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-erc@gnu.org To: 64301-done@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Jul 15 16:07:29 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1qKfvk-0002eL-Qk for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 15 Jul 2023 16:07:29 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qKfvM-0002lP-Cc; Sat, 15 Jul 2023 10:07:04 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qKfvK-0002iC-GO for bug-gnu-emacs@gnu.org; Sat, 15 Jul 2023 10:07:02 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qKfvK-000869-8b for bug-gnu-emacs@gnu.org; Sat, 15 Jul 2023 10:07:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1qKfvJ-0006xb-Mu for bug-gnu-emacs@gnu.org; Sat, 15 Jul 2023 10:07:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: "J.P." Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 15 Jul 2023 14:07:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 64301 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 64301-done@debbugs.gnu.org id=D64301.168942996426690 (code D ref 64301); Sat, 15 Jul 2023 14:07:01 +0000 Original-Received: (at 64301-done) by debbugs.gnu.org; 15 Jul 2023 14:06:04 +0000 Original-Received: from localhost ([127.0.0.1]:45675 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qKfuN-0006wP-K9 for submit@debbugs.gnu.org; Sat, 15 Jul 2023 10:06:04 -0400 Original-Received: from mail-108-mta89.mxroute.com ([136.175.108.89]:34697) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qKfuJ-0006vw-Jk for 64301-done@debbugs.gnu.org; Sat, 15 Jul 2023 10:06:02 -0400 Original-Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta89.mxroute.com (ZoneMTA) with ESMTPSA id 18959df51c70004cef.001 for <64301-done@debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sat, 15 Jul 2023 14:05:55 +0000 X-Zone-Loop: 10cb518fb4bd92cf39a01c4857ff7f6b0642f5d620f3 X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=neverwas.me ; s=x; h=Content-Type:MIME-Version:Message-ID:Date:References:In-Reply-To: Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=5X5gbCSwIiqGEo1cxob193MbvZmmL3B6+hEt0Ge/AMA=; b=Qkr4d9RuiQb8Ad31GAfUHjYK3B o8oLgileYQ4ZLhFgmsdwSOseUjXABJn/k9X6CzcJmbnjySCULxz7PT62xYCch9QjPbFBalwXFRJiR TTiSiIDU0N3C1XuY1IQt5AxY6ihD7esbepCvr49HX5s1yYJNtX3698ku8ph8tJETG37ReE2J1169E s42pEtz68ZDQyNVzMBgKx0qURqeAfPhMGsvUbouN7JKihNVgTtjHAWmIGl94Hl7qvxFSrqKY7mwor dz5OFotVBXW9wW60cO0cqiRiQmjc9/dCT4z6B8++twuGsPG38CTFxMujPjpzVQFJ4FGBpPdg44VsG 32uN4UgQ==; In-Reply-To: <87zg3zqlnr.fsf@neverwas.me> (J. P.'s message of "Thu, 13 Jul 2023 19:20:08 -0700") X-Authenticated-Id: masked@neverwas.me X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:265205 Archived-At: --=-=-= Content-Type: text/plain Some functionality I introduced for wrangling text properties in erc-match.el was shoddily done and not very usable from the perspective of another module building on erc-match as a foundation. The attached patch attempts to correct that. It also ditches "erc-" namespacing for invisibility spec members because the potential for collision seems pretty low given that we're only talking ERC buffers. (Hopefully, I'm not missing any downsides here.) --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Don-t-bother-namespacing-ERC-s-own-invisibility-.patch >From 9fe0a765eba8105ef616280487882247834c299a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Fri, 14 Jul 2023 21:08:31 -0700 Subject: [PATCH] [5.6] Don't bother namespacing ERC's own invisibility props * lisp/erc/erc-fill.el (erc-fill-wrap-mode, erc-fill-wrap-enable): Update name of internal flag for hiding messages. * lisp/erc/erc-match.el (erc-match--hide-fools-offset-bounds, erc-match--offset-invisible-bounds-p): Rename internal variable from former to latter. (erc-match--hide-fools-offset-bounds): Call `erc-match--hide-message' with own `invisible' property value specifically for fools. Specifically, use `match-fools' rather than `erc-match' or `erc-match-fools' to save room when visually inspecting. This retains the module name as a prefix to hopefully minimize collisions with invisibility spec members owned by non-ERC minor modes. (erc-match--hide-message): Define property parameter instead of hard-coding to `erc-match'. (erc-match--modify-invisibility-spec): Use toggle command non-interactively for adding and removing invisibility spec member. (erc-match-toggle-hidden-fools): Add explicit override argument and defer to general helper for actually modifying spec. (erc-match--toggle-hidden): New helper for toggling invisibility spec. * lisp/erc/erc.el (erc--merge-prop): If new value is a list, prepend onto existing. * test/lisp/erc/erc-scenarios-match.el: (erc-scenarios-match--invisible-stamp): Fix comment. (erc-scenarios-match--find-eol): Fix bug affecting interactive use. (erc-scenarios-match--stamp-left-fools-invisible, erc-scenarios-match--stamp-right-fools-invisible, erc-scenarios-match--stamp-right-invisible-fill-wrap, erc-scenarios-match--stamp-both-invisible-fill-static): Update `invisible' property from `erc-match' to `match-fools'. * test/lisp/erc/erc-tests.el (erc-tests--equal-including-properties): Relocate macro in same file. (erc--merge-prop): New test. (Bug#64301) --- lisp/erc/erc-fill.el | 4 +-- lisp/erc/erc-match.el | 43 +++++++++++++++-------- lisp/erc/erc.el | 9 +++-- test/lisp/erc/erc-scenarios-match.el | 51 ++++++++++++++++------------ test/lisp/erc/erc-tests.el | 50 +++++++++++++++++++++++---- 5 files changed, 110 insertions(+), 47 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index a65c95f1d85..2dfae35b871 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -290,7 +290,7 @@ erc-fill-wrap-mode-map (defvar erc-match-mode) (defvar erc-button-mode) -(defvar erc-match--hide-fools-offset-bounds) +(defvar erc-match--offset-invisible-bounds-p) (defun erc-fill--wrap-ensure-dependencies () (let (missing-deps) @@ -340,7 +340,7 @@ fill-wrap (erc-stamp--display-margin-mode +1)) (when (or (bound-and-true-p erc-match-mode) (memq 'match erc-modules)) (require 'erc-match) - (setq erc-match--hide-fools-offset-bounds t)) + (setq erc-match--offset-invisible-bounds-p t)) (when erc-fill-wrap-merge (add-hook 'erc-button--prev-next-predicate-functions #'erc-fill--wrap-merged-button-p nil t)) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index a5b0af41b2a..3fba35536b3 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -655,24 +655,25 @@ erc-go-to-log-matches-buffer (get-buffer (car buffer-cons)))))) (switch-to-buffer buffer-name))) -(defvar-local erc-match--hide-fools-offset-bounds nil) +(defvar-local erc-match--offset-invisible-bounds-p nil + "Whether to hide a message from its preceding newline.") (defun erc-hide-fools (match-type _nickuserhost _message) "Hide comments from designated fools." (when (eq match-type 'fool) - (erc-match--hide-message))) + (erc-match--hide-message 'match-fools))) -(defun erc-match--hide-message () +(defun erc-match--hide-message (prop) (progn ; FIXME raise sexp - (if erc-match--hide-fools-offset-bounds + (if erc-match--offset-invisible-bounds-p (let ((beg (point-min)) (end (point-max))) (save-restriction (widen) - (erc--merge-prop (1- beg) (1- end) 'invisible 'erc-match))) + (erc--merge-prop (1- beg) (1- end) 'invisible prop))) ;; Before ERC 5.6, this also used to add an `intangible' ;; property, but the docs say it's now obsolete. - (erc--merge-prop (point-min) (point-max) 'invisible 'erc-match)))) + (erc--merge-prop (point-min) (point-max) 'invisible prop)))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -682,19 +683,31 @@ erc-beep-on-match (defun erc-match--modify-invisibility-spec () "Add an `erc-match' property to the local spec." + ;; Hopefully, this will be extended to do the same for other + ;; invisible properties managed by this module. (if erc-match-mode - (add-to-invisibility-spec 'erc-match) + (erc-match-toggle-hidden-fools +1) (erc-with-all-buffers-of-server nil nil - (remove-from-invisibility-spec 'erc-match)))) + (erc-match-toggle-hidden-fools -1)))) -(defun erc-match-toggle-hidden-fools () +(defun erc-match-toggle-hidden-fools (arg) "Toggle fool visibility. -Expect `erc-hide-fools' or a function that does something similar -to be in `erc-text-matched-hook'." - (interactive) - (if (memq 'erc-match (ensure-list buffer-invisibility-spec)) - (remove-from-invisibility-spec 'erc-match) - (add-to-invisibility-spec 'erc-match))) +Expect the function `erc-hide-fools' or similar to be present in +`erc-text-matched-hook'." + (interactive "P") + (erc-match--toggle-hidden 'match-fools arg)) + +(defun erc-match--toggle-hidden (prop arg) + "Toggle invisibility for spec member PROP. +Treat ARG in a manner similar to mode toggles defined by +`define-minor-mode'." + (when arg + (setq arg (prefix-numeric-value arg))) + (if (memq prop (ensure-list buffer-invisibility-spec)) + (unless (natnump arg) + (remove-from-invisibility-spec prop)) + (when (or (not arg) (natnump arg)) + (add-to-invisibility-spec prop)))) (provide 'erc-match) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 03c21059a92..6ed919c91c2 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3011,13 +3011,18 @@ erc--merge-prop "Compose existing PROP values with VAL between FROM and TO in OBJECT. For spans where PROP is non-nil, cons VAL onto the existing value, ensuring a proper list. Otherwise, just set PROP to VAL. -See also `erc-button-add-face'." +When VAL is itself a list, prepend its members onto an existing +value. See also `erc-button-add-face'." (let ((old (get-text-property from prop object)) (pos from) (end (next-single-property-change from prop object to)) new) (while (< pos to) - (setq new (if old (cons val (ensure-list old)) val)) + (setq new (if old + (if (listp val) + (append val (ensure-list old)) + (cons val (ensure-list old))) + val)) (put-text-property pos end prop new object) (setq pos end old (get-text-property pos prop object) diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scenarios-match.el index 8a718962c55..a438635960e 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -62,11 +62,15 @@ erc-scenarios-match--stamp-left-current-nick 'erc-current-nick-face)))))) ;; When hacking on tests that use this fixture, it's best to run it -;; interactively, and check for wierdness before and after doing -;; M-: (remove-from-invisibility-spec 'erc-match) RET. +;; interactively, and visually inspect the output with various +;; combinations of: +;; +;; M-x erc-match-toggle-hidden-fools RET +;; M-x erc-toggle-timestamps RET +;; (defun erc-scenarios-match--invisible-stamp (hiddenp visiblep) (unless noninteractive - (kill-new "(remove-from-invisibility-spec 'erc-match)")) + (kill-new "erc-match-toggle-hidden-fools")) (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "join/legacy") @@ -128,11 +132,11 @@ erc-scenarios-match--stamp-left-fools-invisible ;; Leading stamp has combined `invisible' property value. (should (equal (get-text-property (pos-bol) 'invisible) - '(timestamp erc-match))) + '(timestamp match-fools))) - ;; Message proper has the `invisible' property `erc-match'. + ;; Message proper has the `invisible' property `match-fools'. (let ((msg-beg (next-single-property-change (pos-bol) 'invisible))) - (should (eq (get-text-property msg-beg 'invisible) 'erc-match)) + (should (eq (get-text-property msg-beg 'invisible) 'match-fools)) (should (>= (next-single-property-change msg-beg 'invisible nil) (pos-eol))))) @@ -149,7 +153,10 @@ erc-scenarios-match--stamp-left-fools-invisible (defun erc-scenarios-match--find-eol () (save-excursion - (goto-char (next-single-property-change (point) 'erc-command)) + (if-let ((next (next-single-property-change (point) 'erc-command))) + (goto-char next) + ;; We're already at the end of the message. + (should (get-text-property (1- (point)) 'erc-command))) (pos-eol))) ;; In most cases, `erc-hide-fools' makes line endings invisible. @@ -168,19 +175,19 @@ erc-scenarios-match--stamp-right-fools-invisible ;; Stamps have a combined `invisible' property value. (should (equal (get-text-property (1- end) 'invisible) - '(timestamp erc-match))) + '(timestamp match-fools))) ;; The final newline is hidden by `match', not `stamps' - (should (equal (get-text-property end 'invisible) 'erc-match)) + (should (equal (get-text-property end 'invisible) 'match-fools)) - ;; The message proper has the `invisible' property `erc-match', + ;; The message proper has the `invisible' property `match-fools', ;; and it starts after the preceding newline. - (should (eq (get-text-property (pos-bol) 'invisible) 'erc-match)) + (should (eq (get-text-property (pos-bol) 'invisible) 'match-fools)) ;; It ends just before the timestamp. (let ((msg-end (next-single-property-change (pos-bol) 'invisible))) (should (equal (get-text-property msg-end 'invisible) - '(timestamp erc-match))) + '(timestamp match-fools))) ;; Stamp's `invisible' property extends throughout the stamp ;; and ends before the trailing newline. @@ -215,16 +222,16 @@ erc-scenarios-match--stamp-right-invisible-fill-wrap ;; Stamps have a combined `invisible' property value. (should (equal (get-text-property (1- (pos-eol)) 'invisible) - '(timestamp erc-match))) + '(timestamp match-fools))) - ;; The message proper has the `invisible' property `erc-match', + ;; The message proper has the `invisible' property `match-fools', ;; which starts at the preceding newline... - (should (eq (get-text-property (1- (pos-bol)) 'invisible) 'erc-match)) + (should (eq (get-text-property (1- (pos-bol)) 'invisible) 'match-fools)) ;; ... and ends just before the timestamp. (let ((msgend (next-single-property-change (1- (pos-bol)) 'invisible))) (should (equal (get-text-property msgend 'invisible) - '(timestamp erc-match))) + '(timestamp match-fools))) ;; The newline before `erc-insert-marker' is still visible. (should-not (get-text-property (pos-eol) 'invisible)) @@ -265,8 +272,8 @@ erc-scenarios-match--stamp-both-invisible-fill-static (search-forward "[23:59]")))) (ert-info ("Line endings in Bob's messages are invisible") - ;; The message proper has the `invisible' property `erc-match'. - (should (eq (get-text-property (pos-bol) 'invisible) 'erc-match)) + ;; The message proper has the `invisible' property `match-fools'. + (should (eq (get-text-property (pos-bol) 'invisible) 'match-fools)) (let* ((mbeg (next-single-property-change (pos-bol) 'erc-command)) (mend (next-single-property-change mbeg 'erc-command))) @@ -283,9 +290,9 @@ erc-scenarios-match--stamp-both-invisible-fill-static (should (= (next-single-property-change (pos-bol) 'erc-timestamp) mend)) - ;; Line ending has the `invisible' property `erc-match'. + ;; Line ending has the `invisible' property `match-fools'. (should (= (char-after mend) ?\n)) - (should (eq (get-text-property mend'invisible) 'erc-match)))) + (should (eq (get-text-property mend'invisible) 'match-fools)))) ;; Only the message right after Alice speaks contains stamps. (when (= 1 bob-utterance-counter) @@ -298,7 +305,7 @@ erc-scenarios-match--stamp-both-invisible-fill-static ;; Date stamp has a combined `invisible' property value ;; that extends until the start of the message proper. (should (equal (get-text-property (point) 'invisible) - '(timestamp erc-match))) + '(timestamp match-fools))) (should (= (next-single-property-change (point) 'invisible) (1+ (pos-eol)))))) @@ -314,7 +321,7 @@ erc-scenarios-match--stamp-both-invisible-fill-static (let ((msgend (next-single-property-change (pos-bol) 'invisible))) ;; Stamp has a combined `invisible' property value. (should (equal (get-text-property msgend 'invisible) - '(timestamp erc-match))) + '(timestamp match-fools))) ;; Combined `invisible' property spans entire timestamp. (should (= (next-single-property-change msgend 'invisible) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b5db5fe8764..610fb149a94 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1272,6 +1272,50 @@ erc-process-input-line (should-not calls)))))) +(defmacro erc-tests--equal-including-properties (a b) + (list (if (< emacs-major-version 29) + 'ert-equal-including-properties + 'equal-including-properties) + a b)) + +(ert-deftest erc--merge-prop () + (with-current-buffer (get-buffer-create "*erc-test*") + ;; Baseline. + (insert "abc\n") + (erc--merge-prop 1 3 'erc-test 'x) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 0 2 (erc-test x)))) + (erc--merge-prop 1 3 'erc-test 'y) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 0 2 (erc-test (y x))))) + + ;; Multiple intervals. + (goto-char (point-min)) + (insert "def\n") + (erc--merge-prop 1 2 'erc-test 'x) + (erc--merge-prop 2 3 'erc-test 'y) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) + #("def" 0 1 (erc-test x) 1 2 (erc-test y)))) + (erc--merge-prop 1 3 'erc-test 'z) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) + #("def" 0 1 (erc-test (z x)) 1 2 (erc-test (z y))))) + + ;; New val as list. + (goto-char (point-min)) + (insert "ghi\n") + (erc--merge-prop 2 3 'erc-test '(y z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" 1 2 (erc-test (y z))))) + (erc--merge-prop 1 3 'erc-test '(w x)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) + #("ghi" 0 1 (erc-test (w x)) 1 2 (erc-test (w x y z))))) + + (when noninteractive + (kill-buffer)))) + (ert-deftest erc--split-string-shell-cmd () ;; Leading and trailing space @@ -1488,12 +1532,6 @@ erc-message (kill-buffer "ExampleNet") (kill-buffer "#chan"))) -(defmacro erc-tests--equal-including-properties (a b) - (list (if (< emacs-major-version 29) - 'ert-equal-including-properties - 'equal-including-properties) - a b)) - (ert-deftest erc-format-privmessage () ;; Basic PRIVMSG (should (erc-tests--equal-including-properties -- 2.41.0 --=-=-=--