"J.P." <jp@HIDDEN>
to control <at> debbugs.gnu.org
.
Full text available.Debbugs Internal Request <help-debbugs@HIDDEN>
to internal_control <at> debbugs.gnu.org
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 21 Feb 2024 01:12:53 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Feb 20 20:12:53 2024 Received: from localhost ([127.0.0.1]:47369 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1rcbAK-0002v5-SQ for submit <at> debbugs.gnu.org; Tue, 20 Feb 2024 20:12:53 -0500 Received: from mail-108-mta120.mxroute.com ([136.175.108.120]:39487) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1rcbAI-0002ux-A7 for 60936 <at> debbugs.gnu.org; Tue, 20 Feb 2024 20:12:51 -0500 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta120.mxroute.com (ZoneMTA) with ESMTPSA id 18dc93898d40000466.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 21 Feb 2024 01:12:26 +0000 X-Zone-Loop: 2b69a1ae7dedbc56bf804f509ebd2f12433a91054239 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=ggGEwxj2XdVyNsR7arGgd9UYRB8IxCrj7KI/4ysPcb8=; b=bNeQoObEvEdm8UunbNWHW7Dn/L Z4h035DneLfc/BLHQDlxvqSg5lqYNQspXbr3RBNpbYfY9q2c+ODykMV4oVeoWC8hmJZcwAimMBqHx sk8DORntqbg7h1M1tNruNRbX7WL28em6dA3fKBaQgWUN2T3XxuBSkbcrAgTXlpSgMv+/3BnXuQL2K H77iKyMLaJ/eqIHF+7mHjkxWf869Ect9nFiJpdtzJwdZQk4IB+Iom+qwKjXwJjOJf5gbIEZHIG9DO n+/YVlGbEqrMwF4QbROoCDF9Gk/weO5G5R7tSOsf4bEk2IppHjEXACG0mpDzZ7wuIzCRTYWSNxvwf /3yv/VKg==; From: "J.P." <jp@HIDDEN> To: tzakmagiel <tzakmagiel@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <KPysm9zdlPJ7tiM8TA5RnzTFIFDYab4u7zAjMYC4I-cmQ8d9QJv4HSMZThRH746ByndGJ_lEMtMMgo78ueqFnoXtG_Qfn7Wy0SmsGTieTds=@proton.me> (tzakmagiel via's message of "Thu, 15 Feb 2024 12:01:07 +0000") References: <87tu0nao77.fsf@HIDDEN> <KPysm9zdlPJ7tiM8TA5RnzTFIFDYab4u7zAjMYC4I-cmQ8d9QJv4HSMZThRH746ByndGJ_lEMtMMgo78ueqFnoXtG_Qfn7Wy0SmsGTieTds=@proton.me> Date: Tue, 20 Feb 2024 17:12:23 -0800 Message-ID: <87sf1mboy0.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -1.9 (-) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -2.9 (--) tzakmagiel writes: > +1'ing this the issue in Message #166 for visibility. I raised this question > under the nick "alcor" on #erc yesterday, and I agree that the default > behavior of `fill-wrap' (i.e. without `scrolltobottom') might be > confusing/unexpected for new `fill-wrap' users (such as myself, in this case). > > For the record, the behavior without the scrolltobottom module could be > described as "messages tend to drift upward on screen, gradually increasing > the whitespace between prompt and bottom of window" (This description courtesy > of corwin on #erc). > >>I'm thinking it might make sense to have `fill-wrap' formally depend on > `scrolltobottom', even though there's no technical reason to do so. > > +1 on that too. The behavior with `scrolltobottom' makes more sense (as a > default) and is more in line with other IRC clients, where the message prompt > is kept at the bottom of the window. Appreciate the input. `fill-wrap' now activates `scrolltobottom' if not already enabled and also reminds users to add it to `erc-modules' when that's the case: https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=9668b4f9 Please let us know if something's still amiss or if the fix is otherwise inadequate. Thanks.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 15 Feb 2024 12:01:47 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 15 07:01:47 2024 Received: from localhost ([127.0.0.1]:54334 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1raaR1-0000vE-Ic for submit <at> debbugs.gnu.org; Thu, 15 Feb 2024 07:01:47 -0500 Received: from mail-4325.protonmail.ch ([185.70.43.25]:21541) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <tzakmagiel@HIDDEN>) id 1raaR0-0000v1-0k for 60936 <at> debbugs.gnu.org; Thu, 15 Feb 2024 07:01:46 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1707998481; x=1708257681; bh=TjBLKgSxKMupZ7bt38kEcnXwoFo37oHvAJoXUKhINsE=; h=Date:To:From:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=B0nSrogIS3dc4k0b3s5YsCRVUKoXRrTkbw09SE5zZC0XwuxFks1dDz73uwjTahn0k K5IJfIhKTUvALjTM9MkZotvbZE38Fdje+mQE5hvYNfNRg4z5i3V3Hka6Yb9bzKw+9u mSl1+bB8Ciw4JuSgIJELfS/r1f09UGB+a97Q5PAPQ752X6IMUnfJBJ/IXuO3L5uJ1H kOxMGr51bsQWM9UvGkgLirZsKPBIkdRtThbrjR0tybx1iVjFIDN5sE0HMjdYcUAnii obhIyWJSl6647uLX8ewQG67z+HCgFIHHGbZL1vSwMgr/7i4RpKvs7KqLtE7MW8Wmju pg60ODhDKdA3w== Date: Thu, 15 Feb 2024 12:01:07 +0000 To: "60936 <at> debbugs.gnu.org" <60936 <at> debbugs.gnu.org> From: tzakmagiel <tzakmagiel@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Message-ID: <KPysm9zdlPJ7tiM8TA5RnzTFIFDYab4u7zAjMYC4I-cmQ8d9QJv4HSMZThRH746ByndGJ_lEMtMMgo78ueqFnoXtG_Qfn7Wy0SmsGTieTds=@proton.me> Feedback-ID: 101103031:user:proton MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -1.9 (-) X-Debbugs-Envelope-To: 60936 X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -2.9 (--) +1'ing this the issue in Message #166 for visibility. I raised this questio= n under the nick "alcor" on #erc yesterday, and I agree that the default be= havior of `fill-wrap' (i.e. without `scrolltobottom') might be confusing/un= expected for new `fill-wrap' users (such as myself, in this case). For the record, the behavior without the scrolltobottom module could be des= cribed as "messages tend to drift upward on screen, gradually increasing th= e whitespace between prompt and bottom of window" (This description courtes= y of corwin on #erc). >I'm thinking it might make sense to have `fill-wrap' formally depend on `s= crolltobottom', even though there's no technical reason to do so. +1 on that too. The behavior with `scrolltobottom' makes more sense (as a d= efault) and is more in line with other IRC clients, where the message promp= t is kept at the bottom of the window.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.tzakmagiel <tzakmagiel@HIDDEN>
to control <at> debbugs.gnu.org
.
Full text available.Debbugs Internal Request <help-debbugs@HIDDEN>
to internal_control <at> debbugs.gnu.org
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 7 Dec 2023 07:14:56 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Thu Dec 07 02:14:56 2023 Received: from localhost ([127.0.0.1]:40911 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1rB8b2-0006Dz-Iu for submit <at> debbugs.gnu.org; Thu, 07 Dec 2023 02:14:56 -0500 Received: from mail-108-mta235.mxroute.com ([136.175.108.235]:45025) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1rB8b0-0006Do-0H for 60936 <at> debbugs.gnu.org; Thu, 07 Dec 2023 02:14:54 -0500 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta235.mxroute.com (ZoneMTA) with ESMTPSA id 18c4320e60a000190b.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Thu, 07 Dec 2023 07:14:38 +0000 X-Zone-Loop: 7c211717431dbfe7a724ec851c5e3de0d75727deb04d 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=IDqvN3YB5OpfVhqEsg2hx9joLkqPZlrSkUuN388nYO8=; b=RcNfXZV/R10CRztjKhAJI8BSnX 21Re0/6LCE2d+kI9VseccYt4EEXitTKkSefaHpnBVfUJGG9m8f23g8cCoz5dQdJdZeTf8WNZIm8Nn louJc2Fw3mLNJwWciCaIbwCWUBQwCdbtb9Ye+VYGt3Na+Lh2YRc+0Hg/9pwwWMEl+OGuwycLbnOFT klawFaLFU3SNNTeA8EFmtSRhqWps3aPH5O22Ujqmkq8BAo7aykAkYV5hoqMTrpXDjfYwXLBCzl69H /s6W+a1tUlJfD5da9Ew+unNbP71scvOVqRcYOn59FQ4JINs1v3pTOVjLRjzUyPzRD/P41sq5ENdQw Q1EDBzLA==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Wed, 06 Dec 2023 23:14:33 -0800 Message-ID: <878r667acm.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain Changes related to this feature introduced a number of meta-data oriented text properties that I think, in retrospect, should have been double-hyphenated to dissuade users from depending on them. Also, a couple of properties, like `erc-stamp-type', are superfluous, and can be removed. The first of the attached patches should take care of this. There's also (IMO) a rather obvious need for an `erc--spkr' property to aid modules in quickly distinguishing between inserted messages based on their speaker (nick). For example, a module that detects continued messages that should be displayed as a single unit might otherwise have to keep a local backlog or parse inserted messages at runtime. The second of the attached patches tries to address this. Lastly, in "designing" the makeup of these properties, I chose to assign a constant `msg' value for the required `erc--msg' property to all speaker-owned messages, like those originating from PRIVMSG and NOTICE commands. The idea was to allow modules to distinguish between speaker messages and other types. However, making `erc--msg' a union of `msg' and `format-spec' "catalog" keys (and `erc-display-message' TYPE parameters) meant coercing keys for speaker messages to `msg', thereby discarding what now looks to be valuable information (especially in light of bug#67677). Thus, I'm proposing we remove `msg' as an advertised `erc--msg' value and instead rely on `erc--spkr' to convey speaker associations. See bug#67677 for more. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Double-hyphenate-internal-ERC-5.6-text-props.patch Content-Transfer-Encoding: quoted-printable From 218a4f1f4b405fe5c7d934948bdc12a9ea0f2baf Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 1 Dec 2023 22:30:04 -0800 Subject: [PATCH 03/11] [5.6] Double hyphenate internal ERC 5.6 text props * lisp/erc/erc-fill.el (erc-fill, erc-fill-static, erc-fill--wrap-continued-message-p, erc-fill-wrap, erc-fill--wrap-rejigger-region): Add second hyphen to "msg prop" text properties. * lisp/erc/erc-goodies.el (erc--command-indicator-display): Rename `erc-msg' to `erc--msg'. * lisp/erc/erc-stamp.el (erc-stamp--current-time, erc-add-timestamp, erc-stamp-prefix-log-filter, erc-stamp--lr-date-on-pre-modify, erc-munge-invisibility-spec, erc-stamp--add-csf-on-post-modify, erc-stamp--on-clear-message, erc-echo-timestamp, erc--echo-ts-csf): Rename "msg props" with second hyphen. * lisp/erc/erc-track.el (erc-track--skipped-msgs, erc-track-modified-channels): Rename "msg prop" text properties with second hyphen. * lisp/erc/erc.el (erc--msg-props): Update doc with double-hyphenated "msg prop" names. (erc--send-action-display erc--get-inserted-msg-bounds, erc--traverse-inserted, erc-insert-line, erc-display-line, erc--ranked-properties, erc-display-message, erc--get-speaker-bounds, erc-process-ctcp-query, erc-display-msg): Update all "msg prop" names to have two hyphens. * test/lisp/erc/erc-scenarios-display-message.el (erc-scenarios-display-message--multibuf): Double hyphenate "msg prop" text properties. * test/lisp/erc/erc-scenarios-match.el (erc-scenarios-match--hide-fools/stamp-both/fill-wrap, erc-scenarios-match--hide-fools/stamp-both/fill-wrap/speak, erc-scenarios-match--stamp-both-invisible-fill-static): Update "msg prop" names. * test/lisp/erc/erc-scenarios-stamp.el (erc-scenarios-stamp--on-post-modify, erc-scenarios-stamp--left/display-margin-mode, erc-scenarios-stamp--legacy-date-stamps, erc-scenarios-stamp--on-insert-modify, erc-scenarios-stamp--date-mode/left-and-right): Add second hyphen to all "msg props". * test/lisp/erc/erc-stamp-tests.el (erc-echo-timestamp): Rename "msg prop". * test/lisp/erc/erc-tests.el (erc--get-inserted-msg-bounds, erc--delete-inserted-message, erc--order-text-properties-from-hash, erc--route-insertion): Rename "msg props" with second hyphen. (Bug#60936) ; * test/lisp/erc/resources/fill/snapshots/merge-01-start.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/merge-02-right.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld: ; Add second hyphen to msg props. ; * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: ; Add second hyphen to msg props. --- lisp/erc/erc-fill.el | 22 ++++---- lisp/erc/erc-goodies.el | 2 +- lisp/erc/erc-stamp.el | 24 ++++----- lisp/erc/erc-track.el | 4 +- lisp/erc/erc.el | 50 +++++++++---------- .../lisp/erc/erc-scenarios-display-message.el | 4 +- test/lisp/erc/erc-scenarios-match.el | 14 +++--- test/lisp/erc/erc-scenarios-stamp.el | 18 +++---- test/lisp/erc/erc-stamp-tests.el | 2 +- test/lisp/erc/erc-tests.el | 20 ++++---- .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../merge-wrap-indicator-post-01.eld | 2 +- .../snapshots/merge-wrap-indicator-pre-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 21 files changed, 91 insertions(+), 91 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 9b0c74b518d..5434d9af966 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -177,10 +177,10 @@ erc-fill (when-let ((erc-fill-line-spacing) (p (point-min))) (widen) - (when (or (erc--check-msg-prop 'erc-msg 'msg) + (when (or (erc--check-msg-prop 'erc--msg 'msg) (and-let* ((m (save-excursion (forward-line -1) - (erc--get-inserted-msg-prop 'erc-msg= )))) + (erc--get-inserted-msg-prop 'erc--ms= g)))) (eq 'msg m))) (put-text-property (1- p) p 'line-spacing erc-fill-line-spacing))))))= )) @@ -190,7 +190,7 @@ erc-fill-static (save-restriction (goto-char (point-min)) (when-let (((looking-at "^\\(\\S-+\\)")) - ((not (erc--check-msg-prop 'erc-msg 'datestamp))) + ((not (erc--check-msg-prop 'erc--msg 'datestamp))) (nick (match-string 1))) (progn (let ((fill-column (- erc-fill-column (erc-timestamp-offset))) @@ -557,7 +557,7 @@ erc-fill--wrap-continued-message-p advance `erc-fill--wrap-last-msg' unless the message has been marked as being ephemeral." (and - (not (erc--check-msg-prop 'erc-ephemeral)) + (not (erc--check-msg-prop 'erc--ephemeral)) (progn ; preserve blame for now, unprogn on next major change (prog1 (and-let* @@ -568,12 +568,12 @@ erc-fill--wrap-continued-message-p (props (save-restriction (widen) (and-let* - (((eq 'msg (get-text-property m 'erc-msg))) - ((not (eq (get-text-property m 'erc-ctcp) + (((eq 'msg (get-text-property m 'erc--msg))) + ((not (eq (get-text-property m 'erc--ctcp) 'ACTION))) ((not (invisible-p m))) (spr (next-single-property-change m 'erc-speak= er))) - (cons (get-text-property m 'erc-ts) + (cons (get-text-property m 'erc--ts) (get-text-property spr 'erc-speaker))))) (ts (pop props)) (props) @@ -582,7 +582,7 @@ erc-fill--wrap-continued-message-p erc-fill--wrap-max-lull)) ;; Assume presence of leading angle bracket or hyphen. (speaker (next-single-property-change (point-min) 'erc-speak= er)) - ((not (erc--check-msg-prop 'erc-ctcp 'ACTION))) + ((not (erc--check-msg-prop 'erc--ctcp 'ACTION))) (nick (get-text-property speaker 'erc-speaker)) ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))))) @@ -668,12 +668,12 @@ erc-fill-wrap (goto-char (point-min)) (let ((len (or (and erc-fill--wrap-length-function (funcall erc-fill--wrap-length-function)) - (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg)) + (and-let* ((msg-prop (erc--check-msg-prop 'erc--msg)) ((not (eq msg-prop 'unknown)))) (when-let ((e (erc--get-speaker-bounds)) (b (pop e)) ((or erc-fill--wrap-action-dedent-p - (not (erc--check-msg-prop 'erc-ctcp + (not (erc--check-msg-prop 'erc--ctcp 'ACTION))))) (goto-char e)) (skip-syntax-forward "^-") @@ -755,7 +755,7 @@ erc-fill--wrap-rejigger-region (field-beginning beg) beg)) (erc--msg-props (map-into (text-properties-at pos) 'hash-tabl= e)) - (erc-stamp--current-time (gethash 'erc-ts erc--msg-props))) + (erc-stamp--current-time (gethash 'erc--ts erc--msg-props))) (save-restriction (narrow-to-region beg (1+ end)) (let ((erc-fill--wrap-last-msg erc-fill--wrap-rejigger-last-mess= age)) diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index 6c8ec567bd9..e10f047b187 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -578,7 +578,7 @@ erc--command-indicator-display (let ((insert-position (marker-position (goto-char erc-insert-marker= ))) (erc--msg-props (or erc--msg-props (let ((ovs erc--msg-prop-overrides)) - (map-into `((erc-msg . slash-cmd) + (map-into `((erc--msg . slash-cmd) ,@(reverse ovs)) 'hash-table))))) (when-let ((string (erc-command-indicator)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index e6a8f36c332..a6efa3b5151 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -212,7 +212,7 @@ erc-stamp--current-time =20 (cl-defgeneric erc-stamp--current-time () "Return a lisp time object to associate with an IRC message. -This becomes the message's `erc-ts' text property." +This becomes the message's `erc--ts' text property." (erc-compat--current-lisp-time)) =20 (cl-defmethod erc-stamp--current-time :around () @@ -249,10 +249,10 @@ erc-add-timestamp ;; FIXME on major version bump, make this `erc-' prefixed. (if invisible `(timestamp ,@(ensure-list invisible)) 'timestam= p)) (skipp (or (and erc-stamp--skip-when-invisible invisible) - (erc--check-msg-prop 'erc-ephemeral))) + (erc--check-msg-prop 'erc--ephemeral))) (erc-stamp--current-time ct)) (when erc--msg-props - (puthash 'erc-ts ct erc--msg-props)) + (puthash 'erc--ts ct erc--msg-props)) (unless skipp (funcall erc-insert-timestamp-function (erc-format-timestamp ct erc-timestamp-format))) @@ -270,7 +270,7 @@ erc-add-timestamp ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions ;; Regions are no longer contiguous ^ - '(erc--echo-ts-csf) 'erc-ts ct)))))) + '(erc--echo-ts-csf) 'erc--ts ct)))))) =20 (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -403,7 +403,7 @@ erc-stamp-prefix-log-filter ;; Skip a line that's just a timestamp. ((> beg (point)))) (delete-region beg (1+ end))) - (when-let (time (erc--get-inserted-msg-prop 'erc-ts)) + (when-let (time (erc--get-inserted-msg-prop 'erc--ts)) (insert (format-time-string "[%H:%M:%S] " time))) (zerop (forward-line)))) "") @@ -711,8 +711,8 @@ erc-stamp--lr-date-on-pre-modify (setq erc-timestamp-last-inserted-left nil) (let* ((aligned (erc-stamp--time-as-day ct)) (erc-stamp--current-time aligned) - ;; Forget current `erc-cmd', etc. - (erc--msg-props (map-into `((erc-msg . datestamp)) + ;; Forget current `erc--cmd', etc. + (erc--msg-props (map-into `((erc--msg . datestamp)) 'hash-table)) (erc-timestamp-last-inserted-left rendered) erc-timestamp-format erc-away-timestamp-format) @@ -867,7 +867,7 @@ erc-munge-invisibility-spec erc-stamp--csf-props-updated-p nil) (unless erc-stamp--csf-props-updated-p (setq erc-stamp--csf-props-updated-p t) - (let ((erc--msg-props (map-into '((erc-ts . t)) 'hash-table))) + (let ((erc--msg-props (map-into '((erc--ts . t)) 'hash-table))) (with-silent-modifications (erc--traverse-inserted (point-min) erc-insert-marker @@ -889,7 +889,7 @@ erc-munge-invisibility-spec =20 (defun erc-stamp--add-csf-on-post-modify () "Add `cursor-sensor-functions' to narrowed buffer." - (when (erc--check-msg-prop 'erc-ts) + (when (erc--check-msg-prop 'erc--ts) (put-text-property (point-min) (1- (point-max)) 'cursor-sensor-functions '(erc--echo-ts-csf)))) =20 @@ -940,7 +940,7 @@ erc-stamp--last-stamp (defun erc-stamp--on-clear-message (&rest _) "Return `dont-clear-message' when operating inside the same stamp." (and erc-stamp--last-stamp erc-echo-timestamps - (eq (erc--get-inserted-msg-prop 'erc-ts) erc-stamp--last-stamp) + (eq (erc--get-inserted-msg-prop 'erc--ts) erc-stamp--last-stamp) 'dont-clear-message)) =20 (defun erc-echo-timestamp (dir stamp &optional zone) @@ -950,7 +950,7 @@ erc-echo-timestamp interpret a \"raw\" prefix as UTC. To specify a zone for use with the option `erc-echo-timestamps', see the companion option `erc-echo-timestamp-zone'." - (interactive (list nil (erc--get-inserted-msg-prop 'erc-ts) + (interactive (list nil (erc--get-inserted-msg-prop 'erc--ts) (pcase current-prefix-arg ((and (pred numberp) v) (if (<=3D (abs v) 14) (* v 3600) v)) @@ -964,7 +964,7 @@ erc-echo-timestamp (setq erc-stamp--last-stamp nil)))) =20 (defun erc--echo-ts-csf (_window _before dir) - (erc-echo-timestamp dir (erc--get-inserted-msg-prop 'erc-ts))) + (erc-echo-timestamp dir (erc--get-inserted-msg-prop 'erc--ts))) =20 (defun erc-stamp--update-saved-position (&rest _) (remove-hook 'erc-stamp--insert-date-hook diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el index a36b781e04d..7dc4fe754cd 100644 --- a/lisp/erc/erc-track.el +++ b/lisp/erc/erc-track.el @@ -786,7 +786,7 @@ erc-track-select-mode-line-face choice)))) =20 (defvar erc-track--skipped-msgs '(datestamp) - "Values of `erc-msg' text prop to ignore.") + "Values of `erc--msg' text prop to ignore.") =20 (defun erc-track-modified-channels () "Hook function for `erc-insert-post-hook'. @@ -806,7 +806,7 @@ erc-track-modified-channels erc-track-exclude-types) ;; Skip certain non-server-sent messages. (and (not parsed) - (erc--check-msg-prop 'erc-msg + (erc--check-msg-prop 'erc--msg erc-track--skipped-msgs)= ))))) ;; If the active buffer is not visible (not shown in a ;; window), and not to be excluded, determine the kinds of diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index a42c50d91ff..c68c74467b8 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -154,26 +154,26 @@ erc--msg-props their markers accordingly. The following properties have meaning as of ERC 5.6: =20 - - `erc-msg': a symbol, guaranteed present; values include: + - `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' =20 - - `erc-cmd': a message's associated IRC command, as read by + - `erc--cmd': a message's associated IRC command, as read by `erc--get-eq-comparable-cmd'; currently either a symbol, like `PRIVMSG', or a number, like 5, which represents the numeric \"005\"; absent on \"local\" messages, such as simple warnings and help text, and on outgoing messages unless echoed back by the server (assuming future support) =20 - - `erc-ctcp': a CTCP command, like `ACTION' + - `erc--ctcp': a CTCP command, like `ACTION' =20 - - `erc-ts': a timestamp, possibly provided by the server; as of + - `erc--ts': a timestamp, possibly provided by the server; as of 5.6, a ticks/hertz pair on Emacs 29 and above, and a \"list\" type otherwise; managed by the `stamp' module =20 - - `erc-ephemeral': a symbol prefixed by or matching a module + - `erc--ephemeral': a symbol prefixed by or matching a module name; indicates to other modules and members of modification hooks that the current message should not affect stateful operations, such as recording a channel's most recent speaker @@ -3004,7 +3004,7 @@ erc-send-action ;; Sending and displaying are provided separately to afford modules ;; more flexibility, e.g., to forgo displaying on the way out when ;; expecting the server to echo messages back and/or to associate -;; outgoing messages with IDs generated for `erc-ephemeral' +;; outgoing messages with IDs generated for `erc--ephemeral' ;; placeholders. (defun erc--send-action-perform-ctcp (target string force) "Send STRING to TARGET, possibly immediately, with FORCE." @@ -3013,8 +3013,8 @@ erc--send-action-perform-ctcp (defun erc--send-action-display (string) "Display STRING as an outgoing \"CTCP ACTION\" message." ;; Allow hooks acting on inserted PRIVMSG and NOTICES to process us. - (let ((erc--msg-prop-overrides `((erc-msg . msg) - (erc-ctcp . ACTION) + (let ((erc--msg-prop-overrides `((erc--msg . msg) + (erc--ctcp . ACTION) ,@erc--msg-prop-overrides)) (nick (erc-current-nick))) (setq nick (propertize nick 'erc-speaker nick @@ -3142,20 +3142,20 @@ erc--get-inserted-msg-bounds POINT, search from POINT instead of `point'." ;; TODO add edebug spec. `(let* ((point ,(or point '(point))) - (at-start-p (get-text-property point 'erc-msg))) + (at-start-p (get-text-property point 'erc--msg))) (and-let* (,@(and (member only '(nil beg 'beg)) '((b (or (and at-start-p point) (and-let* ((p (previous-single-property-change point - 'erc-ms= g))) + 'erc--m= sg))) (if (=3D p (1- point)) - (if (get-text-property p 'erc-msg) p (1- p= )) + (if (get-text-property p 'erc--msg) p (1- = p)) (1- p))))))) ,@(and (member only '(nil end 'end)) '((e (1- (next-single-property-change (if at-start-p (1+ point) point) - 'erc-msg nil erc-insert-marker)))))) + 'erc--msg nil erc-insert-marker)))))) ,(pcase only ('(quote beg) 'b) ('(quote end) 'e) @@ -3184,12 +3184,12 @@ erc--traverse-inserted (set-marker end (min erc-insert-marker end))) (save-excursion (goto-char beg) - (let ((b (if (get-text-property (point) 'erc-msg) + (let ((b (if (get-text-property (point) 'erc--msg) (point) - (next-single-property-change (point) 'erc-msg nil end)))) + (next-single-property-change (point) 'erc--msg nil end)))) (while-let ((b) ((< b end)) - (e (next-single-property-change (1+ b) 'erc-msg nil end)= )) + (e (next-single-property-change (1+ b) 'erc--msg nil end= ))) (save-restriction (narrow-to-region b e) (funcall fn)) @@ -3267,7 +3267,7 @@ erc-insert-line (let ((props (if erc--msg-props (erc--order-text-properties-from-hash erc--msg-props) - '(erc-msg unknown)))) + '(erc--msg unknown)))) (add-text-properties (point-min) (1+ (point-min)) prop= s))) (erc--refresh-prompt))))) (run-hooks 'erc-insert-done-hook) @@ -3340,8 +3340,8 @@ erc-display-line being equivalent to a `erc-display-message' TYPE of `notice'." (let ((erc--msg-prop-overrides erc--msg-prop-overrides)) (when (eq 'erc-notice-face (get-text-property 0 'font-lock-face string= )) - (unless (assq 'erc-msg erc--msg-prop-overrides) - (push '(erc-msg . notice) erc--msg-prop-overrides))) + (unless (assq 'erc--msg erc--msg-prop-overrides) + (push '(erc--msg . notice) erc--msg-prop-overrides))) (erc-display-message nil nil buffer string))) =20 (defvar erc--merge-text-properties-p nil @@ -3458,7 +3458,7 @@ erc--delete-inserted-message (substring (delete-and-extract-region (1- (point)) (1+ end)) -1)))))))) =20 -(defvar erc--ranked-properties '(erc-msg erc-ts erc-cmd)) +(defvar erc--ranked-properties '(erc--msg erc--ts erc--cmd)) =20 (defun erc--order-text-properties-from-hash (table) "Return a plist of text props from items in TABLE. @@ -3732,7 +3732,7 @@ erc-display-message (let ((table (make-hash-table :size 5)) (cmd (and parsed (erc--get-eq-comparable-cmd (erc-response.command parsed))))) - (puthash 'erc-msg + (puthash 'erc--msg (cond ((and msg (symbolp msg)) msg) ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) (type (pcase type @@ -3744,7 +3744,7 @@ erc-display-message (t 'unknown)) table) (when cmd - (puthash 'erc-cmd cmd table)) + (puthash 'erc--cmd cmd table)) (and-let* ((ovs erc--msg-prop-overrides)) (pcase-dolist (`(,k . ,v) (reverse ovs)) (puthash k v table))) @@ -5744,7 +5744,7 @@ erc-is-message-ctcp-and-not-action-p (defun erc--get-speaker-bounds () "Return the bounds of `erc-speaker' text property when present. Assume buffer is narrowed to the confines of an inserted message." - (and-let* (((erc--check-msg-prop 'erc-msg 'msg)) + (and-let* (((erc--check-msg-prop 'erc--msg 'msg)) (beg (text-property-not-all (point-min) (point-max) 'erc-speaker nil))) (cons beg (next-single-property-change beg 'erc-speaker)))) @@ -6074,8 +6074,8 @@ 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--msg . msg) + (erc--ctcp . ,(intern type)) ,@erc--msg-prop-overrides))) (if (and hook (boundp hook)) (if (string-equal type "ACTION") @@ -7521,7 +7521,7 @@ erc-display-msg (let ((insert-position (marker-position (goto-char erc-insert-marker= ))) (erc--msg-props (or erc--msg-props (let ((ovs erc--msg-prop-overrides)) - (map-into `((erc-msg . msg) ,@(reverse o= vs)) + (map-into `((erc--msg . msg) ,@(reverse = ovs)) 'hash-table)))) beg) (insert (erc-format-my-nick)) diff --git a/test/lisp/erc/erc-scenarios-display-message.el b/test/lisp/erc= /erc-scenarios-display-message.el index c7e0c2fc17a..91b82889f3e 100644 --- a/test/lisp/erc/erc-scenarios-display-message.el +++ b/test/lisp/erc/erc-scenarios-display-message.el @@ -50,12 +50,12 @@ erc-scenarios-display-message--multibuf (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "dummy")) (funcall expect 10 "<dummy> hi") (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") - (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)= )))) + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc--msg= ))))) =20 (ert-info ("Dummy's QUIT notice in #chan contains metadata props") (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") - (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)= )))) + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc--msg= ))))) =20 (with-current-buffer "foonet" (erc-cmd-QUIT "")))) diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scena= rios-match.el index 17f7649566e..0eed1853879 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -304,9 +304,9 @@ erc-scenarios-match--hide-fools/stamp-both/fill-wrap (should (=3D mend (field-end right-stamp))) (should (eq (field-at-pos (1- mend)) 'erc-timestamp)))) =20 - ;; The `erc-ts' property is present in prop stack. - (should (get-text-property (pos-bol) 'erc-ts)) - (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts= )) + ;; The `erc--ts' property is present in prop stack. + (should (get-text-property (pos-bol) 'erc--ts)) + (should-not (next-single-property-change (1+ (pos-bol)) 'erc--t= s)) =20 ;; Line ending has the `invisible' property `match-fools'. (should (eq (get-text-property mbeg 'invisible) 'match-fools)) @@ -413,7 +413,7 @@ erc-scenarios-match--hide-fools/stamp-both/fill-wrap/sp= eak (should-not (equal "" (get-text-property (pos-bol) 'display))) =20 ;; No remaining meta-data positions, no more timestamps. - (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts)) + (should-not (next-single-property-change (1+ (pos-bol)) 'erc--ts)) ;; No remaining invisible messages. (should-not (text-property-not-all (pos-bol) erc-insert-marker 'invisible nil)) @@ -456,10 +456,10 @@ erc-scenarios-match--stamp-both-invisible-fill-static (should (eq (field-at-pos (field-end mbeg)) 'erc-timestamp)) (should (eq (field-at-pos (1- mend)) 'erc-timestamp))) =20 - ;; The `erc-ts' property is present in the message's + ;; The `erc--ts' property is present in the message's ;; width 1 prop collection at its first char. - (should (get-text-property (pos-bol) 'erc-ts)) - (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts= )) + (should (get-text-property (pos-bol) 'erc--ts)) + (should-not (next-single-property-change (1+ (pos-bol)) 'erc--t= s)) =20 ;; Line ending has the `invisible' property `match-fools'. (should (=3D (char-after mend) ?\n)) diff --git a/test/lisp/erc/erc-scenarios-stamp.el b/test/lisp/erc/erc-scena= rios-stamp.el index 49307dd228a..68769e203ff 100644 --- a/test/lisp/erc/erc-scenarios-stamp.el +++ b/test/lisp/erc/erc-scenarios-stamp.el @@ -29,7 +29,7 @@ (defvar erc-scenarios-stamp--user-marker nil) =20 (defun erc-scenarios-stamp--on-post-modify () - (when-let (((erc--check-msg-prop 'erc-cmd 4))) + (when-let (((erc--check-msg-prop 'erc--cmd 4))) (set-marker erc-scenarios-stamp--user-marker (point-max)) (ert-info ("User marker correctly placed at `erc-insert-marker'") (should (=3D ?\n (char-before erc-scenarios-stamp--user-marker))) @@ -68,8 +68,8 @@ 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 (=3D (pos-bol) (field-beginning (pos-bol)))) - (should (eq 'msg (get-text-property (pos-bol) 'erc-msg))) - (should (eq 'NOTICE (get-text-property (pos-bol) 'erc-cmd))) + (should (eq 'msg (get-text-property (pos-bol) 'erc--msg))) + (should (eq 'NOTICE (get-text-property (pos-bol) 'erc--cmd))) (should (=3D ?- (char-after (field-end (pos-bol))))) (should (equal (get-text-property (1+ (field-end (pos-bol))) 'erc-speaker) @@ -104,14 +104,14 @@ erc-scenarios-stamp--legacy-date-stamps (funcall expect 5 "Opening connection") (goto-char (1- (match-beginning 0))) (should (eq 'erc-timestamp (field-at-pos (point)))) - (should (eq 'unknown (erc--get-inserted-msg-prop 'erc-msg))) + (should (eq 'unknown (erc--get-inserted-msg-prop 'erc--msg))) ;; Force redraw of date stamp. (setq erc-timestamp-last-inserted-left nil) =20 (funcall expect 5 "This server is in debug mode") (while (and (zerop (forward-line -1)) (not (eq 'erc-timestamp (field-at-pos (point)))))) - (should (erc--get-inserted-msg-prop 'erc-cmd))))))) + (should (erc--get-inserted-msg-prop 'erc--cmd))))))) =20 ;; This user-owned hook member places a marker on the first message in ;; a buffer. Inserting a date stamp in front of it shouldn't move the @@ -125,18 +125,18 @@ erc-scenarios-stamp--on-insert-modify =20 ;; Sometime after the first message ("Opening connection.."), assert ;; that the marker we just placed hasn't moved. - (when (erc--check-msg-prop 'erc-cmd 2) + (when (erc--check-msg-prop 'erc--cmd 2) (save-restriction (widen) (ert-info ("Date stamp preserves opening user marker") (goto-char erc-scenarios-stamp--user-marker) (should-not (eq 'erc-timestamp (field-at-pos (point)))) (should (looking-at "Opening")) - (should (eq 'unknown (get-text-property (point) 'erc-msg)))))) + (should (eq 'unknown (get-text-property (point) 'erc--msg)))))) =20 ;; On 003 ("*** This server was created on"), clear state to force a ;; new date stamp on the next message. - (when (erc--check-msg-prop 'erc-cmd 3) + (when (erc--check-msg-prop 'erc--cmd 3) (setq erc-timestamp-last-inserted-left nil) (set-marker erc-scenarios-stamp--user-marker erc-insert-marker))) =20 @@ -174,7 +174,7 @@ erc-scenarios-stamp--date-mode/left-and-right (goto-char erc-scenarios-stamp--user-marker) (should-not (eq 'erc-timestamp (field-at-pos (point)))) (should (looking-at (rx "*** irc.foonet.org oragono"))) - (should (eq 's004 (get-text-property (point) 'erc-msg)))) + (should (eq 's004 (get-text-property (point) 'erc--msg)))) =20 (funcall expect 5 "This server is in debug mode"))))) =20 diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tes= ts.el index cc61d599387..fd2e7000c0e 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -279,7 +279,7 @@ erc-echo-timestamp =20 (should-not erc-echo-timestamps) (should-not erc-stamp--last-stamp) - (insert (propertize "a" 'erc-ts 433483200 'erc-msg 'msg) "bc") + (insert (propertize "a" 'erc--ts 433483200 'erc--msg 'msg) "bc") (goto-char (point-min)) (let ((inhibit-message t) (erc-echo-timestamp-format "%Y-%m-%d %H:%M:%S %Z") diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 49d500fadea..b8ebc23e686 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1738,7 +1738,7 @@ erc--get-inserted-msg-bounds :command "PRIVMSG" :command-args (list "#chan" "hi") :contents "hi")) - (erc--msg-prop-overrides '((erc-ts . 0)))) + (erc--msg-prop-overrides '((erc--ts . 0)))) (erc-display-message parsed nil (current-buffer) (erc-format-privmessage "bob" "hi" nil t))) (goto-char 3) @@ -1785,7 +1785,7 @@ erc--delete-inserted-message ;; Put unique invisible properties on the line endings. (erc-display-message nil 'notice nil "one") (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible '= a) - (let ((erc--msg-prop-overrides '((erc-msg . datestamp) (erc-ts . 0)))) + (let ((erc--msg-prop-overrides '((erc--msg . datestamp) (erc--ts . 0)))) (erc-display-message nil nil nil (propertize "\n[date]" 'field 'erc-timestamp))) (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible '= b) @@ -1794,7 +1794,7 @@ erc--delete-inserted-message (ert-info ("Date stamp deleted cleanly") (goto-char 11) (should (looking-at (rx "\n[date]"))) - (should (eq 'datestamp (get-text-property (point) 'erc-msg))) + (should (eq 'datestamp (get-text-property (point) 'erc--msg))) (should (eq (point) (field-beginning (1+ (point))))) =20 (erc--delete-inserted-message (point)) @@ -1855,19 +1855,19 @@ erc--delete-inserted-message =20 (ert-deftest erc--order-text-properties-from-hash () (let ((table (map-into '((a . 1) - (erc-ts . 0) - (erc-msg . s005) + (erc--ts . 0) + (erc--msg . s005) (b . 2) - (erc-cmd . 5) + (erc--cmd . 5) (c . 3)) 'hash-table))) (with-temp-buffer (erc-mode) (insert "abc\n") (add-text-properties 1 2 (erc--order-text-properties-from-hash table= )) - (should (equal '( erc-msg s005 - erc-ts 0 - erc-cmd 5 + (should (equal '( erc--msg s005 + erc--ts 0 + erc--cmd 5 a 1 b 2 c 3) @@ -2392,7 +2392,7 @@ erc--route-insertion =20 (ert-info ("Cons `buffer' routes to live members") ;; Copies a let-bound `erc--msg-props' before mutating. - (let* ((table (map-into '(erc-msg msg) 'hash-table)) + (let* ((table (map-into '(erc--msg msg) 'hash-table)) (erc--msg-props table)) (erc--route-insertion "cons" (list server-buffer spam-buffer)) (should-not (eq table erc--msg-props))) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-01-start.eld index c07eee3517f..f4a43a9384f 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 3= 53 (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-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc--msg datestamp er= c--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(sp= ace :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg noti= ce erc--ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22= 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-pr= efix #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 = 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG= wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-= prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 2= 02 (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--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 27 (6= )))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# lin= e-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefi= x #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 (s= pace :width (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd= PRIVMSG wrap-prefix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 45= 9 (wrap-prefix #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5= #) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #5# display (#6= # #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--ts 16= 80332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (-= 27 (8)))) 475 480 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #= 1# line-prefix #7#) 487 488 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVM= SG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9=3D""= ) 488 493 (wrap-prefix #1# line-prefix #8# display #9#) 493 495 (wrap-prefi= x #1# line-prefix #8# display #9#) 495 499 (wrap-prefix #1# line-prefix #8#= ) 500 501 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1#= line-prefix #10=3D(space :width (- 27 (6)))) 501 504 (wrap-prefix #1# line= -prefix #10#) 504 512 (wrap-prefix #1# line-prefix #10#) 513 514 (erc--msg = msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(= space :width (- 27 0)) display #9#) 514 517 (wrap-prefix #1# line-prefix #1= 1# display #9#) 517 519 (wrap-prefix #1# line-prefix #11# display #9#) 519 = 524 (wrap-prefix #1# line-prefix #11#) 525 526 (erc--msg msg erc--ts 168033= 2400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=3D(space :width (- 27= (8)))) 526 531 (wrap-prefix #1# line-prefix #12#) 531 538 (wrap-prefix #1#= line-prefix #12#) 539 540 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMS= G wrap-prefix #1# line-prefix #13=3D(space :width (- 27 0)) display #9#) 54= 0 545 (wrap-prefix #1# line-prefix #13# display #9#) 545 547 (wrap-prefix #= 1# line-prefix #13# display #9#) 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-02-right.eld index cf5cdb4f825..78450ec08e2 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (6)))) 350 3= 53 (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-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc--msg datestamp er= c--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(sp= ace :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc--msg noti= ce erc--ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22= 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-pr= efix #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 = 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG= wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-= prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 2= 02 (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--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (6= )))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# lin= e-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefi= x #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 (s= pace :width (- 29 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd= PRIVMSG wrap-prefix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 45= 9 (wrap-prefix #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5= #) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #5# display (#6= # #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--ts 16= 80332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (-= 29 (8)))) 475 480 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #= 1# line-prefix #7#) 487 488 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVM= SG wrap-prefix #1# line-prefix #8=3D(space :width (- 29 0)) display #9=3D""= ) 488 493 (wrap-prefix #1# line-prefix #8# display #9#) 493 495 (wrap-prefi= x #1# line-prefix #8# display #9#) 495 499 (wrap-prefix #1# line-prefix #8#= ) 500 501 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1#= line-prefix #10=3D(space :width (- 29 (6)))) 501 504 (wrap-prefix #1# line= -prefix #10#) 504 512 (wrap-prefix #1# line-prefix #10#) 513 514 (erc--msg = msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(= space :width (- 29 0)) display #9#) 514 517 (wrap-prefix #1# line-prefix #1= 1# display #9#) 517 519 (wrap-prefix #1# line-prefix #11# display #9#) 519 = 524 (wrap-prefix #1# line-prefix #11#) 525 526 (erc--msg msg erc--ts 168033= 2400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=3D(space :width (- 29= (8)))) 526 531 (wrap-prefix #1# line-prefix #12#) 531 538 (wrap-prefix #1#= line-prefix #12#) 539 540 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMS= G wrap-prefix #1# line-prefix #13=3D(space :width (- 29 0)) display #9#) 54= 0 545 (wrap-prefix #1# line-prefix #13# display #9#) 545 547 (wrap-prefix #= 1# line-prefix #13# display #9#) 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index ad4e6483f01..8e5535093e1 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field = erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 27)= line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wra= p-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefi= x #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-pr= efix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible tim= estamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-pre= fix #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-p= refix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wr= ap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 353 (wrap-pre= fix #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-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-pre= fix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-times= tamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisibl= e timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap= -prefix #1# line-prefix #7=3D(space :width (- 27 0)) display #8=3D"") 475 4= 78 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# l= ine-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 4= 85 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-pref= ix #1# line-prefix #9=3D(space :width (- 27 (6)))) 485 486 (wrap-prefix #1#= line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-p= refix #1# line-prefix #9#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd P= RIVMSG wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (6)))) 496 499= (wrap-prefix #1# line-prefix #10#) 499 505 (wrap-prefix #1# line-prefix #1= 0#) 506 507 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# = line-prefix #11=3D(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-cmd PRIVMSG erc-ctcp ACTION wrap-prefix #1# line-= prefix #12=3D(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefi= x #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-cmd PRIVMSG w= rap-prefix #1# line-prefix #13=3D(space :width (- 27 (6)))) 529 532 (wrap-p= refix #1# line-prefix #13#) 532 539 (wrap-prefix #1# line-prefix #13#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix= #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# l= ine-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-pre= fix #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--cmd = PRIVMSG wrap-prefix #1# line-prefix #4=3D(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-p= refix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wra= p-prefix #1# line-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-pref= ix #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= --cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 0)) disp= lay #8=3D"") 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--cmd PRIVMSG erc-= -ctcp ACTION wrap-prefix #1# line-prefix #9=3D(space :width (- 27 (6)))) 48= 5 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefi= x #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc-= -ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(space :w= idth (- 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--= cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) displ= ay #8#) 507 510 (wrap-prefix #1# line-prefix #11# display #8#) 510 512 (wra= p-prefix #1# line-prefix #11# display #8#) 512 515 (wrap-prefix #1# line-pr= efix #11#) 516 517 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG erc--c= tcp ACTION wrap-prefix #1# line-prefix #12=3D(space :width (- 27 (2)))) 517= 518 (wrap-prefix #1# line-prefix #12#) 518 521 (wrap-prefix #1# line-prefi= x #12#) 521 527 (wrap-prefix #1# line-prefix #12#) 528 529 (erc--msg msg er= c--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=3D(space = :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wra= p-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-po= st-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pos= t-01.eld index 893588c028f..a0c03244afe 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.e= ld +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.e= ld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field = erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 27)= line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wra= p-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefi= x #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-pr= efix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible tim= estamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-pre= fix #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-p= refix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wr= ap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 353 (wrap-pre= fix #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-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-pre= fix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-times= tamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisibl= e timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap= -prefix #1# line-prefix #7=3D(space :width (- 27 0)) display #8=3D"") 475 4= 78 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# l= ine-prefix #7# display #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 4= 85 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-pref= ix #1# line-prefix #9=3D(space :width (- 27 (6)))) 485 486 (wrap-prefix #1#= line-prefix #9#) 486 489 (wrap-prefix #1# line-prefix #9#) 489 494 (wrap-p= refix #1# line-prefix #9#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd P= RIVMSG wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (6)))) 496 499= (wrap-prefix #1# line-prefix #10#) 499 505 (wrap-prefix #1# line-prefix #1= 0#) 505 506 (display #("~\n" 0 2 (font-lock-face shadow))) 506 507 (erc-msg= msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(s= pace :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 5= 15 (wrap-prefix #1# line-prefix #11#) 516 517 (erc-msg msg erc-ts 168033240= 0 erc-cmd PRIVMSG erc-ctcp ACTION wrap-prefix #1# line-prefix #12=3D(space = :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #12#) 518 521 (wra= p-prefix #1# line-prefix #12#) 521 527 (wrap-prefix #1# line-prefix #12#) 5= 28 529 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-= prefix #13=3D(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefi= x #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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix= #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# l= ine-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-pre= fix #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--cmd = PRIVMSG wrap-prefix #1# line-prefix #4=3D(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-p= refix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wra= p-prefix #1# line-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-pref= ix #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= --cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 0)) disp= lay #8=3D"") 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--cmd PRIVMSG erc-= -ctcp ACTION wrap-prefix #1# line-prefix #9=3D(space :width (- 27 (6)))) 48= 5 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefi= x #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc-= -ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(space :w= idth (- 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 s= hadow))) 506 507 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-pre= fix #1# line-prefix #11=3D(space :width (- 27 0)) display #8#) 507 510 (wra= p-prefix #1# line-prefix #11# display #8#) 510 512 (wrap-prefix #1# line-pr= efix #11# display #8#) 512 515 (wrap-prefix #1# line-prefix #11#) 516 517 (= erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-pref= ix #1# line-prefix #12=3D(space :width (- 27 (2)))) 517 518 (wrap-prefix #1= # line-prefix #12#) 518 521 (wrap-prefix #1# line-prefix #12#) 521 527 (wra= p-prefix #1# line-prefix #12#) 528 529 (erc--msg msg erc--ts 1680332400 erc= --cmd PRIVMSG wrap-prefix #1# line-prefix #13=3D(space :width (- 27 (6)))) = 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wrap-prefix #1# line-pr= efix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pr= e-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-= 01.eld index 2b67cbbf90e..c4a51e06354 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field = erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 27)= line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wra= p-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefi= x #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-pr= efix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible tim= estamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-pre= fix #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-p= refix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wr= ap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 353 (wrap-pre= fix #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-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-pre= fix #6#) 459 466 (wrap-prefix #1# line-prefix #6#) 466 473 (field erc-times= tamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisibl= e timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap= -prefix #1# line-prefix #7=3D(space :width (- 27 #10=3D(2))) display #8=3D#= ("> " 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 48= 3 (wrap-prefix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 = erc-cmd PRIVMSG erc-ctcp ACTION wrap-prefix #1# line-prefix #9=3D(space :wi= dth (- 27 (6)))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-pr= efix #1# line-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496= (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix= #11=3D(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 16= 80332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #12=3D(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-pr= efix #1# line-prefix #12#) 516 517 (erc-msg msg erc-ts 1680332400 erc-cmd P= RIVMSG erc-ctcp ACTION wrap-prefix #1# line-prefix #13=3D(space :width (- 2= 7 (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-cmd PRIVMSG wrap-prefix #1# line-prefix #14= =3D(space :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #14#) 53= 2 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix= #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# l= ine-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-pre= fix #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--cmd = PRIVMSG wrap-prefix #1# line-prefix #4=3D(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-p= refix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wra= p-prefix #1# line-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-pref= ix #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= --cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 #10=3D(2= ))) display #8=3D#("> " 0 1 (font-lock-face shadow))) 475 478 (wrap-prefix = #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# d= isplay #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg msg= erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-= prefix #9=3D(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# li= ne-prefix #9#) 495 496 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wr= ap-prefix #1# line-prefix #11=3D(space :width (- 27 (6)))) 496 499 (wrap-pr= efix #1# line-prefix #11#) 499 505 (wrap-prefix #1# line-prefix #11#) 506 5= 07 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-p= refix #12=3D(space :width (- 27 #10#)) display #8#) 507 510 (wrap-prefix #1= # line-prefix #12# display #8#) 510 512 (wrap-prefix #1# line-prefix #12# d= isplay #8#) 512 515 (wrap-prefix #1# line-prefix #12#) 516 517 (erc--msg ms= g erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line= -prefix #13=3D(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-pref= ix #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--cmd PRIVM= SG wrap-prefix #1# line-prefix #14=3D(space :width (- 27 (6)))) 529 532 (wr= ap-prefix #1# line-prefix #14#) 532 539 (wrap-prefix #1# line-prefix #14#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index 84a1e34670c..5eea73b4f16 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :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#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index 83394f2f639..bc59c0bef22 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :width (- 29 (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#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index 1605628b29f..bfb75c0838e 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :width (- 25 (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#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index 84a1e34670c..5eea73b4f16 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :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#)) diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/t= est/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 7a7e01de49d..1362c57ef10 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-p= refix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #= 2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((= margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (line= -spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1#= line-prefix #3=3D(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 (wra= p-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg m= sg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(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 (wr= ap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :width= (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displa= y #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap-= prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg not= ice erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) 46= 8 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg notice erc-ts 0 wr= ap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-pre= fix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg er= c-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (- 27= (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #1# = line-prefix #9#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 = 20 (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (spa= ce :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# li= ne-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-pref= ix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# displa= y ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (= line-spacing 0.5) 191 192 (erc--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-pre= fix #1# line-prefix #3=3D(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 3= 48 (wrap-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (er= c--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-prefix #1# line-prefix #4=3D(spa= ce :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (w= rap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 3= 60 435 (wrap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437= (erc--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-prefix #1# line-prefix #5=3D= (space :width (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-pref= ix #5# display #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 4= 42 466 (wrap-prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468= (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #7=3D(space :width = (- 27 (4)))) 468 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc--msg no= tice erc--ts 0 wrap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) = 486 502 (wrap-prefix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 50= 4 (erc--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-prefix #1# line-prefix #9= =3D(space :width (- 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507= 525 (wrap-prefix #1# line-prefix #9#)) diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld index bb248ffb28e..4f87c7d2547 100644 --- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -1 +1 @@ -#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg notice erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0 = 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 2= 7 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix #= 2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font-= lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-pr= efix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timesta= mp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #4= #) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line-= prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix = #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (erc= -msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invisi= ble timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap= -prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #8= # field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefix= #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (wr= ap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 35= 5 430 (wrap-prefix #1# line-prefix #7#)) +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= --msg notice erc--ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" = 0 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-tim= estamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (-= 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix= #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc--msg msg erc--ts= 0 erc--cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp = font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# li= ne-prefix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-ti= mestamp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-pref= ix #4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# = line-prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-pr= efix #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338= (erc--msg msg erc--ts 0 erc--cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7= (invisible timestamp font-lock-face erc-timestamp-face))) field erc-timest= amp wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (di= splay #8# field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wra= p-prefix #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348= 350 (wrap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix= #7#) 355 430 (wrap-prefix #1# line-prefix #7#)) --=20 2.42.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Add-erc-spkr-text-property-to-chat-messages.patch Content-Transfer-Encoding: quoted-printable From 1dd470f193d1a7bb0baa34798317d5eac83a93ce Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 4 Dec 2023 22:13:02 -0800 Subject: [PATCH 04/11] [5.6] Add erc--spkr text property to chat messages * etc/ERC-NEWS: Mention combined face ordering for "/me" messages. * lisp/erc/erc-backend.el: Bind `erc--msg-prop-overrides'. * lisp/erc/erc-fill.el (erc-fill): Switch to `erc--spkr' as sentinel property. (erc-fill--wrap-continued-message-p): Look for `erc--spkr' property instead of `erc-speaker'. * lisp/erc/erc.el (erc--msg-props): Mention `erc--spkr' in doc. (erc--msg-props): Mention `erc--spkr'. (erc--send-action-perform-ctcp): Add `erc--spkr' property and ensure `erc-my-nick-face' appears above `erc-input-face' in the speaker portion. (erc--insure-spkr-prop): New function. (erc--ranked-properties): Add `erc--spkr', `erc--ctcp', and `erc--ephemeral'. (erc-display-message): Use default hash table size when initializing. Remove unnecessary assignment of `msg' to `erc--msg' for PRIVMSG and NOTICE commands. (erc--own-property-names): Add all `erc--msg-props' props. (erc--get-speaker-bounds): Use `erc--spkr' instead of `erc--msg'. (erc-format-privmessage, erc-format-my-nick, erc-ctcp-query-ACTION): Add `erc--spkr' to `erc--msg-prop-overrides' when available. * test/lisp/erc/erc-fill-tests.el: (erc--order-text-properties-from-hash): Include `erc--spkr'. (erc-fill-tests--insert-privmsg): bind `erc--msg-prop-overrides'. (erc-fill-tests--compare): Require environment variable value to match current test name for saving to work. Add `erc--msg-props' individually to white list. (Bug#60936) ; * test/lisp/erc/resources/fill/snapshots/merge-01-start.eld: Update. ; * test/lisp/erc/resources/fill/snapshots/merge-02-right.eld: Update. ; * 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. ; * test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld: Update. ; * test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld: Update. ; * test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld: Update. ; * test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld: Update. ; * test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld: Update. ; * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: Update. --- etc/ERC-NEWS | 5 ++- lisp/erc/erc-backend.el | 3 ++ lisp/erc/erc-fill.el | 20 ++++----- lisp/erc/erc.el | 43 +++++++++++++------ test/lisp/erc/erc-fill-tests.el | 11 +++-- test/lisp/erc/erc-tests.el | 2 + .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../merge-wrap-indicator-post-01.eld | 2 +- .../snapshots/merge-wrap-indicator-pre-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 17 files changed, 66 insertions(+), 40 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 238c40feefb..f6a9d934e80 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -214,7 +214,10 @@ Users of the default theme may notice that 'erc-action= -face' and 'erc-notice-face' now appear slightly less bold on systems supporting a weight of 'semi-bold'. This was done to make buttons detectable and to spare users from resorting to tweaking these faces, or options like -'erc-notice-highlight-type', just to achieve this effect. +'erc-notice-highlight-type', just to achieve this effect. It's +currently most prominent in "/ME" messages, where 'erc-action-face' +sits beneath 'erc-input-face', as well as 'erc-my-nick-face' in the +speaker portion. =20 ** Improved interplay between buffer truncation and message logging. While most of these improvements are subtle, some affect everyday use. diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 500e025e5a1..b1ceeea4f44 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1916,6 +1916,7 @@ erc--server-determine-join-display-context (erc-ignored-reply-p msg tgt proc)) (when erc-minibuffer-ignored (message "Ignored %s from %s to %s" cmd sender-spec tgt)) + (defvar erc--msg-prop-overrides) (let* ((sndr (erc-parse-user sender-spec)) (nick (nth 0 sndr)) (login (nth 1 sndr)) @@ -1926,6 +1927,8 @@ erc--server-determine-join-display-context (privp (erc-current-nick-p tgt)) (erc--display-context `((erc-buffer-display . ,(intern cmd)) ,@erc--display-context)) + (erc--msg-prop-overrides `((erc--msg . msg) + ,@erc--msg-prop-overrides)) s buffer fnick) (setf (erc-response.contents parsed) msg) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 5434d9af966..de6cd581fec 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -177,11 +177,10 @@ erc-fill (when-let ((erc-fill-line-spacing) (p (point-min))) (widen) - (when (or (erc--check-msg-prop 'erc--msg 'msg) - (and-let* ((m (save-excursion - (forward-line -1) - (erc--get-inserted-msg-prop 'erc--ms= g)))) - (eq 'msg m))) + (when (or (erc--check-msg-prop 'erc--spkr) + (save-excursion + (forward-line -1) + (erc--get-inserted-msg-prop 'erc--spkr))) (put-text-property (1- p) p 'line-spacing erc-fill-line-spacing))))))= )) =20 @@ -568,22 +567,19 @@ erc-fill--wrap-continued-message-p (props (save-restriction (widen) (and-let* - (((eq 'msg (get-text-property m 'erc--msg))) + ((speaker (get-text-property m 'erc--spkr)) ((not (eq (get-text-property m 'erc--ctcp) 'ACTION))) - ((not (invisible-p m))) - (spr (next-single-property-change m 'erc-speak= er))) - (cons (get-text-property m 'erc--ts) - (get-text-property spr 'erc-speaker))))) + ((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. - (speaker (next-single-property-change (point-min) 'erc-speak= er)) + (nick (erc--check-msg-prop 'erc--spkr)) ((not (erc--check-msg-prop 'erc--ctcp 'ACTION))) - (nick (get-text-property speaker 'erc-speaker)) ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))))) =20 diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index c68c74467b8..7397add1e98 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -167,6 +167,8 @@ erc--msg-props and help text, and on outgoing messages unless echoed back by the server (assuming future support) =20 + - `erc--spkr': a string, the nick of the person speaking + - `erc--ctcp': a CTCP command, like `ACTION' =20 - `erc--ts': a timestamp, possibly provided by the server; as of @@ -3013,13 +3015,16 @@ erc--send-action-perform-ctcp (defun erc--send-action-display (string) "Display STRING as an outgoing \"CTCP ACTION\" message." ;; Allow hooks acting on inserted PRIVMSG and NOTICES to process us. - (let ((erc--msg-prop-overrides `((erc--msg . msg) - (erc--ctcp . ACTION) - ,@erc--msg-prop-overrides)) - (nick (erc-current-nick))) + (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 action input) (current-buffer) + (erc-display-message nil '(t input action) (current-buffer) 'ACTION ?n nick ?a string ?u "" ?h ""))) =20 (defun erc--send-action (target string force) @@ -3029,6 +3034,12 @@ erc--send-action =20 ;; Display interface =20 +(defun erc--ensure-spkr-prop (nick) + "Maybe add NICK to `erc--msg-props' or `erc--msg-prop-overrides'." + (cond (erc--msg-props (puthash 'erc--spkr nick erc--msg-props)) + (erc--msg-prop-overrides + (push (cons 'erc--spkr nick) erc--msg-prop-overrides)))) + (defun erc-string-invisible-p (string) "Check whether STRING is invisible or not. I.e. any char in it has the `invisible' property set." @@ -3458,7 +3469,8 @@ erc--delete-inserted-message (substring (delete-and-extract-region (1- (point)) (1+ end)) -1)))))))) =20 -(defvar erc--ranked-properties '(erc--msg erc--ts erc--cmd)) +(defvar erc--ranked-properties + '(erc--msg erc--spkr erc--ts erc--cmd erc--ctcp erc--ephemeral)) =20 (defun erc--order-text-properties-from-hash (table) "Return a plist of text props from items in TABLE. @@ -3729,12 +3741,11 @@ erc-display-message msg)) (erc--msg-props (or erc--msg-props - (let ((table (make-hash-table :size 5)) + (let ((table (make-hash-table)) (cmd (and parsed (erc--get-eq-comparable-cmd (erc-response.command parsed))))) (puthash 'erc--msg (cond ((and msg (symbolp msg)) msg) - ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) (type (pcase type ((pred symbolp) type) ((pred listp) @@ -3745,8 +3756,8 @@ erc-display-message table) (when cmd (puthash 'erc--cmd cmd table)) - (and-let* ((ovs erc--msg-prop-overrides)) - (pcase-dolist (`(,k . ,v) (reverse ovs)) + (when erc--msg-prop-overrides + (pcase-dolist (`(,k . ,v) (reverse erc--msg-prop-override= s)) (puthash k v table))) table))) (erc-message-parsed parsed)) @@ -4645,6 +4656,9 @@ erc-send-message (funcall erc--send-message-nested-function line force) (erc--send-message-external line force))) =20 +;; 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 @@ -5258,7 +5272,9 @@ erc-ensure-channel-name (concat "#" channel))) =20 (defvar erc--own-property-names - '( tags erc-speaker erc-parsed display ; core + `( tags erc-speaker erc-parsed display ; core + ;; `erc--msg-props' + ,@erc--ranked-properties ;; `erc-display-prompt' rear-nonsticky erc-prompt field front-sticky read-only ;; stamp @@ -5744,7 +5760,7 @@ erc-is-message-ctcp-and-not-action-p (defun erc--get-speaker-bounds () "Return the bounds of `erc-speaker' text property when present. Assume buffer is narrowed to the confines of an inserted message." - (and-let* (((erc--check-msg-prop 'erc--msg 'msg)) + (and-let* (((erc--check-msg-prop 'erc--spkr)) (beg (text-property-not-all (point-min) (point-max) 'erc-speaker nil))) (cons beg (next-single-property-change beg 'erc-speaker)))) @@ -5772,6 +5788,7 @@ erc-format-privmessage nick-prefix-face nick)) 0)) (msg-face (if privp 'erc-direct-msg-face 'erc-default-face))) + (erc--ensure-spkr-prop nick) ;; add text properties to text before the nick, the nick and after the= nick (erc-put-text-property 0 (length mark-s) 'font-lock-face msg-face str) (erc-put-text-properties (+ (length mark-s) prefix-len) @@ -5827,6 +5844,7 @@ erc-format-my-nick (close "> ") (nick (erc-current-nick)) (mode (erc-get-user-mode-prefix nick))) + (erc--ensure-spkr-prop nick) (concat (propertize open 'font-lock-face 'erc-default-face) (propertize mode 'font-lock-face 'erc-my-nick-prefix-face) @@ -6111,6 +6129,7 @@ erc-ctcp-query-ACTION (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 diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index bfdf8cd7320..8560d421cc2 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -35,7 +35,8 @@ erc-stamp--current-time =20 (defun erc-fill-tests--insert-privmsg (speaker &rest msg-parts) (declare (indent 1)) - (let* ((msg (erc-format-privmessage speaker + (let* ((erc--msg-prop-overrides `((erc--msg . msg))) + (msg (erc-format-privmessage speaker (apply #'concat msg-parts) nil t)) (parsed (make-erc-response :unparsed (format ":%s PRIVMSG #chan := %s" speaker msg) @@ -150,7 +151,9 @@ erc-fill-tests--compare "eld")) (erc--own-property-names (seq-difference `(font-lock-face ,@erc--own-property-names) - '(field display wrap-prefix line-prefix) + `(field display wrap-prefix line-prefix + erc--msg erc--cmd erc--spkr erc--ts erc-= -ctcp + erc--ephemeral) #'eq)) (print-circle t) (print-escape-newlines t) @@ -165,12 +168,12 @@ erc-fill-tests--compare (with-silent-modifications (insert (setq got (read repr)))) (erc-mode)) - (if erc-fill-tests--save-p + ;; LHS is a string, RHS is a symbol. + (if (string=3D erc-fill-tests--save-p (ert-test-name (ert-running-test= ))) (let (inhibit-message) (with-temp-file expect-file (insert repr)) ;; Limit writing snapshots to one test at a time. - (setq erc-fill-tests--save-p nil) (message "erc-fill-tests--compare: wrote %S" expect-file)) (if (file-exists-p expect-file) ;; Ensure string-valued properties, like timestamps, aren't diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b8ebc23e686..ed1dcccd59c 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1859,6 +1859,7 @@ erc--order-text-properties-from-hash (erc--msg . s005) (b . 2) (erc--cmd . 5) + (erc--spkr . "X") (c . 3)) 'hash-table))) (with-temp-buffer @@ -1866,6 +1867,7 @@ erc--order-text-properties-from-hash (insert "abc\n") (add-text-properties 1 2 (erc--order-text-properties-from-hash table= )) (should (equal '( erc--msg s005 + erc--spkr "X" erc--ts 0 erc--cmd 5 a 1 diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-01-start.eld index f4a43a9384f..3c32719a052 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc--msg datestamp er= c--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(sp= ace :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg noti= ce erc--ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22= 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-pr= efix #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 = 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG= wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-= prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 2= 02 (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--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 27 (6= )))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# lin= e-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefi= x #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 (s= pace :width (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd= PRIVMSG wrap-prefix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 45= 9 (wrap-prefix #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5= #) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #5# display (#6= # #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--ts 16= 80332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (-= 27 (8)))) 475 480 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #= 1# line-prefix #7#) 487 488 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVM= SG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9=3D""= ) 488 493 (wrap-prefix #1# line-prefix #8# display #9#) 493 495 (wrap-prefi= x #1# line-prefix #8# display #9#) 495 499 (wrap-prefix #1# line-prefix #8#= ) 500 501 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1#= line-prefix #10=3D(space :width (- 27 (6)))) 501 504 (wrap-prefix #1# line= -prefix #10#) 504 512 (wrap-prefix #1# line-prefix #10#) 513 514 (erc--msg = msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(= space :width (- 27 0)) display #9#) 514 517 (wrap-prefix #1# line-prefix #1= 1# display #9#) 517 519 (wrap-prefix #1# line-prefix #11# display #9#) 519 = 524 (wrap-prefix #1# line-prefix #11#) 525 526 (erc--msg msg erc--ts 168033= 2400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=3D(space :width (- 27= (8)))) 526 531 (wrap-prefix #1# line-prefix #12#) 531 538 (wrap-prefix #1#= line-prefix #12#) 539 540 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMS= G wrap-prefix #1# line-prefix #13=3D(space :width (- 27 0)) display #9#) 54= 0 545 (wrap-prefix #1# line-prefix #13# display #9#) 545 547 (wrap-prefix #= 1# line-prefix #13# display #9#) 547 551 (wrap-prefix #1# line-prefix #13#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc--msg datestamp er= c--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(sp= ace :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg noti= ce erc--ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22= 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-pr= efix #1# line-prefix #2# display (#6=3D(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=3D(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 (er= c--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-= prefix #4=3D(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# li= ne-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-timest= amp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc--m= sg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# = line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-p= refix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (field erc-tim= estamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0 7 (invisi= ble timestamp)))) 474 475 (erc--msg msg erc--ts 1680332400 erc--spkr "alice= " erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)= ))) 475 480 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line= -prefix #7#) 487 488 (erc--msg msg erc--ts 1680332400 erc--spkr "alice" erc= --cmd PRIVMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) disp= lay #9=3D"") 488 493 (wrap-prefix #1# line-prefix #8# display #9#) 493 495 = (wrap-prefix #1# line-prefix #8# display #9#) 495 499 (wrap-prefix #1# line= -prefix #8#) 500 501 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--= cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (6)))) 50= 1 504 (wrap-prefix #1# line-prefix #10#) 504 512 (wrap-prefix #1# line-pref= ix #10#) 513 514 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd = PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) display #= 9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wrap-pr= efix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-prefix= #11#) 525 526 (erc--msg msg erc--ts 1680332400 erc--spkr "Dummy" erc--cmd = PRIVMSG wrap-prefix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 53= 1 (wrap-prefix #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #= 12#) 539 540 (erc--msg msg erc--ts 1680332400 erc--spkr "Dummy" erc--cmd PR= IVMSG wrap-prefix #1# line-prefix #13=3D(space :width (- 27 0)) display #9#= ) 540 545 (wrap-prefix #1# line-prefix #13# display #9#) 545 547 (wrap-pref= ix #1# line-prefix #13# display #9#) 547 551 (wrap-prefix #1# line-prefix #= 13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-02-right.eld index 78450ec08e2..e2064b914c4 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc--msg datestamp er= c--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(sp= ace :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc--msg noti= ce erc--ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22= 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-pr= efix #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 = 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG= wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-= prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 2= 02 (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--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (6= )))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# lin= e-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (wrap-prefi= x #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 (s= pace :width (- 29 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd= PRIVMSG wrap-prefix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 45= 9 (wrap-prefix #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5= #) 466 473 (field erc-timestamp wrap-prefix #1# line-prefix #5# display (#6= # #("[07:00]" 0 7 (invisible timestamp)))) 474 475 (erc--msg msg erc--ts 16= 80332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (-= 29 (8)))) 475 480 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #= 1# line-prefix #7#) 487 488 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVM= SG wrap-prefix #1# line-prefix #8=3D(space :width (- 29 0)) display #9=3D""= ) 488 493 (wrap-prefix #1# line-prefix #8# display #9#) 493 495 (wrap-prefi= x #1# line-prefix #8# display #9#) 495 499 (wrap-prefix #1# line-prefix #8#= ) 500 501 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1#= line-prefix #10=3D(space :width (- 29 (6)))) 501 504 (wrap-prefix #1# line= -prefix #10#) 504 512 (wrap-prefix #1# line-prefix #10#) 513 514 (erc--msg = msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(= space :width (- 29 0)) display #9#) 514 517 (wrap-prefix #1# line-prefix #1= 1# display #9#) 517 519 (wrap-prefix #1# line-prefix #11# display #9#) 519 = 524 (wrap-prefix #1# line-prefix #11#) 525 526 (erc--msg msg erc--ts 168033= 2400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=3D(space :width (- 29= (8)))) 526 531 (wrap-prefix #1# line-prefix #12#) 531 538 (wrap-prefix #1#= line-prefix #12#) 539 540 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMS= G wrap-prefix #1# line-prefix #13=3D(space :width (- 29 0)) display #9#) 54= 0 545 (wrap-prefix #1# line-prefix #13# display #9#) 545 547 (wrap-prefix #= 1# line-prefix #13# display #9#) 547 551 (wrap-prefix #1# line-prefix #13#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc--msg datestamp er= c--ts 0 field erc-timestamp) 3 20 (wrap-prefix #1=3D(space :width 29) line-= prefix (space :width (- 29 (18))) field erc-timestamp) 21 22 (wrap-prefix #= 1# line-prefix #2=3D(space :width (- 29 (4))) erc--msg notice erc--ts 0) 22= 183 (wrap-prefix #1# line-prefix #2#) 183 190 (wrap-prefix #1# line-prefix= #2# field erc-timestamp display (#6=3D(margin right-margin) #("[00:00]" 0 = 7 (invisible timestamp)))) 191 192 (wrap-prefix #1# line-prefix #3=3D(space= :width (- 29 (8))) erc--msg msg erc--ts 0 erc--spkr "alice" erc--cmd PRIVM= SG) 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 (space :width (-= 29 (8)))) 349 350 (wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (6= ))) erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG) 350 353 (wrap-= prefix #1# line-prefix #4#) 353 355 (wrap-prefix #1# line-prefix #4#) 355 3= 60 (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 (wrap-prefix #1# line-prefix (space :width (- 29 (18))) field erc-time= stamp) 455 456 (wrap-prefix #1# line-prefix #5=3D(space :width (- 29 (6))) = erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG) 456 459 (= wrap-prefix #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) = 466 473 (wrap-prefix #1# line-prefix #5# field erc-timestamp display (#6# #= ("[07:00]" 0 7 (invisible timestamp)))) 474 475 (wrap-prefix #1# line-prefi= x #7=3D(space :width (- 29 (8))) erc--msg msg erc--ts 1680332400 erc--spkr = "alice" erc--cmd PRIVMSG) 475 480 (wrap-prefix #1# line-prefix #7#) 480 486= (wrap-prefix #1# line-prefix #7#) 487 488 (wrap-prefix #1# line-prefix #8= =3D(space :width (- 29 0)) erc--msg msg erc--ts 1680332400 erc--spkr "alice= " erc--cmd PRIVMSG display #9=3D"") 488 493 (wrap-prefix #1# line-prefix #8= # display #9#) 493 495 (wrap-prefix #1# line-prefix #8# display #9#) 495 49= 9 (wrap-prefix #1# line-prefix #8#) 500 501 (wrap-prefix #1# line-prefix #1= 0=3D(space :width (- 29 (6))) erc--msg msg erc--ts 1680332400 erc--spkr "bo= b" erc--cmd PRIVMSG) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (wr= ap-prefix #1# line-prefix #10#) 513 514 (wrap-prefix #1# line-prefix #11=3D= (space :width (- 29 0)) erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc= --cmd PRIVMSG display #9#) 514 517 (wrap-prefix #1# line-prefix #11# displa= y #9#) 517 519 (wrap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap= -prefix #1# line-prefix #11#) 525 526 (wrap-prefix #1# line-prefix #12=3D(s= pace :width (- 29 (8))) erc--msg msg erc--ts 1680332400 erc--spkr "Dummy" e= rc--cmd PRIVMSG) 526 531 (wrap-prefix #1# line-prefix #12#) 531 538 (wrap-p= refix #1# line-prefix #12#) 539 540 (wrap-prefix #1# line-prefix #13=3D(spa= ce :width (- 29 0)) erc--msg msg erc--ts 1680332400 erc--spkr "Dummy" erc--= cmd PRIVMSG display #9#) 540 545 (wrap-prefix #1# line-prefix #13# display = #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) 547 551 (wrap-p= refix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index 8e5535093e1..9f648915d5c 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix= #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# l= ine-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-pre= fix #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--cmd = PRIVMSG wrap-prefix #1# line-prefix #4=3D(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-p= refix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wra= p-prefix #1# line-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-pref= ix #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= --cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 0)) disp= lay #8=3D"") 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--cmd PRIVMSG erc-= -ctcp ACTION wrap-prefix #1# line-prefix #9=3D(space :width (- 27 (6)))) 48= 5 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefi= x #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc-= -ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(space :w= idth (- 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--= cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) displ= ay #8#) 507 510 (wrap-prefix #1# line-prefix #11# display #8#) 510 512 (wra= p-prefix #1# line-prefix #11# display #8#) 512 515 (wrap-prefix #1# line-pr= efix #11#) 516 517 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG erc--c= tcp ACTION wrap-prefix #1# line-prefix #12=3D(space :width (- 27 (2)))) 517= 518 (wrap-prefix #1# line-prefix #12#) 518 521 (wrap-prefix #1# line-prefi= x #12#) 521 527 (wrap-prefix #1# line-prefix #12#) 528 529 (erc--msg msg er= c--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=3D(space = :width (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wra= p-prefix #1# line-prefix #13#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--spkr "alice" erc--cmd P= RIVMSG wrap-prefix #1# line-prefix #3=3D(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-pr= efix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg e= rc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D= (space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 35= 5 (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 er= c--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-pre= fix #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=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 4= 59 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 timestam= p)))) 474 475 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRI= VMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 0)) display #8=3D= "") 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-pre= fix #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 PRIVM= SG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=3D(space :width (- 27 (6= )))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# lin= e-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg m= sg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line= -prefix #10=3D(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-pref= ix #10#) 499 505 (wrap-prefix #1# line-prefix #10#) 506 507 (erc--msg msg e= rc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-pre= fix #11=3D(space :width (- 27 0)) display #8#) 507 510 (wrap-prefix #1# lin= e-prefix #11# display #8#) 510 512 (wrap-prefix #1# line-prefix #11# displa= y #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-pref= ix #1# line-prefix #12=3D(space :width (- 27 (2)))) 517 518 (wrap-prefix #1= # line-prefix #12#) 518 521 (wrap-prefix #1# line-prefix #12#) 521 527 (wra= p-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=3D(space :wid= th (- 27 (6)))) 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wrap-pr= efix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-po= st-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pos= t-01.eld index a0c03244afe..a63fcad3d38 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.e= ld +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.e= ld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix= #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# l= ine-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-pre= fix #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--cmd = PRIVMSG wrap-prefix #1# line-prefix #4=3D(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-p= refix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wra= p-prefix #1# line-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-pref= ix #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= --cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 0)) disp= lay #8=3D"") 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--cmd PRIVMSG erc-= -ctcp ACTION wrap-prefix #1# line-prefix #9=3D(space :width (- 27 (6)))) 48= 5 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# line-prefi= x #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg msg erc-= -ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(space :w= idth (- 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 s= hadow))) 506 507 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-pre= fix #1# line-prefix #11=3D(space :width (- 27 0)) display #8#) 507 510 (wra= p-prefix #1# line-prefix #11# display #8#) 510 512 (wrap-prefix #1# line-pr= efix #11# display #8#) 512 515 (wrap-prefix #1# line-prefix #11#) 516 517 (= erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-pref= ix #1# line-prefix #12=3D(space :width (- 27 (2)))) 517 518 (wrap-prefix #1= # line-prefix #12#) 518 521 (wrap-prefix #1# line-prefix #12#) 521 527 (wra= p-prefix #1# line-prefix #12#) 528 529 (erc--msg msg erc--ts 1680332400 erc= --cmd PRIVMSG wrap-prefix #1# line-prefix #13=3D(space :width (- 27 (6)))) = 529 532 (wrap-prefix #1# line-prefix #13#) 532 539 (wrap-prefix #1# line-pr= efix #13#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--spkr "alice" erc--cmd P= RIVMSG wrap-prefix #1# line-prefix #3=3D(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-pr= efix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg e= rc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D= (space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 35= 5 (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 er= c--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-pre= fix #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=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 4= 59 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 timestam= p)))) 474 475 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRI= VMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 0)) display #8=3D= "") 475 478 (wrap-prefix #1# line-prefix #7# display #8#) 478 480 (wrap-pre= fix #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 PRIVM= SG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=3D(space :width (- 27 (6= )))) 485 486 (wrap-prefix #1# line-prefix #9#) 486 489 (wrap-prefix #1# lin= e-prefix #9#) 489 494 (wrap-prefix #1# line-prefix #9#) 495 496 (erc--msg m= sg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line= -prefix #10=3D(space :width (- 27 (6)))) 496 499 (wrap-prefix #1# line-pref= ix #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 er= c--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :wi= dth (- 27 0)) display #8#) 507 510 (wrap-prefix #1# line-prefix #11# displa= y #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=3D(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-pr= efix #12#) 528 529 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cm= d PRIVMSG wrap-prefix #1# line-prefix #13=3D(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-pr= e-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-= 01.eld index c4a51e06354..7cbabfd0581 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix= #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix #1# l= ine-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wrap-pre= fix #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--cmd = PRIVMSG wrap-prefix #1# line-prefix #4=3D(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-p= refix #4#) 436 437 (erc--msg datestamp erc--ts 1680307200 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wra= p-prefix #1# line-prefix #6=3D(space :width (- 27 (6)))) 456 459 (wrap-pref= ix #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= --cmd PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 #10=3D(2= ))) display #8=3D#("> " 0 1 (font-lock-face shadow))) 475 478 (wrap-prefix = #1# line-prefix #7# display #8#) 478 480 (wrap-prefix #1# line-prefix #7# d= isplay #8#) 480 483 (wrap-prefix #1# line-prefix #7#) 484 485 (erc--msg msg= erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-= prefix #9=3D(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# li= ne-prefix #9#) 495 496 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wr= ap-prefix #1# line-prefix #11=3D(space :width (- 27 (6)))) 496 499 (wrap-pr= efix #1# line-prefix #11#) 499 505 (wrap-prefix #1# line-prefix #11#) 506 5= 07 (erc--msg msg erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-p= refix #12=3D(space :width (- 27 #10#)) display #8#) 507 510 (wrap-prefix #1= # line-prefix #12# display #8#) 510 512 (wrap-prefix #1# line-prefix #12# d= isplay #8#) 512 515 (wrap-prefix #1# line-prefix #12#) 516 517 (erc--msg ms= g erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line= -prefix #13=3D(space :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-pref= ix #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--cmd PRIVM= SG wrap-prefix #1# line-prefix #14=3D(space :width (- 27 (6)))) 529 532 (wr= ap-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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<bob> 0.5\n* bob one.\n<bob> two.\n<b= ob> 2.5\n* bob three\n<bob> four.\n" 2 3 (erc--msg datestamp erc--ts 0 fiel= d erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(space :width 2= 7) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0= wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-p= refix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix #1# lin= e-prefix #2# display (#5=3D(margin right-margin) #("[00:00]" 0 7 (invisible= timestamp)))) 191 192 (erc--msg msg erc--ts 0 erc--spkr "alice" erc--cmd P= RIVMSG wrap-prefix #1# line-prefix #3=3D(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-pr= efix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc--msg msg e= rc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D= (space :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 35= 5 (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 er= c--ts 1680307200 field erc-timestamp) 437 454 (field erc-timestamp wrap-pre= fix #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=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #6#) 4= 59 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 timestam= p)))) 474 475 (erc--msg msg erc--ts 1680332400 erc--spkr "bob" erc--cmd PRI= VMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 #10=3D(2))) displ= ay #8=3D#("> " 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=3D(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 "b= ob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(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=3D(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=3D(space= :width (- 27 (2)))) 517 518 (wrap-prefix #1# line-prefix #13#) 518 521 (wr= ap-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 w= rap-prefix #1# line-prefix #14=3D(space :width (- 27 (6)))) 529 532 (wrap-p= refix #1# line-prefix #14#) 532 539 (wrap-prefix #1# line-prefix #14#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index 5eea73b4f16..c94629cf357 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :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#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--spkr "alice" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(sp= ace :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-pre= fix #3#) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG w= rap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 353 (wrap-pr= efix #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#= )) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index bc59c0bef22..127c0b29bc9 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :width (- 29 (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#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--spkr "alice" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(sp= ace :width (- 29 (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-pre= fix #3#) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG w= rap-prefix #1# line-prefix #4=3D(space :width (- 29 (6)))) 350 353 (wrap-pr= efix #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#= )) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index bfb75c0838e..a9f3f1d1904 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :width (- 25 (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#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--spkr "alice" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(sp= ace :width (- 25 (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-pre= fix #3#) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG w= rap-prefix #1# line-prefix #4=3D(space :width (- 25 (6)))) 350 353 (wrap-pr= efix #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#= )) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index 5eea73b4f16..c94629cf357 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (= 8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# li= ne-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 202 315 (wrap-pref= ix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #3#) 349 350 (= erc--msg msg erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(s= pace :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#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18= )))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=3D(spa= ce :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-ma= rgin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc--msg msg erc--t= s 0 erc--spkr "alice" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(sp= ace :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-pre= fix #3#) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG w= rap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 353 (wrap-pr= efix #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#= )) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/t= est/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 1362c57ef10..754d7989cea 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 = 20 (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (spa= ce :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# li= ne-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-pref= ix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# displa= y ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (= line-spacing 0.5) 191 192 (erc--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-pre= fix #1# line-prefix #3=3D(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 3= 48 (wrap-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (er= c--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-prefix #1# line-prefix #4=3D(spa= ce :width (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (w= rap-prefix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 3= 60 435 (wrap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437= (erc--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-prefix #1# line-prefix #5=3D= (space :width (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-pref= ix #5# display #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 4= 42 466 (wrap-prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468= (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #7=3D(space :width = (- 27 (4)))) 468 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc--msg no= tice erc--ts 0 wrap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) = 486 502 (wrap-prefix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 50= 4 (erc--msg msg erc--cmd PRIVMSG erc--ts 0 wrap-prefix #1# line-prefix #9= =3D(space :width (- 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507= 525 (wrap-prefix #1# line-prefix #9#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 = 20 (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (spa= ce :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# li= ne-prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-pref= ix #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# displa= y ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (= line-spacing 0.5) 191 192 (erc--msg msg erc--ts 0 erc--spkr "alice" erc--cm= d PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 1= 97 (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#) 348 349 (line-spacin= g 0.5) 349 350 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG wra= p-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 353 (wrap-pref= ix #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#) = 435 436 (line-spacing 0.5) 436 437 (erc--msg msg erc--ts 0 erc--spkr "bob" = erc--cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(space :width (- 27 0)) d= isplay #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# display #6#) 440 4= 42 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap-prefix #1# l= ine-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc--msg notice erc--ts= 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) 468 484 (wra= p-prefix #1# line-prefix #7#) 485 486 (erc--msg notice erc--ts 0 wrap-prefi= x #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-prefix #1# = line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc--msg msg erc--ts 0= erc--spkr "bob" erc--cmd PRIVMSG wrap-prefix #1# line-prefix #9=3D(space := width (- 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-= prefix #1# line-prefix #9#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld index 4f87c7d2547..1b22b6c5cfd 100644 --- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -1 +1 @@ -#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= --msg notice erc--ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" = 0 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-tim= estamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (-= 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix= #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc--msg msg erc--ts= 0 erc--cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp = font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# li= ne-prefix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-ti= mestamp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-pref= ix #4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# = line-prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-pr= efix #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338= (erc--msg msg erc--ts 0 erc--cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7= (invisible timestamp font-lock-face erc-timestamp-face))) field erc-timest= amp wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (di= splay #8# field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wra= p-prefix #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348= 350 (wrap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix= #7#) 355 430 (wrap-prefix #1# line-prefix #7#)) +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= --msg notice erc--ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" = 0 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-tim= estamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (-= 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix= #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc--msg msg erc--ts= 0 erc--spkr "alice" erc--cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (in= visible timestamp font-lock-face erc-timestamp-face))) field erc-timestamp = wrap-prefix #1# line-prefix #4=3D(space :width (- 27 (8)))) 173 179 (displa= y #6# field erc-timestamp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-pr= efix #1# line-prefix #4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187= (wrap-prefix #1# line-prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#= ) 190 303 (wrap-prefix #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-p= refix #4#) 337 338 (erc--msg msg erc--ts 0 erc--spkr "bob" erc--cmd PRIVMSG= display #8=3D(#5# #("[00:00]" 0 7 (invisible timestamp font-lock-face erc-= timestamp-face))) field erc-timestamp wrap-prefix #1# line-prefix #7=3D(spa= ce :width (- 27 (6)))) 338 344 (display #8# field erc-timestamp wrap-prefix= #1# line-prefix #7#) 344 345 (wrap-prefix #1# line-prefix #7#) 345 348 (wr= ap-prefix #1# line-prefix #7#) 348 350 (wrap-prefix #1# line-prefix #7#) 35= 0 355 (wrap-prefix #1# line-prefix #7#) 355 430 (wrap-prefix #1# line-prefi= x #7#)) \ No newline at end of file --=20 2.42.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 13 Nov 2023 21:03:01 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon Nov 13 16:03:01 2023 Received: from localhost ([127.0.0.1]:59435 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1r2e5E-0003Kc-TR for submit <at> debbugs.gnu.org; Mon, 13 Nov 2023 16:03:01 -0500 Received: from mail-108-mta23.mxroute.com ([136.175.108.23]:45783) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1r2e5B-0003KR-Q7 for 60936 <at> debbugs.gnu.org; Mon, 13 Nov 2023 16:02:59 -0500 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta23.mxroute.com (ZoneMTA) with ESMTPSA id 18bca7df449000190b.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Mon, 13 Nov 2023 21:02:14 +0000 X-Zone-Loop: 2c11021e9563118bcd1185322e4399cb516eb4635c86 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=Sae+Wn/QibswXuM+rCYhfPJSAPtHozqxrL1nZU1S/0g=; b=NXS3POy3kWOnN4WX85P7hFn1Y0 qwtGmr2g3N+fbWlUSa5r6+Cu7T36QqRm60WSFlKBYQCzkYVWkhLkjP1hWkf9HJbIPsW/PmqikdwOa PFRSyd8x1yOMDmtOt1gNOKdFD2zgAs6SX3OjQttIvEiYH1iem3hi+ilNblPp9k0Inzn7pWRKsLV0Z 7b8d5iBuUMJxUvOV5V6sJT1lj44hI14mslkHgZmM3vUmakKdtbL7BsfC8S/gzMqcJJQb9aK2zgAzN HnagvQTXoY/LnKfDY8NHhMtcuv4s8G1U13zMfZBl31Cl+Te9/DC44iPdChSlkwGTaZJTz2eHk3ed/ MsSb1o0Q==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Mon, 13 Nov 2023 13:01:47 -0800 Message-ID: <87r0ktxt8k.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain I'm thinking it might make sense to have `fill-wrap' formally depend on `scrolltobottom', even though there's no technical reason to do so. The rare user who prefers otherwise can still get their way via `erc-scrolltobottom-mode-hook'. Alternatively, we could just enable `scrolltobottom' by default in a future release. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Make-erc-fill-wrap-depend-on-scrolltobottom.patch From 66a7f1a34924a7244ac27b25e8d6b36d9c3ceaf2 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 13 Nov 2023 12:07:36 -0800 Subject: [PATCH] [5.6] Make erc-fill-wrap depend on scrolltobottom * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-function): Add reference to `erc-fill-wrap-mode' in doc string. (erc--fill-scrolltobottom-exempt-p): New variable. (erc-fill--wrap-ensure-dependencies): Warn and enable `erc-scrolltobottom-mode' if necessary. (erc-fill-wrap-mode): Mention workaround for users who don't want this module to automatically enable `scrolltobottom'. * test/lisp/erc/erc-fill-tests.el (erc-fill-tests--wrap-populate): Exempt tests from `scrolltobottom' dependency. (Bug#60936) --- lisp/erc/erc-fill.el | 44 +++++++++++++++++++-------------- test/lisp/erc/erc-fill-tests.el | 1 + 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e48d5540c86..457e51e6053 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -44,11 +44,7 @@ erc-fill (define-erc-module fill nil "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in -the channel buffers are filled." - ;; FIXME ensure a consistent ordering relative to hook members from - ;; other modules. Ideally, this module's processing should happen - ;; after "morphological" modifications to a message's text but - ;; before superficial decorations. +the channel buffers are filled. See also `erc-fill-wrap-mode'." ((add-hook 'erc-insert-modify-hook #'erc-fill 60) (add-hook 'erc-send-modify-hook #'erc-fill 60)) ((remove-hook 'erc-insert-modify-hook #'erc-fill) @@ -86,11 +82,12 @@ erc-fill-function A third style resembles static filling but \"wraps\" instead of fills, thanks to `visual-line-mode' mode, which ERC automatically -enables when this option is `erc-fill-wrap' or when the module -`fill-wrap' is active. Use `erc-fill-static-center' to specify -an initial \"prefix\" width and `erc-fill-wrap-margin-width' -instead of `erc-fill-column' for influencing initial message -width. For adjusting these during a session, see the commands +enables when this option is set to `erc-fill-wrap' or when the +module `fill-wrap' is active \(see `erc-fill-wrap-mode' for +details). Use `erc-fill-static-center' to specify an initial +\"prefix\" width and `erc-fill-wrap-margin-width' instead of +`erc-fill-column' for influencing initial message width. For +adjusting these during a session, see the commands `erc-fill-wrap-nudge' and `erc-fill-wrap-refill-buffer'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) @@ -367,8 +364,11 @@ erc-fill-wrap-mode-map "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) (defvar erc-button-mode) +(defvar erc-scrolltobottom-mode) (defvar erc-legacy-invisible-bounds-p) +(defvar erc--fill-scrolltobottom-exempt-p nil) + (defun erc-fill--wrap-ensure-dependencies () (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) (when erc-legacy-invisible-bounds-p @@ -381,6 +381,10 @@ erc-fill--wrap-ensure-dependencies (unless erc-fill-mode (push 'fill missing-deps) (erc-fill-mode +1)) + (unless (or erc-scrolltobottom-mode (memq 'scrolltobottom erc-modules) + erc--fill-scrolltobottom-exempt-p) + (push 'scrolltobottom missing-deps) + (erc-scrolltobottom-mode +1)) (when erc-fill-wrap-merge (require 'erc-button) (unless erc-button-mode @@ -401,20 +405,22 @@ erc-fill--wrap-ensure-dependencies ;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) (define-erc-module fill-wrap nil "Fill style leveraging `visual-line-mode'. + This module displays nicks overhanging leftward to a common offset, as determined by the option `erc-fill-static-center'. And it \"wraps\" messages at a common margin width, as determined by the option `erc-fill-wrap-margin-width'. To use it, either include `fill-wrap' in `erc-modules' or set `erc-fill-function' -to `erc-fill-wrap'. Most users will want to enable the -`scrolltobottom' module as well. Once active, use -\\[erc-fill-wrap-nudge] to adjust the width of the indent and the -stamp margin, and use \\[erc-fill-wrap-toggle-truncate-lines] for -cycling between logical- and screen-line oriented command -movement. Similarly, use \\[erc-fill-wrap-refill-buffer] to fix -alignment problems after running certain commands, like -`text-scale-adjust'. Also see related stylistic options -`erc-fill-line-spacing' and `erc-fill-wrap-merge'. +to `erc-fill-wrap'. Once active, use \\[erc-fill-wrap-nudge] to +adjust the width of the indent and the stamp margin, and use +\\[erc-fill-wrap-toggle-truncate-lines] for cycling between +logical- and screen-line oriented command movement. Similarly, +use \\[erc-fill-wrap-refill-buffer] to fix alignment problems +after running certain commands, like `text-scale-adjust'. Also +see related stylistic options `erc-fill-line-spacing' and +`erc-fill-wrap-merge'. Note that this module currently ensures +`erc-scrolltobottom-mode' is active. Users wishing otherwise can +suppress that behavior by leveraging `erc-fill-wrap-mode-hook'. This module imposes various restrictions on the appearance of timestamps. Most notably, it insists on displaying them in the diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index c21f3935503..d54204eb0ce 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -47,6 +47,7 @@ erc-fill-tests--insert-privmsg (defun erc-fill-tests--wrap-populate (test) (let ((original-window-buffer (window-buffer (selected-window))) + (erc--fill-scrolltobottom-exempt-p t) (erc-stamp--tz t) (erc-fill-function 'erc-fill-wrap) (pre-command-hook pre-command-hook) -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 6 Nov 2023 02:31:23 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Sun Nov 05 21:31:23 2023 Received: from localhost ([127.0.0.1]:38476 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qzpOd-0006Hd-EP for submit <at> debbugs.gnu.org; Sun, 05 Nov 2023 21:31:23 -0500 Received: from mail-108-mta112.mxroute.com ([136.175.108.112]:35083) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qzpOb-0006HR-9M for 60936 <at> debbugs.gnu.org; Sun, 05 Nov 2023 21:31:22 -0500 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta112.mxroute.com (ZoneMTA) with ESMTPSA id 18ba277c618000190b.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Mon, 06 Nov 2023 02:30:40 +0000 X-Zone-Loop: e7b6af6672961868669b79f69158de9ff787c07d91f0 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=Tu/Mr9cggRdA21ERMJn3WcwvydJY2vL5H7hISp2pTNI=; b=XEgB01UA1l8LaBw3GHYKJ8DJAT 34HppMKjznMyhBj9ij6SsOMca5kTFh4EYbdHI8KXItcQgwM/vh2drpweUsy3pzZVPlfNx7lv5FRX5 vB10cOse5XkvjZzsIIKwh6fm2R6S/a2sSWuelO/kGubmjWf2npLdoTp1KjorFdUuYqj8hGmBSGC8C XNZ7Za3SaXL8AOsoDXZvtMiwP3Bv6NItRmhJFH2V+gKz3hLkw199+uxbEADArvcy/pXPPDsEUPlJQ URxi1QihW8i+FhwGraXeEQC1ZpfzdapqzqP3ZpvczXpn893bQ6hJ9dl5qLPPcx3Qe8vgEXje4YwXr 54K8+qGA==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <874ji6tiyn.fsf@HIDDEN> (J. P.'s message of "Tue, 31 Oct 2023 17:28:48 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> <877cniaewr.fsf@HIDDEN> <877cncg3ss.fsf@HIDDEN> <87jzrcccw3.fsf@HIDDEN> <87lebra1io.fsf@HIDDEN> <87bkcguspb.fsf@HIDDEN> <874ji6tiyn.fsf@HIDDEN> Date: Sun, 05 Nov 2023 18:30:14 -0800 Message-ID: <87a5rrlikp.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > Recent work on this feature introduced an annoying regression. > >>From emacs -Q: > > 1. M-: (erc-tls :server "testnet.inspircd.org") RET > 2. /JOIN #test and say something > 3. M-: (setq erc-timestamp-last-inserted-left nil) RET to reset the > date stamp's deduping snapshot > 4. Say something else > 5. Notice that point has been dislodged from the prompt and that a new > date stamp has not been inserted > > The second of the attached patches should fix it. This and related fixes involving date stamps were recently installed. See: * f99a0dae7ca Align date stamps to whole days in ERC * 4c851085769 Decouple disparate escape-hatch concerns in erc-stamp * 781f950edab Preserve user markers when inserting ERC date stamps * f7c7f7ac20d Don't over-truncate erc-timestamp-format-left The second one might be of interest to users with a legitimate need to call `erc-insert-line' (formerly `erc-display-line') directly, as opposed to via `erc-display-message'. It's now possible to do so without sacrificing timestamps and without also incurring the likely unwanted `cursor-sensor-functions' property. (The latter now has its own separate compatibility flag.)
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936-quiet) by debbugs.gnu.org; 6 Nov 2023 01:47:06 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Sun Nov 05 20:47:06 2023 Received: from localhost ([127.0.0.1]:38455 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qzohm-00056t-Gz for submit <at> debbugs.gnu.org; Sun, 05 Nov 2023 20:47:06 -0500 Received: from mail-108-mta253.mxroute.com ([136.175.108.253]:41467) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qzohk-00056k-Um for 60936-quiet <at> debbugs.gnu.org; Sun, 05 Nov 2023 20:47:05 -0500 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta253.mxroute.com (ZoneMTA) with ESMTPSA id 18ba24f4500000190b.001 for <60936-quiet <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Mon, 06 Nov 2023 01:46:25 +0000 X-Zone-Loop: d864aa237007e676b09dd0b0e0f8f6de376978845580 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:To:From:Sender:Reply-To:Cc: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=YwUJqcJokeCQo3zgr/hxJW3EU1TOGEUBGMYW5fW9oXw=; b=jr2mvMx82kW+oGIaH+FB0tvNbv /i+svUWc33yXzaW9oIgfVTv1l/mTDI7yOW6TAMDTKmYsvdm+xpemWHWPYQecLhnWwMzWlTkxU8/PK DxWgupyGBbRjDrEm/RZufvs44iiRDwF27gRhGVLjLWNxoBCGAI6zG7GpH4tjFpmkclm7q64mz8s57 3F5ieSkO61sk2WqXyJOx/zZCWaZ1DYFfDa/pQS2qRFsdlmosYxSuEP+wC56/gxkwcblsSDbEU9a4W GriSaQ0ghSWe4KbXpHoEmXVTgRwCX3r6WgRPRV9W4jme9gvGWwqBcIBOu6Q4clXohaTCNo1oyKPed CpDOSvxw==; From: "J.P." <jp@HIDDEN> To: 60936-quiet <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Sun, 05 Nov 2023 17:45:59 -0800 Message-ID: <87a5rrmz6w.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936-quiet X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain Screenshot storage (unrelated to this feature): --=-=-= Content-Type: image/png Content-Disposition: attachment; filename=erc-multi-target-match-hack.png Content-Transfer-Encoding: base64 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 zvwnXmL2y5soLcpiw30PMuujwsYf3HBSPu9V3hj3Ael5ddRsmsfHFz3Jsm2Wxg5Uyr/4N2/ct4Ry /FALd7Nm0jP8sr7htpNqKSRnyVYyNhdiqSgkd/1ustbtJnt7EdbGX/RQi9fyyz/ns+mlJ5k5+Uey coop3H6o4botnaV3fcLeCvX4ePPe4ZvPchpviTgonTuN16+Zxd78Cop//IB5s/JacLtExbJ+Nu9d +jIb0i1QvZ/lNz3E3O9KGuavBOKTNZ9P75zHYSuolVv56ZZ3OWgPbDSSoL1ofoAzfyXfjrmPzz/a Q7XFwpFv3+DdRzdgaVAg5TsadJa1ZjmL7nubrTnHZyfWr5OSD5/mf3d9w54DNVhz1zD/ikdYuFGj fQTjC/1D6F8ChPbXi3v9ONN/Yu7Nz/LD7EwyXn+ej255jw3btrHkxumsL2yMEHf2E8aPd+UHQK0n c9pU5s3NpLpwB4vGT2b2vBKN8S3wX6F/uM8PQkT+o3d8YXsBAv/Ukv/co8G+7hDO74/5831mXf0v Zn94sCG+RPEn6t9Rys6nn2fWNU8x76sG/1t8/f3M/rZEW/zrzs86+9erf/TlB1H+EecnUXyL1k/9 +UtXfhSuH6L8IrKvTv/Xu76eQcQAnYBEIBnoAfQBBgCDgWHAxKqqKtXdS4g9X10y5hr1zVczVIuq qqrqVM1fPKU+ee3ParVTVVXzOnVu79vV79daGhs41NL3H1WfHveDWuZQVVW1qnsmj1dfeXq3anEx hKqqqu2H59Unx81XK50nX3PmfKvO6DROfW3KZtX8x+uWFeonXR9TVx8+esGhFrw4UZ02ZadqV1VV Na9VZ/e6TZ23ovbY9cJX71P//fCWhusibJnqwtE3qV8sqFCPjmDb+IH6yshZap7taJel6ra7blff eGmruuuRCeqM1zJUWwvau52fs0rddsd49aUndjTRn0O1W5tRlHWX+v3ge9Vfd548M3f6VeutTXTR oJ+pD20+QT9u27sbX+QfIv8SIbL/sWkVqMsu+z/1y0W2ZjoRXHejH/uKN9V/D/lAzbHa1fz/TFBf fHKXardlqb9dcKv63Wqb2H7C+NGIh/I36P9a9cPZpY3+6VRr57+gPjvqU/WQTZt8bv23Kc36p7b8 4JKW+I/e8d3El0s0+qem+HKFhvgV+r+quohfQf7UGn+u+hf5nwi9+bk1+teif1fozA+i/CPMT6L4 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 --=-=-=--
Received: (at 60936) by debbugs.gnu.org; 1 Nov 2023 00:29:40 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 31 20:29:40 2023 Received: from localhost ([127.0.0.1]:49514 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qxz72-0004A2-GR for submit <at> debbugs.gnu.org; Tue, 31 Oct 2023 20:29:40 -0400 Received: from mail-108-mta17.mxroute.com ([136.175.108.17]:35631) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qxz6w-00049o-GO for 60936 <at> debbugs.gnu.org; Tue, 31 Oct 2023 20:29:34 -0400 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta17.mxroute.com (ZoneMTA) with ESMTPSA id 18b88487a30000190b.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 01 Nov 2023 00:28:53 +0000 X-Zone-Loop: a918333593106611627cddb729d25f64aabb3eb6ea21 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=Ut0zx+YJcrFjxysUQXUuKZxcjQqUqnBqB6LbQ2Ih4eQ=; b=m/X2V9V3gd+kD5+5nJOfyW55O0 q/YxvRBxpyll+8PEO+R53UcF1dzYFUQRP/mT2Q0UyPvP49QwKYFbmsjs1srj/9+XA9tqmTBDHi+xo JjhrWArEqri/00ZoHd2zLgPkHhDxlXTr5qywi0NjUY5lXN+vL7MCGT9zCHH4gZxzscq9xx6AHPcM3 k67eQ6bzlrcKaarLCOz+64MV/cbB3SLfcSAw7Amjtn2uYoAEJUXKJ1yp55IUTCIGw4qM/I67FMk7w Uv5zoYkmXQrReWo7ofTou/9UV8em+Y6455b+5AI4Uhbv2jmlueCN/MKCzRKSPAb5mpSAS39/LNBvM usytsiKw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87bkcguspb.fsf@HIDDEN> (J. P.'s message of "Mon, 30 Oct 2023 06:48:32 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> <877cniaewr.fsf@HIDDEN> <877cncg3ss.fsf@HIDDEN> <87jzrcccw3.fsf@HIDDEN> <87lebra1io.fsf@HIDDEN> <87bkcguspb.fsf@HIDDEN> Date: Tue, 31 Oct 2023 17:28:48 -0700 Message-ID: <874ji6tiyn.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Recent work on this feature introduced an annoying regression. From emacs -Q: 1. M-: (erc-tls :server "testnet.inspircd.org") RET 2. /JOIN #test and say something 3. M-: (setq erc-timestamp-last-inserted-left nil) RET to reset the date stamp's deduping snapshot 4. Say something else 5. Notice that point has been dislodged from the prompt and that a new date stamp has not been inserted The second of the attached patches should fix it. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Fix-concurrency-bug-in-erc-buffer-display-test.patch From fd0fed210fca48cc8a7f754011b1e1aaabc4d9f4 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 30 Oct 2023 23:36:54 -0700 Subject: [PATCH 1/2] [5.6] ; Fix concurrency bug in erc-buffer-display test * test/lisp/erc/erc-fill-tests.el (erc-fill-tests--time-vals, erc-fill-tests--current-time-value): Rename former to latter and change type from function to natnum. (erc-fill-tests--wrap-populate, erc-fill-wrap--merge, erc-fill-wrap--merge-action): Use `erc-fill-tests--current-time-value' instead of function `erc-fill-tests--time-vals'. * test/lisp/erc/erc-scenarios-base-association.el (erc-scenarios-common--base-association-multi-net): Extend timeout. * test/lisp/erc/erc-scenarios-base-buffer-display.el (erc-scenarios-base-buffer-display--reconnect-common): Move some common assertions here from callers. (erc-scenarios-base-buffer-display--defwin-recbury-intbuf, erc-scenarios-base-buffer-display--count-reset-timeout): Factor out a couple common assertions. Clarify some comments. (erc-scenarios-base-buffer-display--defwino-recbury-intbuf): Factor out a couple common assertions. Clarify some comments. Account for possible concurrency bug leading to intermittent test failures. * test/lisp/erc/erc-scenarios-base-misc-regressions.el (erc-scenarios-base-gapless-connect, erc-scenarios-base-channel-buffer-revival): Extend timeouts. * test/lisp/erc/resources/dcc/chat/accept.eld: Extend timeout. * test/lisp/erc/resources/base/reconnect/options-again.eld: Extend timeouts. * test/lisp/erc/resources/erc-d/erc-d.el (erc-d--m): Prevent possible wrong-type error. * test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld: Extend timeouts. * test/lisp/erc/resources/erc-scenarios-common.el (erc-scenarios-common--base-network-id-bouncer): Extend timeout. --- test/lisp/erc/erc-fill-tests.el | 10 +- .../erc/erc-scenarios-base-association.el | 2 +- .../erc/erc-scenarios-base-buffer-display.el | 104 ++++++++++-------- .../erc-scenarios-base-misc-regressions.el | 4 +- .../base/reconnect/options-again.eld | 4 +- test/lisp/erc/resources/dcc/chat/accept.eld | 2 +- test/lisp/erc/resources/erc-d/erc-d.el | 2 +- .../erc-d/resources/dynamic-foonet.eld | 2 +- .../erc/resources/erc-scenarios-common.el | 2 +- 9 files changed, 73 insertions(+), 59 deletions(-) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index 92424d1e556..8179cbda2cb 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -27,7 +27,7 @@ (require 'erc-fill) (defvar erc-fill-tests--buffers nil) -(defvar erc-fill-tests--time-vals (lambda () 0)) +(defvar erc-fill-tests--current-time-value 0) (defun erc-fill-tests--insert-privmsg (speaker &rest msg-parts) (declare (indent 1)) @@ -49,7 +49,7 @@ erc-fill-tests--wrap-populate extended-command-history erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) (cl-letf (((symbol-function 'erc-stamp--current-time) - (lambda () (funcall erc-fill-tests--time-vals))) + (lambda () erc-fill-tests--current-time-value)) ((symbol-function 'erc-server-connect) (lambda (&rest _) (setq erc-server-process @@ -261,7 +261,7 @@ erc-fill-wrap--merge ;; Set this here so that the first few messages are from 1970. ;; Following the current date stamp, the speaker isn't merged ;; even though it's continued: "<bob> zero." - (let ((erc-fill-tests--time-vals (lambda () 1680332400))) + (let ((erc-fill-tests--current-time-value 1680332400)) (erc-fill-tests--insert-privmsg "bob" "zero.") (erc-fill-tests--insert-privmsg "alice" "one.") (erc-fill-tests--insert-privmsg "alice" "two.") @@ -297,8 +297,8 @@ erc-fill-wrap--merge-action (erc-fill-tests--wrap-populate (lambda () - ;; Set this here so that the first few messages are from 1970 - (let ((erc-fill-tests--time-vals (lambda () 1680332400))) + ;; Allow prior messages to be from 1970. + (let ((erc-fill-tests--current-time-value 1680332400)) (erc-fill-tests--insert-privmsg "bob" "zero.") (erc-fill-tests--insert-privmsg "bob" "0.5") diff --git a/test/lisp/erc/erc-scenarios-base-association.el b/test/lisp/erc/erc-scenarios-base-association.el index a40a4cb7550..10abe14c43b 100644 --- a/test/lisp/erc/erc-scenarios-base-association.el +++ b/test/lisp/erc/erc-scenarios-base-association.el @@ -78,7 +78,7 @@ erc-scenarios-common--base-association-multi-net (with-current-buffer "#chan@foonet" (funcall expect 3 "bob") (funcall expect 3 "was created on") - (funcall expect 3 "prosperous"))) + (funcall expect 10 "prosperous"))) (ert-info ("All #chan@barnet output consumed") (with-current-buffer "#chan@barnet" diff --git a/test/lisp/erc/erc-scenarios-base-buffer-display.el b/test/lisp/erc/erc-scenarios-base-buffer-display.el index df292a8c113..6a80baeaaa9 100644 --- a/test/lisp/erc/erc-scenarios-base-buffer-display.el +++ b/test/lisp/erc/erc-scenarios-base-buffer-display.el @@ -27,7 +27,10 @@ (eval-when-compile (require 'erc-join)) ;; These first couple `erc-auto-reconnect-display' tests used to live -;; in erc-scenarios-base-reconnect but have since been renamed. +;; in erc-scenarios-base-reconnect but have since been renamed. Note +;; that these are somewhat difficult to reason about because the user +;; joins a second channel after reconnecting, and the first is +;; controlled by `autojoin'. (defun erc-scenarios-base-buffer-display--reconnect-common (assert-server assert-chan assert-rest) @@ -55,6 +58,7 @@ erc-scenarios-base-buffer-display--reconnect-common (ert-info ("Wait for some output in channels") (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) (funcall assert-chan expect) + (funcall expect 10 "welcome") (funcall expect 10 "welcome"))) (ert-info ("Server buffer shows connection failed") @@ -68,6 +72,10 @@ erc-scenarios-base-buffer-display--reconnect-common (ert-info ("Wait for auto reconnect") (with-current-buffer "FooNet" (funcall expect 10 "still in debug mode"))) + (ert-info ("Lone window still shows messages buffer") + (should (eq (window-buffer) (messages-buffer))) + (should (frame-root-window-p (selected-window)))) + (funcall assert-rest expect) (ert-info ("Wait for activity to recommence in both channels") @@ -76,40 +84,50 @@ erc-scenarios-base-buffer-display--reconnect-common (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam")) (funcall expect 10 "her elves come here anon"))))) +;; Interactively issuing a slash command resets the auto-reconnect +;; count, making ERC ignore the option `erc-auto-reconnect-display' +;; when next displaying a newly set up buffer. In the case of a +;; /JOIN, the option `erc-interactive-display' takes precedence. (ert-deftest erc-scenarios-base-buffer-display--defwin-recbury-intbuf () :tags '(:expensive-test) (should (eq erc-buffer-display 'bury)) (should (eq erc-interactive-display 'window)) (should-not erc-auto-reconnect-display) - (let ((erc-buffer-display 'window) - (erc-interactive-display 'buffer) - (erc-auto-reconnect-display 'bury)) + (let ((erc-buffer-display 'window) ; defwin + (erc-interactive-display 'buffer) ; intbuf + (erc-auto-reconnect-display 'bury)) ; recbury (erc-scenarios-base-buffer-display--reconnect-common (lambda (_) - (should (eq (window-buffer) (current-buffer))) - (should-not (frame-root-window-p (selected-window)))) + (ert-info ("New server buffer appears in a selected split") + (should (eq (window-buffer) (current-buffer))) + (should-not (frame-root-window-p (selected-window))))) (lambda (_) - (should (eq (window-buffer) (current-buffer))) - (should (equal (get-buffer "FooNet") (window-buffer (next-window))))) + (ert-info ("New channel buffer appears in other window") + (should (eq (window-buffer) (current-buffer))) ; selected + (should (equal (get-buffer "FooNet") (window-buffer (next-window)))))) + + (lambda (expect) + ;; If we /JOIN #spam now, we'll cancel the auto-reconnect + ;; timer, and "#chan" may well pop up in a split before we can + ;; verify that the lone window displays #spam (a race, IOW). + (ert-info ("Autojoined channel #chan buried on JOIN") + (with-current-buffer "#chan" + (funcall expect 10 "You have joined channel #chan")) + (should (frame-root-window-p (selected-window))) + (should (eq (window-buffer) (messages-buffer)))) - (lambda (_) - (with-current-buffer "FooNet" - (should (eq (window-buffer) (messages-buffer))) - (should (frame-root-window-p (selected-window)))) - - ;; A manual /JOIN command tells ERC we're done auto-reconnecting (with-current-buffer "FooNet" (erc-scenarios-common-say "/JOIN #spam")) - (ert-info ("#spam ignores `erc-auto-reconnect-display'") - ;; Uses `erc-interactive-display' instead. + (ert-info ("A /JOIN ignores `erc-auto-reconnect-display'") (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam")) (should (eq (window-buffer) (get-buffer "#spam"))) - ;; Option `buffer' replaces entire window (no split) - (erc-d-t-wait-for 5 (frame-root-window-p (selected-window))))))))) + ;; Option `erc-interactive-display' being `buffer' means + ;; Emacs reuses the selected window (no split). + (should (frame-root-window-p (selected-window))))))))) (ert-deftest erc-scenarios-base-buffer-display--defwino-recbury-intbuf () :tags '(:expensive-test) @@ -117,7 +135,7 @@ erc-scenarios-base-buffer-display--defwino-recbury-intbuf (should (eq erc-interactive-display 'window)) (should-not erc-auto-reconnect-display) - (let ((erc-buffer-display 'window-noselect) + (let ((erc-buffer-display 'window-noselect) ; defwino (erc-auto-reconnect-display 'bury) (erc-interactive-display 'buffer)) (erc-scenarios-base-buffer-display--reconnect-common @@ -139,26 +157,24 @@ erc-scenarios-base-buffer-display--defwino-recbury-intbuf (should (eq (current-buffer) (window-buffer (next-window))))) (lambda (_) - (with-current-buffer "FooNet" - (should (eq (window-buffer) (messages-buffer))) - (should (frame-root-window-p (selected-window)))) - - ;; A non-interactive JOIN command doesn't signal that we're - ;; done auto-reconnecting, and `erc-interactive-display' is - ;; ignored, so `erc-buffer-display' is again in charge (here, - ;; that means `window-noselect'). - (ert-info ("Join chan noninteractively and open a /QUERY") + ;; A JOIN command sent from lisp code is "non-interactive" and + ;; doesn't reset the auto-reconnect count, so ERC treats the + ;; response as possibly server-initiated or otherwise the + ;; result of an autojoin and continues to favor + ;; `erc-auto-reconnect-display'. + (ert-info ("Join chan non-interactively and open a /QUERY") (with-current-buffer "FooNet" - (erc-cmd-JOIN "#spam") - ;; However this will reset the option. - (erc-scenarios-common-say "/QUERY bob") + (erc-cmd-JOIN "#spam") ; "non-interactive" according to ERC + (erc-scenarios-common-say "/QUERY bob") ; resets count (should (eq (window-buffer) (get-buffer "bob"))) (should (frame-root-window-p (selected-window))))) + ;; The /QUERY above resets the count, and `erc-buffer-display' + ;; again decides how #spam is displayed. (ert-info ("Newly joined chan ignores `erc-auto-reconnect-display'") (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam")) (should (eq (window-buffer) (get-buffer "bob"))) - (should-not (frame-root-window-p (selected-window))) + (should-not (frame-root-window-p (selected-window))) ; noselect (should (eq (current-buffer) (window-buffer (next-window)))))))))) (ert-deftest erc-scenarios-base-buffer-display--count-reset-timeout () @@ -177,24 +193,22 @@ erc-scenarios-base-buffer-display--count-reset-timeout (lambda (_) (with-current-buffer "FooNet" - (should erc--server-reconnect-display-timer) - (should (eq (window-buffer) (messages-buffer))) - (should (frame-root-window-p (selected-window)))) + (should erc--server-reconnect-display-timer)) ;; A non-interactive JOIN command doesn't signal that we're - ;; done auto-reconnecting - (ert-info ("Join chan noninteractively") + ;; done auto-reconnecting. + (ert-info ("Join channel #spam non-interactively") (with-current-buffer "FooNet" (erc-d-t-wait-for 1 (null erc--server-reconnect-display-timer)) - (erc-cmd-JOIN "#spam"))) + (erc-cmd-JOIN "#spam"))) ; not processed as a /JOIN - (ert-info ("Newly joined chan ignores `erc-auto-reconnect-display'") - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam")) - (should (eq (window-buffer) (messages-buffer))) - ;; If `erc-auto-reconnect-display-timeout' were left alone, this - ;; would be (frame-root-window-p #<window 1 on *scratch*>). - (should-not (frame-root-window-p (selected-window))) - (should (eq (current-buffer) (window-buffer (next-window)))))))))) + (ert-info ("Option `erc-auto-reconnect-display' ignored w/o timer") + (should (eq (window-buffer) (messages-buffer))) + (erc-d-t-wait-for 10 (get-buffer "#spam")) + ;; If `erc-auto-reconnect-display-timeout' were left alone, + ;; this would be (frame-root-window-p #<window 1 on scratch*>). + (should-not (frame-root-window-p (selected-window))) + (should (eq (get-buffer "#spam") (window-buffer (next-window))))))))) ;; This shows that the option `erc-interactive-display' overrides ;; `erc-join-buffer' during cold opens and interactive /JOINs. diff --git a/test/lisp/erc/erc-scenarios-base-misc-regressions.el b/test/lisp/erc/erc-scenarios-base-misc-regressions.el index c1915d088a0..42d7653d3ec 100644 --- a/test/lisp/erc/erc-scenarios-base-misc-regressions.el +++ b/test/lisp/erc/erc-scenarios-base-misc-regressions.el @@ -77,7 +77,7 @@ erc-scenarios-base-gapless-connect (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#bar")) (funcall expect 10 "was created on") - (funcall expect 2 "his second fit")) + (funcall expect 10 "his second fit")) (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#foo")) (funcall expect 10 "was created on") @@ -108,7 +108,7 @@ erc-scenarios-base-channel-buffer-revival (should (string= (buffer-name) (format "127.0.0.1:%d" port))))) (ert-info ("Server buffer is unique and temp name is absent") - (erc-d-t-wait-for 1 (get-buffer "FooNet")) + (erc-d-t-wait-for 10 (get-buffer "FooNet")) (should-not (erc-scenarios-common-buflist "127.0.0.1")) (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))) diff --git a/test/lisp/erc/resources/base/reconnect/options-again.eld b/test/lisp/erc/resources/base/reconnect/options-again.eld index f1fcc439cc3..8a3264fda9c 100644 --- a/test/lisp/erc/resources/base/reconnect/options-again.eld +++ b/test/lisp/erc/resources/base/reconnect/options-again.eld @@ -32,13 +32,13 @@ (0 ":irc.foonet.org 353 tester = #spam :alice tester @bob") (0 ":irc.foonet.org 366 tester #spam :End of NAMES list")) -((~mode-chan 4 "MODE #chan") +((~mode-chan 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620104779") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: But, as it seems, did violence on herself.") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :bob: Well, this is the forest of Arden.")) -((mode-spam 4 "MODE #spam") +((mode-spam 20 "MODE #spam") (0 ":irc.foonet.org 324 tester #spam +nt") (0 ":irc.foonet.org 329 tester #spam 1620104779") (0.1 ":bob!~u@HIDDEN PRIVMSG #spam :alice: Signior Iachimo will not from it. Pray, let us follow 'em.") diff --git a/test/lisp/erc/resources/dcc/chat/accept.eld b/test/lisp/erc/resources/dcc/chat/accept.eld index a23e9580bcc..463f931d26f 100644 --- a/test/lisp/erc/resources/dcc/chat/accept.eld +++ b/test/lisp/erc/resources/dcc/chat/accept.eld @@ -17,7 +17,7 @@ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 1.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") ;; No mode answer (0 ":irc.foonet.org NOTICE tester :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.") (0.2 ":dummy!~u@HIDDEN PRIVMSG tester :\C-aDCC CHAT chat 2130706433 " port "\C-a")) diff --git a/test/lisp/erc/resources/erc-d/erc-d.el b/test/lisp/erc/resources/erc-d/erc-d.el index f072c6b93b2..a87904e5830 100644 --- a/test/lisp/erc/resources/erc-d/erc-d.el +++ b/test/lisp/erc/resources/erc-d/erc-d.el @@ -297,7 +297,7 @@ erc-d--m (when erc-d--m-debug (setq format-string (concat (format-time-string "%s.%N: ") format-string))) (let ((insertp (and process erc-d--in-process)) - (buffer (process-buffer (process-get process :server)))) + (buffer (and process (process-buffer (process-get process :server))))) (when (and insertp (buffer-live-p buffer)) (princ (concat (apply #'format format-string args) "\n") buffer)) (when (or erc-d--m-debug (not insertp)) diff --git a/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld b/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld index e5532980644..2db750e49da 100644 --- a/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld +++ b/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld @@ -17,7 +17,7 @@ (0. ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0. ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 2 "MODE tester +i") +((mode-user 4 "MODE tester +i") (0. ":irc.foonet.org 221 tester +Zi") (0. ":irc.foonet.org 306 tester :You have been marked as being away") (0 ":tester!~u@HIDDEN JOIN #chan") diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el index 9e134e6932f..802ccaeedaa 100644 --- a/test/lisp/erc/resources/erc-scenarios-common.el +++ b/test/lisp/erc/resources/erc-scenarios-common.el @@ -455,7 +455,7 @@ erc-scenarios-common--base-network-id-bouncer :id foo-id)) (setq erc-server-process-foo erc-server-process) (erc-scenarios-common-assert-initial-buf-name foo-id port) - (erc-d-t-wait-for 3 (eq (erc-network) 'foonet)) + (erc-d-t-wait-for 6 (eq (erc-network) 'foonet)) (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-foo)) (funcall expect 5 "foonet"))) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Preserve-point-when-inserting-date-stamps-in-ERC.patch From 65142a8d39af7072a51911ffaf1bd38b2b53fd13 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Tue, 31 Oct 2023 16:50:16 -0700 Subject: [PATCH 2/2] [5.6] Preserve point when inserting date stamps in ERC * lisp/erc/erc-stamp.el (erc-stamp--insert-date-stamp-as-phony-message): Move `erc--msg-props' binding to `erc-stamp--lr-date-on-pre-modify'. (erc-stamp--lr-date-on-pre-modify): Bind `erc--msg-props' here so that the related guard condition in `erc-add-timestamp' is satisfied and `erc-insert-timestamp-function' runs. This fixes a regression new in ERC 5.6 and introduced by c68dc778 "Manage some text props for ERC insertion-hook members". Also, `save-excursion' when narrowing to prevent point from being dislodged at the prompt. (erc-insert-timestamp-left-and-right): Allow global hook members to run so that those owned by `scrolltobottom' and similar get first dibs. Also fix wrong hook name. (erc-stamp--setup): Fix wrong hook name. (Bug#60936) --- lisp/erc/erc-stamp.el | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index b3812470a4d..7c5413a43c9 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -666,9 +666,6 @@ erc-stamp--insert-date-stamp-as-phony-message (setq string erc-stamp--current-datestamp-left) (cl-assert string) (let ((erc-stamp--skip t) - (erc--msg-props (map-into `((erc-msg . datestamp) - (erc-ts . ,(erc-stamp--current-time))) - 'hash-table)) (erc-insert-modify-hook `(,@erc-insert-modify-hook erc-stamp--propertize-left-date-stamp)) ;; Don't run hooks that aren't expecting a narrowed buffer. @@ -684,11 +681,17 @@ erc-stamp--lr-date-on-pre-modify (erc-stamp--current-datestamp-left rendered) (erc-insert-timestamp-function #'erc-stamp--insert-date-stamp-as-phony-message)) - (save-restriction - (narrow-to-region (or erc--insert-marker erc-insert-marker) - (or erc--insert-marker erc-insert-marker)) - (let (erc-timestamp-format erc-away-timestamp-format) - (erc-add-timestamp))))) + (save-excursion + (save-restriction + (narrow-to-region (or erc--insert-marker erc-insert-marker) + (or erc--insert-marker erc-insert-marker)) + ;; Forget current `erc-cmd', etc. + (let ((erc--msg-props + (map-into `((erc-msg . datestamp) + (erc-ts . ,(erc-stamp--current-time))) + 'hash-table)) + erc-timestamp-format erc-away-timestamp-format) + (erc-add-timestamp)))))) (defvar erc-stamp-prepend-date-stamps-p nil "When non-nil, date stamps are not independent messages. @@ -715,8 +718,8 @@ erc-insert-timestamp-left-and-right that internal modules can easily distinguish between other left-sided stamps and date stamps inserted by this function." (unless (or erc-stamp--date-format-end erc-stamp-prepend-date-stamps-p) - (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify -95 t) - (add-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify -95 t) + (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify 10 t) + (add-hook 'erc-pre-send-functions #'erc-stamp--lr-date-on-pre-modify 10 t) (let ((erc--insert-marker (point-min-marker)) (end-marker (point-max-marker))) (set-marker-insertion-type erc--insert-marker t) @@ -817,7 +820,7 @@ erc-stamp--setup (erc-munge-invisibility-spec)) ;; Undo local mods from `erc-insert-timestamp-left-and-right'. (remove-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify t) - (remove-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify t) + (remove-hook 'erc-pre-send-functions #'erc-stamp--lr-date-on-pre-modify t) (kill-local-variable 'erc-stamp--date-format-end))) (defun erc-hide-timestamps () -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 30 Oct 2023 13:49:17 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon Oct 30 09:49:17 2023 Received: from localhost ([127.0.0.1]:44586 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qxSdp-0004zD-BY for submit <at> debbugs.gnu.org; Mon, 30 Oct 2023 09:49:17 -0400 Received: from mail-108-mta249.mxroute.com ([136.175.108.249]:38951) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qxSdn-0004z2-5l for 60936 <at> debbugs.gnu.org; Mon, 30 Oct 2023 09:49:15 -0400 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta249.mxroute.com (ZoneMTA) with ESMTPSA id 18b80d7eb7e000190b.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Mon, 30 Oct 2023 13:48:36 +0000 X-Zone-Loop: aea86b70e35eab99aecd337a5dafd960499c0abf294a 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=n9OScHxz879BBnPBCUPSbJqDsod29m2jlnFaSUO/FiM=; b=meGHkBjONmPZ1rV2sjIIhJXa5w HxVHf/FZqpJfe/3+wqJUF0KI8G4NGgQbtT101xYPII7M8SW6Dv0gkPGUNm6cazf7md1g727AMhkGJ RDzNyJTf9OdNVKK8vnlBEcWeePij+BJaFsG5A183fWfWkW5f8eIU2do3FTiy5cEj4472bZPSxgaEJ NwRN6Uyczbag+aAhtL8REVj6LZGCFP+JjnVkh4dG/tmk4O0hmFKR0w7dqwb5WVMyTMpzJuKOXUXQu Wy4/nCJRf6nez5zf8/1dBeol5OJiOwwm+4bpdPMwHMRuNYSvep4liIqb6vNkpmPJwK5FvChn+yD0s s36hBaOg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87lebra1io.fsf@HIDDEN> (J. P.'s message of "Tue, 24 Oct 2023 19:17:51 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> <877cniaewr.fsf@HIDDEN> <877cncg3ss.fsf@HIDDEN> <87jzrcccw3.fsf@HIDDEN> <87lebra1io.fsf@HIDDEN> Date: Mon, 30 Oct 2023 06:48:32 -0700 Message-ID: <87bkcguspb.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > This also needs > > (erc-insert-pre-hook nil) > >> + (erc-insert-done-hook nil)) >> (erc-display-message nil nil (current-buffer) string) >> (setq erc-timestamp-last-inserted-left string))) > > because any hook member that can't operate in a narrowed buffer will > fail, especially on init, when the narrowed region is empty. The change above was included as part of 5c4a9b73031 * Use marker for max pos in erc--traverse-inserted This bug is already closed.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 25 Oct 2023 02:18:30 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 24 22:18:30 2023 Received: from localhost ([127.0.0.1]:56982 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qvTTa-0007OJ-EG for submit <at> debbugs.gnu.org; Tue, 24 Oct 2023 22:18:30 -0400 Received: from mail-108-mta136.mxroute.com ([136.175.108.136]:41721) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qvTTX-0007OA-Il for 60936 <at> debbugs.gnu.org; Tue, 24 Oct 2023 22:18:28 -0400 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta136.mxroute.com (ZoneMTA) with ESMTPSA id 18b649fc8860008912.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 25 Oct 2023 02:17:55 +0000 X-Zone-Loop: 008dc43d507931a24a36def5b29ca3e3bc9d98eeab8a 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=7o32oAV7QuSo7cxL4Luk0LMVueyR6Safgff0mUHHvI0=; b=jEa1L/T3+dKZhkviA8ZaXrRxEe k6KSo56KI4/LDo+830FHaoNsEYkkSYOofL3VJGYNxUBmSMPiBPfxa804FWgWYxW7Jv0Q2vFxAmXRS ATgmGYMHV8lfMk9C2TqdphdV8TxlC06LG/GJBb10/iK3tnQaXFBJWeK3ZVGPVA7zllCtEKs1FJzSl YuvYuO9dQb1tQhAPlw0QGIhBd8caCMByNLpTOnV7zPv2gOxzBcooxECYfw9jvDnY+cyUhtN18Lkf5 CNk0kUG8NJ1NAAbNzw6J3wYKd6gtq3zSmFLUX9tHUco23ezU94J+kuvddwXW6iV9qHRC6RdonwBGJ NN09joDQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87jzrcccw3.fsf@HIDDEN> (J. P.'s message of "Tue, 24 Oct 2023 07:29:16 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> <877cniaewr.fsf@HIDDEN> <877cncg3ss.fsf@HIDDEN> <87jzrcccw3.fsf@HIDDEN> Date: Tue, 24 Oct 2023 19:17:51 -0700 Message-ID: <87lebra1io.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > v2. Fix date-stamp regression in erc-track. Optionally reinstate old > "prepended" date-stamp behavior gated by new compat var. > > [...] > > @@ -665,19 +666,17 @@ erc-stamp--insert-date-stamp-as-phony-message > (cl-assert string) > (let ((erc-stamp--skip t) > (erc--msg-props (map-into `((erc-msg . datestamp) > - (erc-ts . ,erc-stamp--current-time)) > + (erc-ts . ,(erc-stamp--current-time))) > 'hash-table)) > - (erc-send-modify-hook `(,@erc-send-modify-hook > - erc-stamp--propertize-left-date-stamp > - ,@erc-stamp--insert-date-hook)) > (erc-insert-modify-hook `(,@erc-insert-modify-hook > - erc-stamp--propertize-left-date-stamp > - ,@erc-stamp--insert-date-hook))) > + erc-stamp--propertize-left-date-stamp)) > + ;; Don't run hooks that aren't expecting a narrowed buffer. This also needs (erc-insert-pre-hook nil) > + (erc-insert-done-hook nil)) > (erc-display-message nil nil (current-buffer) string) > (setq erc-timestamp-last-inserted-left string))) because any hook member that can't operate in a narrowed buffer will fail, especially on init, when the narrowed region is empty.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 24 Oct 2023 17:11:13 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 24 13:11:13 2023 Received: from localhost ([127.0.0.1]:56536 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qvKvw-0006bt-P3 for submit <at> debbugs.gnu.org; Tue, 24 Oct 2023 13:11:13 -0400 Received: from mail-ot1-f49.google.com ([209.85.210.49]:58410) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <mplscorwin@HIDDEN>) id 1qvKvt-0006bf-5J for 60936 <at> debbugs.gnu.org; Tue, 24 Oct 2023 13:11:11 -0400 Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-6ce344fa7e4so3201478a34.0 for <60936 <at> debbugs.gnu.org>; Tue, 24 Oct 2023 10:10:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698167434; x=1698772234; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=SDGBgiSmAyrTiCTywW/OibuNx2rXX3ZIEc6pCxDUisU=; b=MFQRGVgMVRpOEd3yBxz48+7a/co6kmfiWlBs36XjEPRiWh8Wr94nG5HOUuhpOQzZXF YKVTTlw45izVLmQqHPOmlFUXXFjDGLyZJhkuzHUlp5TZ9x39G6B4jbILGh6q7IpYcNx8 vX2TghxuNHH4I+I1Wmv4poi6QKnfW2zCzZNxMLhaWjrOhamYXRyC4xDS2ZBGoyTvfucc r04vtfu3OS6sasyqlSbma3lSI0J5R9lMw8ldRWgX1TzY0UQTb5HKFgzJ22vGwzcU7Sx1 DEOF1u3iK5avZw38/0p9M/lG26nDY7OLHbNn9NNFDj75hsDrPXHzycYXDLAQsZ7Ks648 22Hw== X-Gm-Message-State: AOJu0YyFI9yFYnE2BbsmMNWgtux9tq9sEe2eaI6Axt4M8zwSyazxPIDU jeUTdvxdjO4hGwykGAnJCBECK82MmMOISFmj3bk= X-Google-Smtp-Source: AGHT+IGuPSmXlD4TqPJNPvj2cHMYVflVJi3U5PEc2fJwMnVGWAPwIDInXTLXxPDrar/PWNU7mUKTXbXFNY+jo/j0jes= X-Received: by 2002:a05:6830:2646:b0:6b4:5ed3:8246 with SMTP id f6-20020a056830264600b006b45ed38246mr15001619otu.2.1698167433834; Tue, 24 Oct 2023 10:10:33 -0700 (PDT) MIME-Version: 1.0 References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> <877cniaewr.fsf@HIDDEN> <877cncg3ss.fsf@HIDDEN> <87jzrcccw3.fsf@HIDDEN> In-Reply-To: <87jzrcccw3.fsf@HIDDEN> From: Corwin Brust <corwin@HIDDEN> Date: Tue, 24 Oct 2023 12:10:22 -0500 Message-ID: <CAJf-WoQ8seg-uqhgseNc_A3ihxCFj557EvzAMKxv6JGyXS8bVQ@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode To: "J.P." <jp@HIDDEN> Content-Type: multipart/alternative; boundary="000000000000a9b58c0608796a4a" X-Spam-Score: 0.5 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -0.5 (/) --000000000000a9b58c0608796a4a Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Oct 24, 2023 at 9:29=E2=80=AFAM J.P. <jp@HIDDEN> wrote: > v2. Fix date-stamp regression in erc-track. Optionally reinstate old > "prepended" date-stamp behavior gated by new compat var. > > Earlier changes for this feature introduced a regression involving date > stamps and the option `erc-track-exclude-types'. Basically, date stamps > > [SNIP] > > To reproduce from -Q: > > 1. Connect and ensure "JOIN" appears in `erc-track-exclude-types' > 2. Join #chan > 3. From the server buffer, do > > (with-current-buffer "#chan" > (setq erc-timestamp-last-inserted-left nil)) > > 3. Connect and join #chan from another client > 4. Notice a [#c] in the mode line of the original client > > I can no longer reproduce after applying the 001-003 patches from your last to rev 522a74d60a915ca9e922ad42dedc19d9f72e3ae5 Thank you JP! --000000000000a9b58c0608796a4a Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div dir=3D"ltr">On Tue, Oct 24, 2023 at 9:29=E2=80=AFAM J= .P. <<a href=3D"mailto:jp@HIDDEN">jp@HIDDEN</a>> wrote:<br>= </div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D= "margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-le= ft:1ex">v2. Fix date-stamp regression in erc-track. Optionally reinstate ol= d<br> "prepended" date-stamp behavior gated by new compat var.<br> <br> Earlier changes for this feature introduced a regression involving date<br> stamps and the option `erc-track-exclude-types'. Basically, date stamps= <br> <br></blockquote><div><br></div><div>[SNIP]</div><div>=C2=A0</div><blockquo= te class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px = solid rgb(204,204,204);padding-left:1ex"> <br> To reproduce from -Q:<br> <br> =C2=A0 1. Connect and ensure "JOIN" appears in `erc-track-exclude= -types'<br> =C2=A0 2. Join #chan<br> =C2=A0 3. From the server buffer, do<br> <br> =C2=A0 =C2=A0 =C2=A0(with-current-buffer "#chan"<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq erc-timestamp-last-inserted-left nil))<br> <br> =C2=A0 3. Connect and join #chan from another client<br> =C2=A0 4. Notice a [#c] in the mode line of the original client<br> <br></blockquote><div><br></div><div>I can no longer reproduce after applyi= ng the 001-003 patches from your last to rev=C2=A0522a74d60a915ca9e922ad42d= edc19d9f72e3ae5</div><div><br></div><div>Thank you JP!</div></div></div> --000000000000a9b58c0608796a4a--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 24 Oct 2023 14:30:00 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 24 10:30:00 2023 Received: from localhost ([127.0.0.1]:56104 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qvIPu-0007iA-CA for submit <at> debbugs.gnu.org; Tue, 24 Oct 2023 10:30:00 -0400 Received: from mail-108-mta172.mxroute.com ([136.175.108.172]:45985) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qvIPp-0007hz-4w for 60936 <at> debbugs.gnu.org; Tue, 24 Oct 2023 10:29:57 -0400 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta172.mxroute.com (ZoneMTA) with ESMTPSA id 18b621710f10008912.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Tue, 24 Oct 2023 14:29:20 +0000 X-Zone-Loop: 7646fcb628dfc912cf9e011a75eb67a58a3561e7a37e 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=moywq4/QX3aN4rS7Mw9uWNMQR4B8iq2pKYmV/AvCoOQ=; b=GERaL+T+6Ayck6GLUFa296F1oF i71jHAzDLrrZNnASUEO3VSndEjuo6X6eanlHhbqT+oD91DVQajQIa+X+XWKfZBADqRCxeMSlRiUoD j1hNRuF3D8mmfsgxPRM9vAlwV8GD0x9Cz0aa6EqysoYGTmYvV5XkzoPoSKOUuAsSJAqa3IuDnRfJH wl31yFVBYR3fhKRFBS+daBmSgOaBR5fpcfkeMrx6IdGelm7kJpvgE7MVnQL4lqYO6uOsRByN0t+so FCuVsR7km4cDjYSZoB33RjtoRLNBk1vyV1E7Baa3XfhXicnz1c0bGanRa7Lk9rB3ZtlLBh5fTLgLn e/alLMGQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <877cncg3ss.fsf@HIDDEN> (J. P.'s message of "Mon, 23 Oct 2023 19:19:47 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> <877cniaewr.fsf@HIDDEN> <877cncg3ss.fsf@HIDDEN> Date: Tue, 24 Oct 2023 07:29:16 -0700 Message-ID: <87jzrcccw3.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain v2. Fix date-stamp regression in erc-track. Optionally reinstate old "prepended" date-stamp behavior gated by new compat var. Earlier changes for this feature introduced a regression involving date stamps and the option `erc-track-exclude-types'. Basically, date stamps aren't supposed to affect the mode line, at least so long as their inciting message's command appears in `erc-track-exclude-types'. However, this changed after c68dc7786fc * Manage some text props for ERC insertion-hook members To reproduce from -Q: 1. Connect and ensure "JOIN" appears in `erc-track-exclude-types' 2. Join #chan 3. From the server buffer, do (with-current-buffer "#chan" (setq erc-timestamp-last-inserted-left nil)) 3. Connect and join #chan from another client 4. Notice a [#c] in the mode line of the original client Thanks to Corwin for pointing this out. The way I'm proposing we tackle this is to decouple date stamps from `erc-track-exclude-types' completely. That is, have erc-track completely ignore them, so they never affect the mode line. In addition to this fix, I've also added a path for accessing the old behavior in which date stamps aren't standalone messages. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v1-v2.diff From 48dfdc118270fbd72ea93ca02363dcda5d7ef528 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Tue, 24 Oct 2023 07:09:53 -0700 Subject: [PATCH 0/3] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (3): ; * lisp/erc/erc.el (erc-after-connect): Remove package-version. [5.6] Ignore date stamps in erc-track [5.6] Ensure marker for max pos in erc--traverse-inserted etc/ERC-NEWS | 10 ++- lisp/erc/erc-stamp.el | 36 +++++++--- lisp/erc/erc-track.el | 14 ++-- lisp/erc/erc.el | 36 ++++++++-- test/lisp/erc/erc-scenarios-stamp.el | 28 +++++++- test/lisp/erc/erc-tests.el | 84 ++++++++++++++++++++++-- test/lisp/erc/resources/erc-d/erc-d-t.el | 1 + 7 files changed, 182 insertions(+), 27 deletions(-) Interdiff: diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 41ab9cc4c5e..f59023eae62 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -228,6 +228,12 @@ with a legitimate use for this option likely also possesses the knowledge to rig up a suitable analog with minimal effort. That said, the road to removal is long. +** The 'track' module always ignores date stamps. +Users of the stamp module who leave 'erc-insert-timestamp-function' +set to its default of 'erc-insert-timestamp-left-and-right' will find +that date stamps no longer affect the mode line, even for IRC commands +not included in 'erc-track-exclude-types'. + ** Option 'erc-warn-about-blank-lines' is more informative. Enabled by default, this option now produces more useful feedback whenever ERC rejects prompt input containing whitespace-only lines. @@ -348,7 +354,9 @@ leading portion of message bodies as well as special casing to act on these areas without inflicting collateral damage. It may also be worth noting that as consequence of these changes, the internally managed variable 'erc-timestamp-last-inserted-left' no longer records -the final trailing newline in 'erc-timestamp-format-left'. +the final trailing newline in 'erc-timestamp-format-left'. If you +must, see variable 'erc-stamp-prepend-date-stamps-p' for a temporary +escape hatch. *** The role of a module's Custom group is now more clearly defined. Associating built-in modules with Custom groups and provided library diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 56fa975c32d..6e35c5e2244 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -688,6 +688,16 @@ erc-stamp--lr-date-on-pre-modify (let (erc-timestamp-format erc-away-timestamp-format) (erc-add-timestamp))))) +(defvar erc-stamp-prepend-date-stamps-p nil + "When non-nil, don't treat date stamps as independent messages. +This is an escape hatch. When enabled, expect post-5.5 features, +like `fill-wrap', dynamic invisibility, etc., to malfunction +severely or lead to a degraded experience. Also know that +support for the default configuration, without any customization, +may expire before the next major release.") +(make-obsolete-variable 'erc-stamp-prepend-date-stamps-p + "unsupported legacy behavior" "30.1") + (defun erc-insert-timestamp-left-and-right (string) "Insert a stamp on either side when it changes. When the deprecated option `erc-timestamp-format-right' is nil, @@ -702,7 +712,7 @@ erc-insert-timestamp-left-and-right Additionally, ensure every date stamp is identifiable as such so that internal modules can easily distinguish between other left-sided stamps and date stamps inserted by this function." - (unless erc-stamp--date-format-end + (unless (or erc-stamp--date-format-end erc-stamp-prepend-date-stamps-p) (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify -95 t) (add-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify -95 t) (let ((erc--insert-marker (point-min-marker)) @@ -718,6 +728,13 @@ erc-insert-timestamp-left-and-right (if erc-timestamp-format-right (erc-format-timestamp ct erc-timestamp-format-right) string)))) + ;; Maybe insert legacy date stamp. + (when-let ((erc-stamp-prepend-date-stamps-p) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + ((not (string= ts-left erc-timestamp-last-inserted-left)))) + (goto-char (point-min)) + (erc-put-text-property 0 (length ts-left) 'field 'erc-timestamp ts-left) + (insert (setq erc-timestamp-last-inserted-left ts-left))) ;; insert right timestamp (let ((erc-timestamp-only-if-changed-flag t) (erc-timestamp-last-inserted erc-timestamp-last-inserted-right)) diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el index c8f2e04c3eb..a36b781e04d 100644 --- a/lisp/erc/erc-track.el +++ b/lisp/erc/erc-track.el @@ -785,6 +785,9 @@ erc-track-select-mode-line-face choice)) choice)))) +(defvar erc-track--skipped-msgs '(datestamp) + "Values of `erc-msg' text prop to ignore.") + (defun erc-track-modified-channels () "Hook function for `erc-insert-post-hook'. Check if the current buffer should be added to the mode line as a @@ -798,10 +801,13 @@ erc-track-modified-channels ;; FIXME either use `erc--server-buffer-p' or ;; explain why that's unwise. (erc-server-or-unjoined-channel-buffer-p))) - (not (erc-message-type-member - (or (erc-find-parsed-property) - (point-min)) - erc-track-exclude-types))) + (not (let ((parsed (erc-find-parsed-property))) + (or (erc-message-type-member (or parsed (point-min)) + erc-track-exclude-types) + ;; Skip certain non-server-sent messages. + (and (not parsed) + (erc--check-msg-prop 'erc-msg + erc-track--skipped-msgs)))))) ;; If the active buffer is not visible (not shown in a ;; window), and not to be excluded, determine the kinds of ;; faces used in the current message, and unless the user diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 92f6f1fcb1f..872ce5b4f49 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2490,7 +2490,6 @@ erc-after-connect to the 376/422 message's \"sender\", as well as the current nick, as given by the 376/422 message's \"target\" parameter, which is typically the same as that reported by `erc-current-nick'." - :package-version '(ERC . "5.6") ; FIXME sync on release :group 'erc-hooks :type '(repeat function)) @@ -2981,7 +2980,7 @@ erc--get-inserted-msg-bounds (and-let* ((p (previous-single-property-change point 'erc-msg))) - (if (= p (1- point)) point (1- p))))))) + (if (= p (1- point)) p (1- p))))))) ,@(and (member only '(nil 'end)) '((e (1- (next-single-property-change (if at-start-p (1+ point) point) diff --git a/test/lisp/erc/erc-scenarios-stamp.el b/test/lisp/erc/erc-scenarios-stamp.el index d6b5d868ce5..c420e62fe14 100644 --- a/test/lisp/erc/erc-scenarios-stamp.el +++ b/test/lisp/erc/erc-scenarios-stamp.el @@ -50,7 +50,6 @@ erc-scenarios-stamp--left/display-margin-mode (erc-stamp--current-time 704591940) (erc-stamp--tz t) (erc-server-flood-penalty 0.1) - (erc-timestamp-only-if-changed-flag nil) (erc-insert-timestamp-function #'erc-insert-timestamp-left) (erc-modules (cons 'fill-wrap erc-modules)) (erc-timestamp-only-if-changed-flag nil) @@ -87,4 +86,31 @@ erc-scenarios-stamp--left/display-margin-mode (should (looking-back "CEIMRUabefhiklmnoqstuv\n")) (should (looking-at (rx "["))))))))) +(ert-deftest erc-scenarios-stamp--legacy-date-stamps () + (with-suppressed-warnings ((obsolete erc-stamp-prepend-date-stamps-p)) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/reconnect") + (erc-stamp-prepend-date-stamps-p t) + (dumb-server (erc-d-run "localhost" t 'unexpected-disconnect)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (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") + (funcall expect 5 "opening connection") + (goto-char (1- (match-beginning 0))) + (should (eq 'erc-timestamp (field-at-pos (point)))) + (should (eq 'unknown (erc--get-inserted-msg-prop 'erc-msg))) + ;; Force redraw of date stamp. + (setq erc-timestamp-last-inserted-left nil) + + (funcall expect 5 "This server is in debug mode") + (while (and (zerop (forward-line -1)) + (not (eq 'erc-timestamp (field-at-pos (point)))))) + (should (erc--get-inserted-msg-prop 'erc-cmd))))))) + ;;; erc-scenarios-stamp.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 6429fce8861..1af087e7e31 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1481,7 +1481,30 @@ erc--delete-inserted-message (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) (let ((erc-legacy-invisible-bounds-p t)) (erc--delete-inserted-message (point)))) - (should (looking-at (rx "*** four\n"))))) + (should (looking-at (rx "*** four\n")))) + + (ert-info ("Deleting most recent message preserves markers") + (let ((m (point-marker)) + (n (point-marker)) + (p (point))) + (should (equal "*** four\n" (buffer-substring p erc-insert-marker))) + (set-marker-insertion-type m t) + (goto-char (point-max)) + (erc--delete-inserted-message p) + (should (= (marker-position m) p)) + (should (= (marker-position n) p)) + (goto-char p) + (should (looking-back (rx "*** one\n"))) + (should (looking-at erc-prompt)) + (erc--assert-input-bounds) + + ;; However, `m' is now forever "trapped" at `erc-insert-marker'. + (erc-display-message nil 'notice nil "two") + (should (= m erc-insert-marker)) + (goto-char n) + (should (looking-at (rx "*** two\n"))) + (set-marker m nil) + (set-marker n nil)))) (ert-deftest erc--order-text-properties-from-hash () (let ((table (map-into '((a . 1) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-lisp-erc-erc.el-erc-after-connect-Remove-package-ver.patch From 359cd55879ee0bce87b52547e1d3e3ee087d8108 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Oct 2023 19:33:32 -0700 Subject: [PATCH 1/3] ; * lisp/erc/erc.el (erc-after-connect): Remove package-version. --- lisp/erc/erc.el | 1 - 1 file changed, 1 deletion(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 7d75ec49ccd..f618fb17076 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2490,7 +2490,6 @@ erc-after-connect to the 376/422 message's \"sender\", as well as the current nick, as given by the 376/422 message's \"target\" parameter, which is typically the same as that reported by `erc-current-nick'." - :package-version '(ERC . "5.6") ; FIXME sync on release :group 'erc-hooks :type '(repeat function)) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Ignore-date-stamps-in-erc-track.patch From bfe93b485c0760bd7c23f8bf3e8da8c53b68069b Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Oct 2023 21:59:25 -0700 Subject: [PATCH 2/3] [5.6] Ignore date stamps in erc-track * etc/ERC-NEWS: Mention that date stamps no longer optionally affect the mode line. Also mention but discourage new variable 'erc-stamp-prepend-date-stamps-p'. * lisp/erc/erc-stamp.el (erc-stamp-prepend-date-stamps-p): New variable, an escape hatch to allow date stamps to once again be prepended to messages. (erc-insert-timestamp-left-and-right): Don't insert stamps as independent messages when legacy flag `erc-stamp-prepend-date-stamps-p' is non-nil. * lisp/erc/erc-track.el (erc-track--skipped-msgs): New internal variable. (erc-track-modified-channels): In previous versions, a date stamp accompanying a message for an IRC command appearing in `erc-track-exclude-types' would have no effect on the mode line. That they were able to otherwise was probably a bug. Regardless, this behavior changed after date stamps became independent messages with c68dc7786fc "Manage some text props for ERC insertion-hook members". This commit corrects this regression by making ERC always ignore date stamps. Thanks to Corwin Brust for spotting this. * test/lisp/erc/erc-scenarios-stamp.el (erc-scenarios-stamp--left/display-margin-mode): Remove redundant binding. (erc-scenarios-stamp--legacy-date-stamps): New test. (Bug#60936) --- etc/ERC-NEWS | 10 +++++++++- lisp/erc/erc-stamp.el | 19 ++++++++++++++++++- lisp/erc/erc-track.el | 14 ++++++++++---- test/lisp/erc/erc-scenarios-stamp.el | 28 +++++++++++++++++++++++++++- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 41ab9cc4c5e..f59023eae62 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -228,6 +228,12 @@ with a legitimate use for this option likely also possesses the knowledge to rig up a suitable analog with minimal effort. That said, the road to removal is long. +** The 'track' module always ignores date stamps. +Users of the stamp module who leave 'erc-insert-timestamp-function' +set to its default of 'erc-insert-timestamp-left-and-right' will find +that date stamps no longer affect the mode line, even for IRC commands +not included in 'erc-track-exclude-types'. + ** Option 'erc-warn-about-blank-lines' is more informative. Enabled by default, this option now produces more useful feedback whenever ERC rejects prompt input containing whitespace-only lines. @@ -348,7 +354,9 @@ leading portion of message bodies as well as special casing to act on these areas without inflicting collateral damage. It may also be worth noting that as consequence of these changes, the internally managed variable 'erc-timestamp-last-inserted-left' no longer records -the final trailing newline in 'erc-timestamp-format-left'. +the final trailing newline in 'erc-timestamp-format-left'. If you +must, see variable 'erc-stamp-prepend-date-stamps-p' for a temporary +escape hatch. *** The role of a module's Custom group is now more clearly defined. Associating built-in modules with Custom groups and provided library diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index b515513dcb7..e0db472d289 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -689,6 +689,16 @@ erc-stamp--lr-date-on-pre-modify (let (erc-timestamp-format erc-away-timestamp-format) (erc-add-timestamp))))) +(defvar erc-stamp-prepend-date-stamps-p nil + "When non-nil, don't treat date stamps as independent messages. +This is an escape hatch. When enabled, expect post-5.5 features, +like `fill-wrap', dynamic invisibility, etc., to malfunction +severely or lead to a degraded experience. Also know that +support for the default configuration, without any customization, +may expire before the next major release.") +(make-obsolete-variable 'erc-stamp-prepend-date-stamps-p + "unsupported legacy behavior" "30.1") + (defun erc-insert-timestamp-left-and-right (string) "Insert a stamp on either side when it changes. When the deprecated option `erc-timestamp-format-right' is nil, @@ -703,7 +713,7 @@ erc-insert-timestamp-left-and-right Additionally, ensure every date stamp is identifiable as such so that internal modules can easily distinguish between other left-sided stamps and date stamps inserted by this function." - (unless erc-stamp--date-format-end + (unless (or erc-stamp--date-format-end erc-stamp-prepend-date-stamps-p) (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify -95 t) (add-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify -95 t) (let ((erc--insert-marker (point-min-marker)) @@ -719,6 +729,13 @@ erc-insert-timestamp-left-and-right (if erc-timestamp-format-right (erc-format-timestamp ct erc-timestamp-format-right) string)))) + ;; Maybe insert legacy date stamp. + (when-let ((erc-stamp-prepend-date-stamps-p) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + ((not (string= ts-left erc-timestamp-last-inserted-left)))) + (goto-char (point-min)) + (erc-put-text-property 0 (length ts-left) 'field 'erc-timestamp ts-left) + (insert (setq erc-timestamp-last-inserted-left ts-left))) ;; insert right timestamp (let ((erc-timestamp-only-if-changed-flag t) (erc-timestamp-last-inserted erc-timestamp-last-inserted-right)) diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el index c8f2e04c3eb..a36b781e04d 100644 --- a/lisp/erc/erc-track.el +++ b/lisp/erc/erc-track.el @@ -785,6 +785,9 @@ erc-track-select-mode-line-face choice)) choice)))) +(defvar erc-track--skipped-msgs '(datestamp) + "Values of `erc-msg' text prop to ignore.") + (defun erc-track-modified-channels () "Hook function for `erc-insert-post-hook'. Check if the current buffer should be added to the mode line as a @@ -798,10 +801,13 @@ erc-track-modified-channels ;; FIXME either use `erc--server-buffer-p' or ;; explain why that's unwise. (erc-server-or-unjoined-channel-buffer-p))) - (not (erc-message-type-member - (or (erc-find-parsed-property) - (point-min)) - erc-track-exclude-types))) + (not (let ((parsed (erc-find-parsed-property))) + (or (erc-message-type-member (or parsed (point-min)) + erc-track-exclude-types) + ;; Skip certain non-server-sent messages. + (and (not parsed) + (erc--check-msg-prop 'erc-msg + erc-track--skipped-msgs)))))) ;; If the active buffer is not visible (not shown in a ;; window), and not to be excluded, determine the kinds of ;; faces used in the current message, and unless the user diff --git a/test/lisp/erc/erc-scenarios-stamp.el b/test/lisp/erc/erc-scenarios-stamp.el index d6b5d868ce5..c420e62fe14 100644 --- a/test/lisp/erc/erc-scenarios-stamp.el +++ b/test/lisp/erc/erc-scenarios-stamp.el @@ -50,7 +50,6 @@ erc-scenarios-stamp--left/display-margin-mode (erc-stamp--current-time 704591940) (erc-stamp--tz t) (erc-server-flood-penalty 0.1) - (erc-timestamp-only-if-changed-flag nil) (erc-insert-timestamp-function #'erc-insert-timestamp-left) (erc-modules (cons 'fill-wrap erc-modules)) (erc-timestamp-only-if-changed-flag nil) @@ -87,4 +86,31 @@ erc-scenarios-stamp--left/display-margin-mode (should (looking-back "CEIMRUabefhiklmnoqstuv\n")) (should (looking-at (rx "["))))))))) +(ert-deftest erc-scenarios-stamp--legacy-date-stamps () + (with-suppressed-warnings ((obsolete erc-stamp-prepend-date-stamps-p)) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/reconnect") + (erc-stamp-prepend-date-stamps-p t) + (dumb-server (erc-d-run "localhost" t 'unexpected-disconnect)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (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") + (funcall expect 5 "opening connection") + (goto-char (1- (match-beginning 0))) + (should (eq 'erc-timestamp (field-at-pos (point)))) + (should (eq 'unknown (erc--get-inserted-msg-prop 'erc-msg))) + ;; Force redraw of date stamp. + (setq erc-timestamp-last-inserted-left nil) + + (funcall expect 5 "This server is in debug mode") + (while (and (zerop (forward-line -1)) + (not (eq 'erc-timestamp (field-at-pos (point)))))) + (should (erc--get-inserted-msg-prop 'erc-cmd))))))) + ;;; erc-scenarios-stamp.el ends here -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Ensure-marker-for-max-pos-in-erc-traverse-insert.patch From 48dfdc118270fbd72ea93ca02363dcda5d7ef528 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sat, 21 Oct 2023 13:53:46 -0700 Subject: [PATCH 3/3] [5.6] Ensure marker for max pos in erc--traverse-inserted * lisp/erc/erc-stamp.el (erc-stamp--propertize-left-date-stamp): Run `erc-stamp--insert-date-hook' here. (erc-stamp--insert-date-stamp-as-phony-message): Don't include value of `erc-stamp--insert-date-hook' in let-bound `erc-insert-modify-hook' because it runs twice if buffer-local. Also call getter for `erc-stamp--current-time' and remove `erc-send-modify-hook' because that only runs via `erc-display-msg'. (erc-stamp--lr-date-on-pre-modify, erc-insert-timestamp-left-and-right): Use function form of `erc-stamp--current-time' for determining current time stamp. * lisp/erc/erc.el (erc--get-inserted-msg-bounds): Fix off-by-one. (erc--traverse-inserted): Create temporary marker when END is non-nil and not already a marker so that insertions and deletions do not affect the position at which the loop should end. (erc--delete-inserted-message): New function. * test/lisp/erc/erc-tests.el (erc--delete-inserted-message): New test. (erc--update-modules/unknown): Improve readability slightly. * test/lisp/erc/resources/erc-d/erc-d-t.el (erc-d-t-make-expecter): Indicate assertion flavor in error message. (Bug#60936) --- lisp/erc/erc-stamp.el | 17 +++-- lisp/erc/erc.el | 35 ++++++++-- test/lisp/erc/erc-tests.el | 84 ++++++++++++++++++++++-- test/lisp/erc/resources/erc-d/erc-d-t.el | 1 + 4 files changed, 118 insertions(+), 19 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index e0db472d289..6e35c5e2244 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -638,7 +638,8 @@ erc-stamp--date-format-end (defun erc-stamp--propertize-left-date-stamp () (add-text-properties (point-min) (1- (point-max)) '(field erc-timestamp erc-stamp-type date-left)) - (erc--hide-message 'timestamp)) + (erc--hide-message 'timestamp) + (run-hooks 'erc-stamp--insert-date-hook)) ;; A kludge to pass state from insert hook to nested insert hook. (defvar erc-stamp--current-datestamp-left nil) @@ -665,19 +666,17 @@ erc-stamp--insert-date-stamp-as-phony-message (cl-assert string) (let ((erc-stamp--skip t) (erc--msg-props (map-into `((erc-msg . datestamp) - (erc-ts . ,erc-stamp--current-time)) + (erc-ts . ,(erc-stamp--current-time))) 'hash-table)) - (erc-send-modify-hook `(,@erc-send-modify-hook - erc-stamp--propertize-left-date-stamp - ,@erc-stamp--insert-date-hook)) (erc-insert-modify-hook `(,@erc-insert-modify-hook - erc-stamp--propertize-left-date-stamp - ,@erc-stamp--insert-date-hook))) + erc-stamp--propertize-left-date-stamp)) + ;; Don't run hooks that aren't expecting a narrowed buffer. + (erc-insert-done-hook nil)) (erc-display-message nil nil (current-buffer) string) (setq erc-timestamp-last-inserted-left string))) (defun erc-stamp--lr-date-on-pre-modify (_) - (when-let ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (when-let ((ct (erc-stamp--current-time)) (rendered (erc-stamp--format-date-stamp ct)) ((not (string-equal rendered erc-timestamp-last-inserted-left))) (erc-stamp--current-datestamp-left rendered) @@ -723,7 +722,7 @@ erc-insert-timestamp-left-and-right (narrow-to-region erc--insert-marker end-marker) (set-marker end-marker nil) (set-marker erc--insert-marker nil))) - (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (let* ((ct (erc-stamp--current-time)) (ts-right (with-suppressed-warnings ((obsolete erc-timestamp-format-right)) (if erc-timestamp-format-right diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index f618fb17076..872ce5b4f49 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2980,7 +2980,7 @@ erc--get-inserted-msg-bounds (and-let* ((p (previous-single-property-change point 'erc-msg))) - (if (= p (1- point)) point (1- p))))))) + (if (= p (1- point)) p (1- p))))))) ,@(and (member only '(nil 'end)) '((e (1- (next-single-property-change (if at-start-p (1+ point) point) @@ -3005,8 +3005,12 @@ erc--with-inserted-msg ,@body))) (defun erc--traverse-inserted (beg end fn) - "Visit messages between BEG and END and run FN in narrowed buffer." - (setq end (min end (marker-position erc-insert-marker))) + "Visit messages between BEG and END and run FN in narrowed buffer. +If END is a marker, possibly update its position." + (unless (markerp end) + (setq end (set-marker (make-marker) (or end erc-insert-marker)))) + (unless (eq end erc-insert-marker) + (set-marker end (min erc-insert-marker end))) (save-excursion (goto-char beg) (let ((b (if (get-text-property (point) 'erc-msg) @@ -3018,7 +3022,9 @@ erc--traverse-inserted (save-restriction (narrow-to-region b e) (funcall fn)) - (setq b e))))) + (setq b e)))) + (unless (eq end erc-insert-marker) + (set-marker end nil))) (defvar erc--insert-marker nil "Internal override for `erc-insert-marker'.") @@ -3240,6 +3246,27 @@ erc--hide-message (cl-incf beg)) (erc--merge-prop (1- beg) (1- end) 'invisible value))))) +(defun erc--delete-inserted-message (beg-or-point &optional end) + "Remove message between BEG and END. +Expect BEG and END to match bounds as returned by the macro +`erc--get-inserted-msg-bounds'. Ensure all markers residing at +the start of the deleted message end up at the beginning of the +subsequent message." + (let ((beg beg-or-point)) + (save-restriction + (widen) + (unless end + (setq end (erc--get-inserted-msg-bounds nil beg-or-point) + beg (pop end))) + (with-silent-modifications + (if erc-legacy-invisible-bounds-p + (delete-region beg (1+ end)) + (save-excursion + (goto-char beg) + (insert-before-markers + (substring (delete-and-extract-region (1- (point)) (1+ end)) + -1)))))))) + (defvar erc--ranked-properties '(erc-msg erc-ts erc-cmd)) (defun erc--order-text-properties-from-hash (table) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 57bf5860ac4..1af087e7e31 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1432,6 +1432,80 @@ erc-process-input-line (should-not calls)))))) +(ert-deftest erc--delete-inserted-message () + (erc-mode) + (erc--initialize-markers (point) nil) + ;; Put unique invisible properties on the line endings. + (erc-display-message nil 'notice nil "one") + (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible 'a) + (let ((erc--msg-prop-overrides '((erc-msg . datestamp) (erc-ts . 0)))) + (erc-display-message nil nil nil + (propertize "\n[date]" 'field 'erc-timestamp))) + (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible 'b) + (erc-display-message nil 'notice nil "two") + + (ert-info ("Date stamp deleted cleanly") + (goto-char 11) + (should (looking-at (rx "\n[date]"))) + (should (eq 'datestamp (get-text-property (point) 'erc-msg))) + (should (eq (point) (field-beginning (1+ (point))))) + + (erc--delete-inserted-message (point)) + + ;; Preceding line ending clobbered, replaced by trailing. + (should (looking-back (rx "*** one\n"))) + (should (looking-at (rx "*** two"))) + (should (eq 'b (get-text-property (1- (point)) 'invisible)))) + + (ert-info ("Markers at pos-bol preserved") + (erc-display-message nil 'notice nil "three") + (should (looking-at (rx "*** two"))) + + (let ((m (point-marker)) + (n (point-marker)) + (p (point))) + (set-marker-insertion-type m t) + (goto-char (point-max)) + (erc--delete-inserted-message p) + (should (= (marker-position n) p)) + (should (= (marker-position m) p)) + (goto-char p) + (set-marker m nil) + (set-marker n nil) + (should (looking-back (rx "*** one\n"))) + (should (looking-at (rx "*** three"))))) + + (ert-info ("Compat") + (erc-display-message nil 'notice nil "four") + (should (looking-at (rx "*** three\n"))) + (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) + (let ((erc-legacy-invisible-bounds-p t)) + (erc--delete-inserted-message (point)))) + (should (looking-at (rx "*** four\n")))) + + (ert-info ("Deleting most recent message preserves markers") + (let ((m (point-marker)) + (n (point-marker)) + (p (point))) + (should (equal "*** four\n" (buffer-substring p erc-insert-marker))) + (set-marker-insertion-type m t) + (goto-char (point-max)) + (erc--delete-inserted-message p) + (should (= (marker-position m) p)) + (should (= (marker-position n) p)) + (goto-char p) + (should (looking-back (rx "*** one\n"))) + (should (looking-at erc-prompt)) + (erc--assert-input-bounds) + + ;; However, `m' is now forever "trapped" at `erc-insert-marker'. + (erc-display-message nil 'notice nil "two") + (should (= m erc-insert-marker)) + (goto-char n) + (should (looking-at (rx "*** two\n"))) + (set-marker m nil) + (set-marker n nil)))) + (ert-deftest erc--order-text-properties-from-hash () (let ((table (map-into '((a . 1) (erc-ts . 0) @@ -2617,8 +2691,8 @@ erc--update-modules/unknown (obarray (obarray-make)) (err (should-error (erc--update-modules erc-modules)))) (should (equal (cadr err) "`foo' is not a known ERC module")) - (should (equal (funcall get-calls) - `((req . ,(intern-soft "erc-foo"))))))) + (should (equal (mapcar #'prin1-to-string (funcall get-calls)) + '("(req . erc-foo)"))))) ;; Module's mode command exists but lacks an associated file. (ert-info ("Bad autoload flagged as suspect") @@ -2627,10 +2701,8 @@ erc--update-modules/unknown (obarray (obarray-make)) (erc-modules (list (intern "foo")))) - ;; Create a mode activation command. + ;; Create a mode-activation command and make mode-var global. (funcall mk-cmd "foo") - - ;; Make the mode var global. (funcall mk-global "foo") ;; No local modules to return. @@ -2639,7 +2711,7 @@ erc--update-modules/unknown '("foo"))) ;; ERC requires the library via prefixed module name. (should (equal (mapcar #'prin1-to-string (funcall get-calls)) - `("(req . erc-foo)" "(erc-foo-mode . 1)")))))))) + '("(req . erc-foo)" "(erc-foo-mode . 1)")))))))) ;; A local module (here, `lo2') lacks a mode toggle, so ERC tries to ;; load its defining library, first via the symbol property diff --git a/test/lisp/erc/resources/erc-d/erc-d-t.el b/test/lisp/erc/resources/erc-d/erc-d-t.el index cf869fb3c70..7126165fd91 100644 --- a/test/lisp/erc/resources/erc-d/erc-d-t.el +++ b/test/lisp/erc/resources/erc-d/erc-d-t.el @@ -157,6 +157,7 @@ erc-d-t-make-expecter (let (positions) (lambda (timeout text &optional reset-from) (let* ((pos (cdr (assq (current-buffer) positions))) + (erc-d-t--wait-message-prefix (and (< timeout 0) "Sustaining: ")) (cb (lambda () (unless pos (push (cons (current-buffer) (setq pos (make-marker))) -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 24 Oct 2023 02:20:33 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon Oct 23 22:20:33 2023 Received: from localhost ([127.0.0.1]:52632 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qv720-0007LW-OR for submit <at> debbugs.gnu.org; Mon, 23 Oct 2023 22:20:33 -0400 Received: from mail-108-mta84.mxroute.com ([136.175.108.84]:46121) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qv71v-0007LF-7A for 60936 <at> debbugs.gnu.org; Mon, 23 Oct 2023 22:20:31 -0400 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta84.mxroute.com (ZoneMTA) with ESMTPSA id 18b5f7b32df0008912.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Tue, 24 Oct 2023 02:19:51 +0000 X-Zone-Loop: 375c66d047f8ab3fc72281a4d569904d0888430d5251 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=n3/ibpefEleN8bI8gvK1Yr+xanhxQCjORSv1VkFKCzg=; b=SHr5QVYJtBPCKTKu9HuQGrOMrD 36+ZULSxGABmjdiCtK7m0XeQXly/TgmmNs1WaIoswwf/WjhSdIfMuvGvL+OcCWlQPVrvUTHkrC4EZ 8aE3+RuR0jN4Ra7v5t2vJnVhrKZrRTwvyQS5WcEq7+kOXDHEoYjQJBxEBHfZx9E/CbVDjH24OFCV/ dBsB5wJtg0DQLlTvxL1V7f+fcnO7Uw//LbKuxKezeUgkn3JUzWeeQvM63iX5x5oZEVDqnZqbxvJXI W0tfelCAX2tlB10Taz9bdSy5JDADmfuoQffIdKwpcXv6h4nrglAUUf7XQ0cN5wE9HTCzgj84UeIYj ePLH4qbw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <877cniaewr.fsf@HIDDEN> (J. P.'s message of "Thu, 19 Oct 2023 07:02:44 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> <877cniaewr.fsf@HIDDEN> Date: Mon, 23 Oct 2023 19:19:47 -0700 Message-ID: <877cncg3ss.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Some bugs have surfaced stemming from recent work on this initiative. Most come down to sloppiness on my part. The worst of the bunch involves `erc-insert-done-hook' being narrowed on date-stamp insertion, which defies a tacit agreement to the contrary. A related bug concerns members of the new internal date-stamp hook possibly running twice if the latter has a buffer-local value. I've also added a new helper for deleting inserted messages. It attempts to respect user markers and invisibility props. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Ensure-marker-for-max-pos-in-erc-traverse-insert.patch From b1b473f23db097106fb250686c06f4e8ef5d536f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sat, 21 Oct 2023 13:53:46 -0700 Subject: [PATCH] [5.6] Ensure marker for max pos in erc--traverse-inserted * lisp/erc/erc-stamp.el (erc-stamp--propertize-left-date-stamp): Run `erc-stamp--insert-date-hook' here. (erc-stamp--insert-date-stamp-as-phony-message): Don't include value of `erc-stamp--insert-date-hook' in let-bound `erc-insert-modify-hook' because it runs twice if buffer-local. Also call getter for `erc-stamp--current-time' and remove `erc-send-modify-hook' because that only runs via `erc-display-msg'. (erc-stamp--lr-date-on-pre-modify, erc-insert-timestamp-left-and-right): Use function form of `erc-stamp--current-time' for determining current time stamp. * lisp/erc/erc.el (erc--traverse-inserted): Create temporary marker when END is non-nil and not already a marker so that insertions and deletions do not affect the position at which the loop should end. (erc--delete-inserted-message): New function. * test/lisp/erc/erc-tests.el (erc--delete-inserted-message): New test. (erc--update-modules/unknown): Improve readability slightly. * test/lisp/erc/resources/erc-d/erc-d-t.el (erc-d-t-make-expecter): Indicate assertion flavor in error message. (Bug#60936) --- lisp/erc/erc-stamp.el | 17 ++++--- lisp/erc/erc.el | 33 +++++++++++-- test/lisp/erc/erc-tests.el | 61 +++++++++++++++++++++--- test/lisp/erc/resources/erc-d/erc-d-t.el | 1 + 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index b515513dcb7..56fa975c32d 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -638,7 +638,8 @@ erc-stamp--date-format-end (defun erc-stamp--propertize-left-date-stamp () (add-text-properties (point-min) (1- (point-max)) '(field erc-timestamp erc-stamp-type date-left)) - (erc--hide-message 'timestamp)) + (erc--hide-message 'timestamp) + (run-hooks 'erc-stamp--insert-date-hook)) ;; A kludge to pass state from insert hook to nested insert hook. (defvar erc-stamp--current-datestamp-left nil) @@ -665,19 +666,17 @@ erc-stamp--insert-date-stamp-as-phony-message (cl-assert string) (let ((erc-stamp--skip t) (erc--msg-props (map-into `((erc-msg . datestamp) - (erc-ts . ,erc-stamp--current-time)) + (erc-ts . ,(erc-stamp--current-time))) 'hash-table)) - (erc-send-modify-hook `(,@erc-send-modify-hook - erc-stamp--propertize-left-date-stamp - ,@erc-stamp--insert-date-hook)) (erc-insert-modify-hook `(,@erc-insert-modify-hook - erc-stamp--propertize-left-date-stamp - ,@erc-stamp--insert-date-hook))) + erc-stamp--propertize-left-date-stamp)) + ;; Don't run hooks that aren't expecting a narrowed buffer. + (erc-insert-done-hook nil)) (erc-display-message nil nil (current-buffer) string) (setq erc-timestamp-last-inserted-left string))) (defun erc-stamp--lr-date-on-pre-modify (_) - (when-let ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (when-let ((ct (erc-stamp--current-time)) (rendered (erc-stamp--format-date-stamp ct)) ((not (string-equal rendered erc-timestamp-last-inserted-left))) (erc-stamp--current-datestamp-left rendered) @@ -713,7 +712,7 @@ erc-insert-timestamp-left-and-right (narrow-to-region erc--insert-marker end-marker) (set-marker end-marker nil) (set-marker erc--insert-marker nil))) - (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (let* ((ct (erc-stamp--current-time)) (ts-right (with-suppressed-warnings ((obsolete erc-timestamp-format-right)) (if erc-timestamp-format-right diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 7d75ec49ccd..92f6f1fcb1f 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3006,8 +3006,12 @@ erc--with-inserted-msg ,@body))) (defun erc--traverse-inserted (beg end fn) - "Visit messages between BEG and END and run FN in narrowed buffer." - (setq end (min end (marker-position erc-insert-marker))) + "Visit messages between BEG and END and run FN in narrowed buffer. +If END is a marker, possibly update its position." + (unless (markerp end) + (setq end (set-marker (make-marker) (or end erc-insert-marker)))) + (unless (eq end erc-insert-marker) + (set-marker end (min erc-insert-marker end))) (save-excursion (goto-char beg) (let ((b (if (get-text-property (point) 'erc-msg) @@ -3019,7 +3023,9 @@ erc--traverse-inserted (save-restriction (narrow-to-region b e) (funcall fn)) - (setq b e))))) + (setq b e)))) + (unless (eq end erc-insert-marker) + (set-marker end nil))) (defvar erc--insert-marker nil "Internal override for `erc-insert-marker'.") @@ -3241,6 +3247,27 @@ erc--hide-message (cl-incf beg)) (erc--merge-prop (1- beg) (1- end) 'invisible value))))) +(defun erc--delete-inserted-message (beg-or-point &optional end) + "Remove message between BEG and END. +Expect BEG and END to match bounds as returned by the macro +`erc--get-inserted-msg-bounds'. Ensure all markers residing at +the start of the deleted message end up at the beginning of the +subsequent message." + (let ((beg beg-or-point)) + (save-restriction + (widen) + (unless end + (setq end (erc--get-inserted-msg-bounds nil beg-or-point) + beg (pop end))) + (with-silent-modifications + (if erc-legacy-invisible-bounds-p + (delete-region beg (1+ end)) + (save-excursion + (goto-char beg) + (insert-before-markers + (substring (delete-and-extract-region (1- (point)) (1+ end)) + -1)))))))) + (defvar erc--ranked-properties '(erc-msg erc-ts erc-cmd)) (defun erc--order-text-properties-from-hash (table) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 57bf5860ac4..6429fce8861 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1432,6 +1432,57 @@ erc-process-input-line (should-not calls)))))) +(ert-deftest erc--delete-inserted-message () + (erc-mode) + (erc--initialize-markers (point) nil) + ;; Put unique invisible properties on the line endings. + (erc-display-message nil 'notice nil "one") + (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible 'a) + (let ((erc--msg-prop-overrides '((erc-msg . datestamp) (erc-ts . 0)))) + (erc-display-message nil nil nil + (propertize "\n[date]" 'field 'erc-timestamp))) + (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible 'b) + (erc-display-message nil 'notice nil "two") + + (ert-info ("Date stamp deleted cleanly") + (goto-char 11) + (should (looking-at (rx "\n[date]"))) + (should (eq 'datestamp (get-text-property (point) 'erc-msg))) + (should (eq (point) (field-beginning (1+ (point))))) + + (erc--delete-inserted-message (point)) + + ;; Preceding line ending clobbered, replaced by trailing. + (should (looking-back (rx "*** one\n"))) + (should (looking-at (rx "*** two"))) + (should (eq 'b (get-text-property (1- (point)) 'invisible)))) + + (ert-info ("Markers at pos-bol preserved") + (erc-display-message nil 'notice nil "three") + (should (looking-at (rx "*** two"))) + + (let ((m (point-marker)) + (n (point-marker)) + (p (point))) + (set-marker-insertion-type m t) + (goto-char (point-max)) + (erc--delete-inserted-message p) + (should (= (marker-position n) p)) + (should (= (marker-position m) p)) + (goto-char p) + (set-marker m nil) + (set-marker n nil) + (should (looking-back (rx "*** one\n"))) + (should (looking-at (rx "*** three"))))) + + (ert-info ("Compat") + (erc-display-message nil 'notice nil "four") + (should (looking-at (rx "*** three\n"))) + (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) + (let ((erc-legacy-invisible-bounds-p t)) + (erc--delete-inserted-message (point)))) + (should (looking-at (rx "*** four\n"))))) + (ert-deftest erc--order-text-properties-from-hash () (let ((table (map-into '((a . 1) (erc-ts . 0) @@ -2617,8 +2668,8 @@ erc--update-modules/unknown (obarray (obarray-make)) (err (should-error (erc--update-modules erc-modules)))) (should (equal (cadr err) "`foo' is not a known ERC module")) - (should (equal (funcall get-calls) - `((req . ,(intern-soft "erc-foo"))))))) + (should (equal (mapcar #'prin1-to-string (funcall get-calls)) + '("(req . erc-foo)"))))) ;; Module's mode command exists but lacks an associated file. (ert-info ("Bad autoload flagged as suspect") @@ -2627,10 +2678,8 @@ erc--update-modules/unknown (obarray (obarray-make)) (erc-modules (list (intern "foo")))) - ;; Create a mode activation command. + ;; Create a mode-activation command and make mode-var global. (funcall mk-cmd "foo") - - ;; Make the mode var global. (funcall mk-global "foo") ;; No local modules to return. @@ -2639,7 +2688,7 @@ erc--update-modules/unknown '("foo"))) ;; ERC requires the library via prefixed module name. (should (equal (mapcar #'prin1-to-string (funcall get-calls)) - `("(req . erc-foo)" "(erc-foo-mode . 1)")))))))) + '("(req . erc-foo)" "(erc-foo-mode . 1)")))))))) ;; A local module (here, `lo2') lacks a mode toggle, so ERC tries to ;; load its defining library, first via the symbol property diff --git a/test/lisp/erc/resources/erc-d/erc-d-t.el b/test/lisp/erc/resources/erc-d/erc-d-t.el index cf869fb3c70..7126165fd91 100644 --- a/test/lisp/erc/resources/erc-d/erc-d-t.el +++ b/test/lisp/erc/resources/erc-d/erc-d-t.el @@ -157,6 +157,7 @@ erc-d-t-make-expecter (let (positions) (lambda (timeout text &optional reset-from) (let* ((pos (cdr (assq (current-buffer) positions))) + (erc-d-t--wait-message-prefix (and (< timeout 0) "Sustaining: ")) (cb (lambda () (unless pos (push (cons (current-buffer) (setq pos (make-marker))) -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 19 Oct 2023 14:03:45 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Thu Oct 19 10:03:45 2023 Received: from localhost ([127.0.0.1]:37355 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qtTcn-0005pY-AV for submit <at> debbugs.gnu.org; Thu, 19 Oct 2023 10:03:45 -0400 Received: from mail-108-mta177.mxroute.com ([136.175.108.177]:44439) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qtTcl-0005pN-2i for 60936 <at> debbugs.gnu.org; Thu, 19 Oct 2023 10:03:43 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta177.mxroute.com (ZoneMTA) with ESMTPSA id 18b483f552d0008912.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Thu, 19 Oct 2023 14:03:12 +0000 X-Zone-Loop: 081d9a5b60dab0763bfece5fc189e9716df0a31a811a 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=GhviTcumXUQFiFdSQ2paw08EyBHaNQ7xTGVS4P3YDiU=; b=ajxb0pdBmjyjU66rtr/O3HYaoe R9P+aJ4qDLG3zrZhBVpvmA9sSZ5NVQlLoBpfx3pHrkfEV7ThX5F7RFK0/1O+4a7KemAtMudi1Pw2o nOlJxpYla6P4UPwVj/uBr8kiiwuYmNK8b7CKH2BPzTkXfGPgm5OHzfP7fFM4a0r3reUY+VeA7Oe5y ebtpHRx3E4q8F/ZMbU3dJk7sfmBwJJeC8o1oTOKDdzyK5pHsQpzKJdeATBQ4fFGf8psNNOs22tO63 WhBt1VPiW8CZt61hsmih3qpU952mGbCHEubt7QLESGz6w9U9Zp0IPIich3w/IvUZXZ+6psulWafft x/IUc/bg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87o7gxe4wq.fsf@HIDDEN> (J. P.'s message of "Tue, 17 Oct 2023 06:48:21 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> <87o7gxe4wq.fsf@HIDDEN> Date: Thu, 19 Oct 2023 07:02:44 -0700 Message-ID: <877cniaewr.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v3 (erc-display-line redux). Properly offset renarrowed region after inserting initial date stamp in `erc-insert-timestamp-left-and-right'. Don't displace third-party markers when inserting left-sided stamps in `erc-stamp--display-margin-mode'. The first bug was introduced by c68dc7786fc * Manage some text props for ERC insertion-hook members and causes right-sided stamps to appear inside the prompt, among other unpleasant things (see third patch). Thanks to Corwin for spotting this. The other bug has been around a bit longer, likely since 63d8b2a59a4 * Make erc-fill-wrap work with left-sided stamps It has the potential to break packages that place markers in modification hooks (see last patch). --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v2-v3.diff From 15f2e73c4022edc1d5ba0ad9c2dea69bbabe3a97 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 19 Oct 2023 06:20:30 -0700 Subject: [PATCH 0/4] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (4): ; Mark erc-log test as :unstable [5.6] Restore missing metadata props in erc-display-line [5.6] Fix right stamps commingling with erc-prompt [5.6] Respect user markers in erc--insert-timestamp-left etc/ERC-NEWS | 23 +++ lisp/erc/erc-fill.el | 3 +- lisp/erc/erc-stamp.el | 20 ++- lisp/erc/erc.el | 146 +++++++++++------- test/lisp/erc/erc-fill-tests.el | 57 +++---- test/lisp/erc/erc-networks-tests.el | 2 +- .../lisp/erc/erc-scenarios-display-message.el | 64 ++++++++ test/lisp/erc/erc-scenarios-log.el | 2 +- test/lisp/erc/erc-scenarios-stamp.el | 90 +++++++++++ test/lisp/erc/erc-tests.el | 63 ++++++++ .../base/display-message/multibuf.eld | 45 ++++++ .../resources/base/renick/queries/solo.eld | 2 +- .../base/reuse-buffers/channel/barnet.eld | 2 +- .../base/reuse-buffers/channel/foonet.eld | 2 +- .../erc/resources/erc-scenarios-common.el | 4 +- .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 24 files changed, 437 insertions(+), 106 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-display-message.el create mode 100644 test/lisp/erc/erc-scenarios-stamp.el create mode 100644 test/lisp/erc/resources/base/display-message/multibuf.eld Interdiff: diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 57fd7f39e50..b515513dcb7 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -492,8 +492,11 @@ erc--conceal-prompt (put-text-property erc-insert-marker (1- erc-input-marker) 'display `((margin left-margin) ,prompt)))) -(cl-defmethod erc-insert-timestamp-left (string) +(defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." + (erc--insert-timestamp-left string)) + +(cl-defmethod erc--insert-timestamp-left (string) (goto-char (point-min)) (let* ((ignore-p (and erc-timestamp-only-if-changed-flag (string-equal string erc-timestamp-last-inserted))) @@ -504,13 +507,12 @@ erc-insert-timestamp-left (erc-put-text-property 0 len 'invisible erc-stamp--invisible-property s) (insert s))) -(cl-defmethod erc-insert-timestamp-left +(cl-defmethod erc--insert-timestamp-left (string &context (erc-stamp--display-margin-mode (eql t))) (unless (and erc-timestamp-only-if-changed-flag (string-equal string erc-timestamp-last-inserted)) (goto-char (point-min)) - (insert-before-markers-and-inherit - (setq erc-timestamp-last-inserted string)) + (insert-and-inherit (setq erc-timestamp-last-inserted string)) (dolist (p erc-stamp--inherited-props) (when-let ((v (get-text-property (point) p))) (put-text-property (point-min) (point) p v))) @@ -704,10 +706,12 @@ erc-insert-timestamp-left-and-right (unless erc-stamp--date-format-end (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify -95 t) (add-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify -95 t) - (let ((erc--insert-marker (point-min-marker))) + (let ((erc--insert-marker (point-min-marker)) + (end-marker (point-max-marker))) (set-marker-insertion-type erc--insert-marker t) (erc-stamp--lr-date-on-pre-modify nil) - (narrow-to-region erc--insert-marker (point-max)) + (narrow-to-region erc--insert-marker end-marker) + (set-marker end-marker nil) (set-marker erc--insert-marker nil))) (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) (ts-right (with-suppressed-warnings diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index f6c4c268017..80f5fd22ac6 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -203,36 +203,39 @@ erc-fill-wrap--monospace (unless (>= emacs-major-version 29) (ert-skip "Emacs version too low, missing `buffer-text-pixel-size'")) - (erc-fill-tests--wrap-populate - - (lambda () - (should (= erc-fill--wrap-value 27)) - (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-01-start") - - (ert-info ("Shift right by one (plus)") - ;; Args are all `erc-fill-wrap-nudge' +1 because interactive "p" - (ert-with-message-capture messages - ;; M-x erc-fill-wrap-nudge RET = - (ert-simulate-command '(erc-fill-wrap-nudge 2)) - (should (string-match (rx "for further adjustment") messages))) - (should (= erc-fill--wrap-value 29)) - (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-02-right")) - - (ert-info ("Shift left by five") - ;; "M-x erc-fill-wrap-nudge RET -----" - (ert-simulate-command '(erc-fill-wrap-nudge -4)) - (should (= erc-fill--wrap-value 25)) - (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-03-left")) + (let ((erc-prompt (lambda () "ABC>"))) + (erc-fill-tests--wrap-populate - (ert-info ("Reset") - ;; M-x erc-fill-wrap-nudge RET 0 - (ert-simulate-command '(erc-fill-wrap-nudge 0)) + (lambda () (should (= erc-fill--wrap-value 27)) (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-04-reset"))))) + (erc-fill-tests--compare "monospace-01-start") + + (ert-info ("Shift right by one (plus)") + ;; Args are all `erc-fill-wrap-nudge' +1 because interactive "p" + (ert-with-message-capture messages + ;; M-x erc-fill-wrap-nudge RET = + (ert-simulate-command '(erc-fill-wrap-nudge 2)) + (should (string-match (rx "for further adjustment") messages))) + (should (= erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") + (erc-fill-tests--compare "monospace-02-right")) + + (ert-info ("Shift left by five") + ;; "M-x erc-fill-wrap-nudge RET -----" + (ert-simulate-command '(erc-fill-wrap-nudge -4)) + (should (= erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") + (erc-fill-tests--compare "monospace-03-left")) + + (ert-info ("Reset") + ;; M-x erc-fill-wrap-nudge RET 0 + (ert-simulate-command '(erc-fill-wrap-nudge 0)) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") + (erc-fill-tests--compare "monospace-04-reset")) + + (erc--assert-input-bounds))))) (defun erc-fill-tests--simulate-refill () ;; Simulate `erc-fill-wrap-refill-buffer' synchronously and without diff --git a/test/lisp/erc/erc-scenarios-stamp.el b/test/lisp/erc/erc-scenarios-stamp.el new file mode 100644 index 00000000000..d6b5d868ce5 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-stamp.el @@ -0,0 +1,90 @@ +;;; erc-scenarios-stamp.el --- Misc `erc-stamp' 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) + +(defvar erc-scenarios-stamp--user-marker nil) + +(defun erc-scenarios-stamp--on-post-modify () + (when-let (((erc--check-msg-prop 'erc-cmd 4))) + (set-marker erc-scenarios-stamp--user-marker (point-max)) + (ert-info ("User marker correctly placed at `erc-insert-marker'") + (should (= ?\n (char-before erc-scenarios-stamp--user-marker))) + (should (= erc-scenarios-stamp--user-marker erc-insert-marker)) + (save-excursion + (goto-char erc-scenarios-stamp--user-marker) + ;; The raw message ends in " Iabefhkloqv". However, + ;; `erc-server-004' only prints up to the 5th parameter. + (should (looking-back "CEIMRUabefhiklmnoqstuv\n")))))) + +(ert-deftest erc-scenarios-stamp--left/display-margin-mode () + + (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-scenarios-stamp--user-marker (make-marker)) + (erc-stamp--current-time 704591940) + (erc-stamp--tz t) + (erc-server-flood-penalty 0.1) + (erc-timestamp-only-if-changed-flag nil) + (erc-insert-timestamp-function #'erc-insert-timestamp-left) + (erc-modules (cons 'fill-wrap erc-modules)) + (erc-timestamp-only-if-changed-flag nil) + (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") + + (add-hook 'erc-insert-post-hook #'erc-scenarios-stamp--on-post-modify + nil t) + (funcall expect 5 "This server is in debug 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 '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))) + 'erc-speaker) + "irc.foonet.org")) + (should (pcase (get-text-property (pos-bol) 'display) + (`((margin left-margin) ,s) + (eq 'timestamp (get-text-property 0 'invisible s)))))) + + ;; We set a third-party marker at the end of 004's message (on + ;; then "\n"), post-insertion. + (ert-info ("User markers untouched by subsequent message left stamp") + (save-excursion + (goto-char erc-scenarios-stamp--user-marker) + (should (looking-back "CEIMRUabefhiklmnoqstuv\n")) + (should (looking-at (rx "["))))))))) + +;;; erc-scenarios-stamp.el ends here -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Mark-erc-log-test-as-unstable.patch From 943d2abafe5f16c77f540b48d686d50e85fd52e7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 15 Oct 2023 13:43:12 -0700 Subject: [PATCH 1/4] ; Mark erc-log test as :unstable * test/lisp/erc/erc-scenarios-log.el (erc-scenarios-log--truncate): Mark :unstable for now. * test/lisp/erc/resources/base/renick/queries/solo.eld: Timeouts. * test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld: Timeouts. * test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld: Timeouts. * test/lisp/erc/resources/erc-scenarios-common.el: Timeouts. --- test/lisp/erc/erc-scenarios-log.el | 2 +- test/lisp/erc/resources/base/renick/queries/solo.eld | 2 +- test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld | 2 +- test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld | 2 +- test/lisp/erc/resources/erc-scenarios-common.el | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenarios-log.el index f7e7d61c92e..cd28ea54b2e 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -149,7 +149,7 @@ erc-scenarios-log--clear-stamp (when noninteractive (delete-directory tempdir :recursive)))) (ert-deftest erc-scenarios-log--truncate () - :tags '(:expensive-test) + :tags '(:expensive-test :unstable) (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "base/assoc/bouncer-history") (dumb-server (erc-d-run "localhost" t 'foonet)) diff --git a/test/lisp/erc/resources/base/renick/queries/solo.eld b/test/lisp/erc/resources/base/renick/queries/solo.eld index 12fa7d264e9..fa4c075adac 100644 --- a/test/lisp/erc/resources/base/renick/queries/solo.eld +++ b/test/lisp/erc/resources/base/renick/queries/solo.eld @@ -30,7 +30,7 @@ (0 ":irc.foonet.org NOTICE tester :[09:56:57] 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.") (0 ":irc.foonet.org 305 tester :You are no longer marked as being away")) -((mode 1 "MODE #foo") +((mode 10 "MODE #foo") (0 ":irc.foonet.org 324 tester #foo +nt") (0 ":irc.foonet.org 329 tester #foo 1622454985") (0.1 ":alice!~u@HIDDEN PRIVMSG #foo :bob: Farewell, pretty lady: you must hold the credit of your father.") diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld index efc2506fd6f..d106a45cf66 100644 --- a/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld +++ b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld @@ -56,7 +56,7 @@ (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":joe!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620205534") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: Chi non te vede, non te pretia.") diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld index a11cfac2e73..603afa2fc3e 100644 --- a/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld +++ b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld @@ -52,7 +52,7 @@ (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620205534") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: Thou desirest me to stop in my tale against the hair.") diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el index 5354b300b47..9e134e6932f 100644 --- a/test/lisp/erc/resources/erc-scenarios-common.el +++ b/test/lisp/erc/resources/erc-scenarios-common.el @@ -574,7 +574,7 @@ erc-scenarios-common--upstream-reconnect :password "changeme" :full-name "tester") (erc-scenarios-common-assert-initial-buf-name nil port) - (erc-d-t-wait-for 3 (eq (erc-network) 'foonet)) + (erc-d-t-wait-for 6 (eq (erc-network) 'foonet)) (erc-d-t-wait-for 3 (string= (buffer-name) "foonet")) (funcall expect 5 "foonet"))) @@ -713,7 +713,7 @@ erc-scenarios-common--join-network-id (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-foo)) (funcall expect 3 "<bob>") (erc-d-t-absent-for 0.1 "<joe>") - (funcall expect 10 "not given me"))) + (funcall expect 20 "not given me"))) (ert-info ("All #chan@barnet output received") (with-current-buffer chan-buf-bar -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Restore-missing-metadata-props-in-erc-display-li.patch Content-Transfer-Encoding: quoted-printable From 3996279b48589764c07329c63a39aa573546b7b5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 15 Oct 2023 17:22:22 -0700 Subject: [PATCH 2/4] [5.6] Restore missing metadata props in erc-display-li= ne * etc/ERC-NEWS: Designate `erc-display-message' as the favored means of inserting messages. * lisp/erc/erc-fill.el (erc-fill-wrap): Skip any `unknown' `erc-msg'. * lisp/erc/erc-stamp.el (erc-stamp--current-time): Use an existing `erc-ts' text property, when present, for the current message time. * lisp/erc/erc.el (erc-display-line-1): Update doc string. (erc-display-line): Convert to a thin wrapper around `erc-display-message', and move its existing body to a new function, `erc--route-insertion'. (erc--route-insertion): Adopt former body of `erc-display-line'. Copy `erc--msg-props' hash table when inserting a message in multiple buffers. At present, only `erc-server-QUIT' uses this facility. Also, improve readability with at most one recursive call for the fall-through case. (erc--compose-text-properties, erc--merge-text-properties-p): Rename former to latter to avoid confusion with `composition' property. (erc-display-message): Update doc string. Attempt to adapt a non-nil TYPE parameter for use as the value of the `erc-msg' text property before resorting to a value of `unknown'. But only do this when PARSED is nil, and MSG is a string. Call `erc--route-insertion' instead of `erc-display-line'. Use new name for `erc--compose-text-properties'. (erc-put-text-property): Update name of variable `erc--compose-text-properties'. * test/lisp/erc/erc-networks-tests.el (erc-networks--set-name): Mock `erc--route-insertion' instead of `erc-display-line'. * test/lisp/erc/erc-scenarios-display-message.el: New file. * test/lisp/erc/erc-tests.el (erc--route-insertion): New test. * test/lisp/erc/resources/base/display-message/multibuf.eld: New test data. * test/lisp/erc/resources/fill/snapshots/merge-01-start.eld: Update. * test/lisp/erc/resources/fill/snapshots/merge-02-right.eld: Update. * test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld: Update. * test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld: Update. * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: Update. (Bug#60936) --- etc/ERC-NEWS | 23 +++ lisp/erc/erc-fill.el | 3 +- lisp/erc/erc-stamp.el | 4 +- lisp/erc/erc.el | 146 +++++++++++------- test/lisp/erc/erc-networks-tests.el | 2 +- .../lisp/erc/erc-scenarios-display-message.el | 64 ++++++++ test/lisp/erc/erc-tests.el | 63 ++++++++ .../base/display-message/multibuf.eld | 45 ++++++ .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 17 files changed, 301 insertions(+), 67 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-display-message.el create mode 100644 test/lisp/erc/resources/base/display-message/multibuf.e= ld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 2e56539f210..282a538e04d 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -288,6 +288,29 @@ ERC also provisionally reserves the same depth interva= l for continue to modify non-ERC hooks locally whenever possible, especially in new code. =20 +*** Message insertion function 'erc-display-message' heavily favored. +Displaying "local" messages, like help text and interactive-command +feedback, in ERC buffers has never been straightforward. As such, +ancient patterns, like the pairing of preformatted "notice" text with +ERC's oldest insertion function, 'erc-display-line', still appear +quite frequently in the wild despite having been largely phased out of +ERC's own code base in 2002. That this specific example has endured +makes some sense because it's probably seen as less cumbersome than +fiddling with the more powerful and complicated 'erc-display-message'. + +The latest twist in this saga comes with this release, in which a +healthy dose of \"pre-insertion business\" has been invited to take up +residence in 'erc-display-message'. While this would seem to put +antiquated patterns, like the above mentioned 'erc-make-notice' combo, +at risk of having messages ignored or subject to degraded treatment by +built-in modules, a prophylactic measure has been erected to recast +'erc-display-line' as a thin wrapper around 'erc-display-message'. +And though nothing of the sort has been done for the lower-level +'erc-display-line-1' (now an obsolete alias for 'erc-insert-line'), +some fallback code has been put in place to ensure baseline +functionality. As always, if you find these developments disturbing, +please say so on the tracker. + *** ERC now manages timestamp-related properties a bit differently. For starters, the 'cursor-sensor-functions' text property is absent by default unless the option 'erc-echo-timestamps' is already enabled on diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 0048956e075..e28c3563ebf 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -539,7 +539,8 @@ erc-fill-wrap (goto-char (point-min)) (let ((len (or (and erc-fill--wrap-length-function (funcall erc-fill--wrap-length-function)) - (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg))) + (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg)) + ((not (eq msg-prop 'unknown)))) (when-let ((e (erc--get-speaker-bounds)) (b (pop e)) ((or erc-fill--wrap-action-dedent-p diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 394643c03cb..57fd7f39e50 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -219,7 +219,9 @@ erc-stamp--current-time (erc-compat--current-lisp-time)) =20 (cl-defmethod erc-stamp--current-time :around () - (or erc-stamp--current-time (cl-call-next-method))) + (or erc-stamp--current-time + (and erc--msg-props (gethash 'erc-ts erc--msg-props)) + (cl-call-next-method))) =20 (defvar erc-stamp--skip nil "Non-nil means inhibit `erc-add-timestamp' completely.") diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 5bf6496e926..0513a5c785c 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3003,13 +3003,26 @@ erc--traverse-inserted (defvar erc--insert-marker nil "Internal override for `erc-insert-marker'.") =20 -(defun erc-display-line-1 (string buffer) - "Display STRING in `erc-mode' BUFFER. -Auxiliary function used in `erc-display-line'. The line gets filtered to -interpret the control characters. Then, `erc-insert-pre-hook' gets called. -If `erc-insert-this' is still t, STRING gets inserted into the buffer. -Afterwards, `erc-insert-modify' and `erc-insert-post-hook' get called. -If STRING is nil, the function does nothing." +(define-obsolete-function-alias 'erc-display-line-1 'erc-insert-line "30.1= ") +(defun erc-insert-line (string buffer) + "Insert STRING in an `erc-mode' BUFFER. +When STRING is nil, do nothing. Otherwise, start off by running +`erc-insert-pre-hook' in BUFFER with `erc-insert-this' bound to +t. If the latter remains non-nil afterward, insert STRING into +BUFFER, ensuring a trailing newline. After that, narrow BUFFER +around STRING, along with its final line ending, and run +`erc-insert-modify' and `erc-insert-post-hook', respectively. In +all cases, run `erc-insert-done-hook' unnarrowed before exiting, +and update positions in `buffer-undo-list'. + +In general, expect to be called from a higher-level insertion +function, like `erc-display-message', especially when modules +should consider STRING as a candidate for formatting with +enhancements like indentation, fontification, timestamping, etc. +Otherwise, when called directly, allow built-in modules to ignore +STRING, which may make it appear incongruous in situ (unless +preformatted or anticipated by third-party members of the various +modification hooks)." (when string (with-current-buffer (or buffer (process-buffer erc-server-process)) (let ((insert-position (marker-position erc-insert-marker))) @@ -3021,7 +3034,7 @@ erc-display-line-1 (when (erc-string-invisible-p string) (erc-put-text-properties 0 (length string) '(invisible intangible) string))) - (erc-log (concat "erc-display-line: " string + (erc-log (concat "erc-display-message: " string (format "(%S)" string) " in buffer " (format "%s" buffer))) (setq erc-insert-this t) @@ -3091,39 +3104,45 @@ erc-is-valid-nick-p "Check if NICK is a valid IRC nickname." (string-match (concat "\\`" erc-valid-nick-regexp "\\'") nick)) =20 -(defun erc-display-line (string &optional buffer) - "Display STRING in the ERC BUFFER. -All screen output must be done through this function. If BUFFER is nil -or omitted, the default ERC buffer for the `erc-session-server' is used. -The BUFFER can be an actual buffer, a list of buffers, `all' or `active'. -If BUFFER =3D `all', the string is displayed in all the ERC buffers for the -current session. `active' means the current active buffer -\(`erc-active-buffer'). If the buffer can't be resolved, the current -buffer is used. `erc-display-line-1' is used to display STRING. - -If STRING is nil, the function does nothing." - (let (new-bufs) +(defun erc--route-insertion (string buffer) + "Insert STRING in BUFFER. +See `erc-display-message' for acceptable BUFFER types." + (let (seen msg-props) (dolist (buf (cond ((bufferp buffer) (list buffer)) - ((listp buffer) buffer) + ((consp buffer) + (setq msg-props erc--msg-props) + buffer) ((processp buffer) (list (process-buffer buffer))) ((eq 'all buffer) ;; Hmm, or all of the same session server? (erc-buffer-list nil erc-server-process)) - ((and (eq 'active buffer) (erc-active-buffer)) - (list (erc-active-buffer))) + ((and-let* (((eq 'active buffer)) + (b (erc-active-buffer))) + (list b))) ((erc-server-buffer-live-p) (list (process-buffer erc-server-process))) (t (list (current-buffer))))) (when (buffer-live-p buf) - (erc-display-line-1 string buf) - (push buf new-bufs))) - (when (null new-bufs) - (erc-display-line-1 string (if (erc-server-buffer-live-p) - (process-buffer erc-server-process) - (current-buffer)))))) - -(defvar erc--compose-text-properties nil + (when msg-props + (setq erc--msg-props (copy-hash-table msg-props))) + (erc-insert-line string buf) + (setq seen t))) + (unless (or seen (null buffer)) + (erc--route-insertion string nil)))) + +(defun erc-display-line (string &optional buffer) + "Insert STRING in BUFFER as a plain \"local\" message. +Take pains to ensure modification hooks see messages created by +the old pattern (erc-display-line (erc-make-notice) my-buffer) as +being equivalent to a `erc-display-message' TYPE of `notice'." + (let ((erc--msg-prop-overrides erc--msg-prop-overrides)) + (when (eq 'erc-notice-face (get-text-property 0 'font-lock-face string= )) + (unless (assq 'erc-msg erc--msg-prop-overrides) + (push '(erc-msg . notice) erc--msg-prop-overrides))) + (erc-display-message nil nil buffer string))) + +(defvar erc--merge-text-properties-p nil "Non-nil when `erc-put-text-property' defers to `erc--merge-prop'.") =20 ;; To save space, we could maintain a map of all readable property @@ -3432,14 +3451,24 @@ erc-display-message Insert MSG or text derived from MSG into an ERC buffer, possibly after applying formatting by way of either a `format-spec' known to a message-catalog entry or a TYPE known to a specialized -string handler. Additionally, derive internal metadata, faces, -and other text properties from the various overloaded parameters, -such as PARSED, when it's an `erc-response' object, and MSG, when -it's a key (symbol) for a \"message catalog\" entry. Expect -ARGS, when applicable, to be `format-spec' args known to such an -entry, and TYPE, when non-nil, to be a symbol handled by +string handler. Additionally, derive metadata, faces, and other +text properties from the various overloaded parameters, such as +PARSED, when it's an `erc-response' object, and MSG, when it's a +key (symbol) for a \"message catalog\" entry. Expect ARGS, when +applicable, to be `format-spec' args known to such an entry, and +TYPE, when non-nil, to be a symbol handled by `erc-display-message-highlight' (necessarily accompanied by a -string MSG). +string MSG). Expect BUFFER to be among the sort accepted by the +function `erc-display-line'. + +Expect BUFFER to be a live `erc-mode' buffer, a list of such +buffers, or the symbols `all' or `active'. If `all', insert +STRING in all buffers for the current session. If `active', +defer to the function `erc-active-buffer', which may return the +session's server buffer if the previously active buffer has been +killed. If BUFFER is nil or a network process, pretend it's set +to the appropriate server buffer. Otherwise, use the current +buffer. =20 When TYPE is a list of symbols, call handlers from left to right without influencing how they behave when encountering existing @@ -3451,24 +3480,31 @@ erc-display-message being (erc-error-face erc-notice-face) throughout MSG when `erc-notice-highlight-type' is left at its default, `all'. =20 -As of ERC 5.6, assume user code will use this function instead of -`erc-display-line' when it's important that insert hooks treat -MSG in a manner befitting messages received from a server. That -is, expect to process most nontrivial informational messages, for -which PARSED is typically nil, when the caller desires -buttonizing and other effects." +As of ERC 5.6, assume third-party code will use this function +instead of lower-level ones, like `erc-insert-line', when needing +ERC to process arbitrary informative messages as if they'd been +sent from a server. That is, guarantee \"local\" messages, for +which PARSED is typically nil, will be subject to buttonizing, +filling, and other effects." (let ((string (if (symbolp msg) (apply #'erc-format-message msg args) msg)) (erc--msg-props (or erc--msg-props - (let* ((table (make-hash-table :size 5)) - (cmd (and parsed (erc--get-eq-comparable-cmd - (erc-response.command parsed)))) - (m (cond ((and msg (symbolp msg)) msg) - ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) - (t 'unknown)))) - (puthash 'erc-msg m table) + (let ((table (make-hash-table :size 5)) + (cmd (and parsed (erc--get-eq-comparable-cmd + (erc-response.command parsed))))) + (puthash 'erc-msg + (cond ((and msg (symbolp msg)) msg) + ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) + (type (pcase type + ((pred symbolp) type) + ((pred listp) + (intern (mapconcat #'prin1-to-string + type "-"))) + (_ 'unknown))) + (t 'unknown)) + table) (when cmd (puthash 'erc-cmd cmd table)) (and erc--msg-prop-overrides @@ -3481,7 +3517,7 @@ erc-display-message ((null type) string) ((listp type) - (let ((erc--compose-text-properties + (let ((erc--merge-text-properties-p (and (eq (car type) t) (setq type (cdr type))))) (dolist (type type) (setq string (erc-display-message-highlight type string)))) @@ -3490,13 +3526,13 @@ erc-display-message (erc-display-message-highlight type string)))) =20 (if (not (erc-response-p parsed)) - (erc-display-line string buffer) + (erc--route-insertion string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parse= d) string)) - (erc-display-line string buffer))))) + (erc--route-insertion string buffer))))) =20 (defun erc-message-type-member (position list) "Return non-nil if the erc-parsed text-property at POSITION is in LIST. @@ -6481,7 +6517,7 @@ erc-put-text-property =20 You can redefine or `defadvice' this function in order to add EmacsSpeak support." - (if erc--compose-text-properties + (if erc--merge-text-properties-p (erc--merge-prop start end property value object) (put-text-property start end property value object))) =20 diff --git a/test/lisp/erc/erc-networks-tests.el b/test/lisp/erc/erc-networ= ks-tests.el index e95d99c128f..45ef0d10a6e 100644 --- a/test/lisp/erc/erc-networks-tests.el +++ b/test/lisp/erc/erc-networks-tests.el @@ -1206,7 +1206,7 @@ erc-networks--set-name calls) (erc-mode) =20 - (cl-letf (((symbol-function 'erc-display-line) + (cl-letf (((symbol-function 'erc--route-insertion) (lambda (&rest r) (push r calls)))) =20 (ert-info ("Signals when `erc-server-announced-name' unset") diff --git a/test/lisp/erc/erc-scenarios-display-message.el b/test/lisp/erc= /erc-scenarios-display-message.el new file mode 100644 index 00000000000..51bdf305ad5 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-display-message.el @@ -0,0 +1,64 @@ +;;; erc-scenarios-display-message.el --- erc-display-message -*- lexical-b= inding: 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))) + +(ert-deftest erc-scenarios-display-message--multibuf () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/display-message") + (dumb-server (erc-d-run "localhost" t 'multibuf)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (erc-modules (cons 'fill-wrap erc-modules)) + (erc-autojoin-channels-alist '((foonet "#chan"))) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :full-name "tester") + (funcall expect 10 "debug mode"))) + + (ert-info ("User dummy is a member of #chan") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (funcall expect 10 "dummy"))) + + (ert-info ("Dummy's QUIT notice in query contains metadata props") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "dummy")) + (funcall expect 10 "<dummy> hi") + (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)= )))) + + (ert-info ("Dummy's QUIT notice in #chan contains metadata props") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)= )))) + + (erc-cmd-QUIT ""))) + +(eval-when-compile (require 'erc-join)) + +;;; erc-scenarios-display-message.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 4f4662f5075..02dfc55b6d5 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1938,6 +1938,69 @@ erc-format-privmessage 2 5 (erc-speaker "Bob" font-lock-face erc-nick-default-face) 5 12 (font-lock-face erc-default-face)))))) =20 +(ert-deftest erc--route-insertion () + (erc-tests--send-prep) + (erc-tests--set-fake-server-process "sleep" "1") + (setq erc-networks--id (erc-networks--id-create 'foonet)) + + (let* ((erc-modules) ; for `erc--open-target' + (server-buffer (current-buffer)) + (spam-buffer (save-excursion (erc--open-target "#spam"))) + (chan-buffer (save-excursion (erc--open-target "#chan"))) + calls) + (cl-letf (((symbol-function 'erc-insert-line) + (lambda (&rest r) (push (cons 'line-1 r) calls)))) + + (with-current-buffer chan-buffer + + (ert-info ("Null `buffer' routes to live server-buffer") + (erc--route-insertion "null" nil) + (should (equal (pop calls) `(line-1 "null" ,server-buffer))) + (should-not calls)) + + (ert-info ("Cons `buffer' routes to live members") + ;; Copies a let-bound `erc--msg-props' before mutating. + (let* ((table (map-into '(erc-msg msg) 'hash-table)) + (erc--msg-props table)) + (erc--route-insertion "cons" (list server-buffer spam-buffer)) + (should-not (eq table erc--msg-props))) + (should (equal (pop calls) `(line-1 "cons" ,spam-buffer))) + (should (equal (pop calls) `(line-1 "cons" ,server-buffer))) + (should-not calls)) + + (ert-info ("Variant `all' inserts in all session buffers") + (erc--route-insertion "all" 'all) + (should (equal (pop calls) `(line-1 "all" ,chan-buffer))) + (should (equal (pop calls) `(line-1 "all" ,spam-buffer))) + (should (equal (pop calls) `(line-1 "all" ,server-buffer))) + (should-not calls)) + + (ert-info ("Variant `active' routes to active buffer if alive") + (should (eq chan-buffer (erc-with-server-buffer erc-active-buffe= r))) + (erc-set-active-buffer spam-buffer) + (erc--route-insertion "act" 'active) + (should (equal (pop calls) `(line-1 "act" ,spam-buffer))) + (should (eq (erc-active-buffer) spam-buffer)) + (should-not calls)) + + (ert-info ("Variant `active' falls back to current buffer") + (should (eq spam-buffer (erc-active-buffer))) + (kill-buffer "#spam") + (erc--route-insertion "nact" 'active) + (should (equal (pop calls) `(line-1 "nact" ,server-buffer))) + (should (eq (erc-with-server-buffer erc-active-buffer) + server-buffer)) + (should-not calls)) + + (ert-info ("Dead single buffer defaults to live server-buffer") + (should-not (get-buffer "#spam")) + (erc--route-insertion "dead" 'spam-buffer) + (should (equal (pop calls) `(line-1 "dead" ,server-buffer))) + (should-not calls)))) + + (should-not (buffer-live-p spam-buffer)) + (kill-buffer chan-buffer))) + (defvar erc-tests--ipv6-examples '("1:2:3:4:5:6:7:8" "::ffff:10.0.0.1" "::ffff:1.2.3.4" "::ffff:0.0.0.0" diff --git a/test/lisp/erc/resources/base/display-message/multibuf.eld b/te= st/lisp/erc/resources/base/display-message/multibuf.eld new file mode 100644 index 00000000000..e49a654cd06 --- /dev/null +++ b/test/lisp/erc/resources/base/display-message/multibuf.eld @@ -0,0 +1,45 @@ +;; -*- mode: lisp-data; -*- +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") + (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network test= er") + (0.01 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running v= ersion ergo-v2.11.1") + (0.01 ":irc.foonet.org 003 tester :This server was created Sat, 14 Oct 20= 23 16:08:20 UTC") + (0.02 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.11.1 BERTZios CE= IMRUabefhiklmnoqstuv Iabefhkloqv") + (0.00 ":irc.foonet.org 005 tester AWAYLEN=3D390 BOT=3DB CASEMAPPING=3Dasc= ii CHANLIMIT=3D#:100 CHANMODES=3DIbe,k,fl,CEMRUimnstu CHANNELLEN=3D64 CHANT= YPES=3D# CHATHISTORY=3D1000 ELIST=3DU EXCEPTS EXTBAN=3D,m FORWARD=3Df INVEX= :are supported by this server") + (0.01 ":irc.foonet.org 005 tester KICKLEN=3D390 MAXLIST=3DbeI:60 MAXTARGE= TS=3D4 MODES MONITOR=3D100 NETWORK=3Dfoonet NICKLEN=3D32 PREFIX=3D(qaohv)~&= @%+ STATUSMSG=3D~&@%+ TARGMAX=3DNAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PR= IVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=3D390 UTF8ONLY WHOX :are sup= ported by this server") + (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=3D1000 :are supported= by this server") + (0.00 ":irc.foonet.org 251 tester :There are 0 users and 5 invisible on 1= server(s)") + (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online") + (0.00 ":irc.foonet.org 253 tester 0 :unregistered connections") + (0.00 ":irc.foonet.org 254 tester 2 :channels formed") + (0.00 ":irc.foonet.org 255 tester :I have 5 clients and 0 servers") + (0.00 ":irc.foonet.org 265 tester 5 5 :Current local users 5, max 5") + (0.02 ":irc.foonet.org 266 tester 5 5 :Current global users 5, max 5") + (0.01 ":irc.foonet.org 422 tester :MOTD File is missing") + (0.00 ":irc.foonet.org 221 tester +i") + (0.01 ":irc.foonet.org NOTICE tester :This server is in debug mode and is= logging all user I/O. If you do not wish for everything you send to be rea= dable by the server owner(s), please disconnect.")) + +((mode 10 "MODE tester +i") + (0.00 ":irc.foonet.org 221 tester +i")) + +((join 10 "JOIN #chan") + (0.03 ":tester!~u@HIDDEN JOIN #chan") + (0.03 ":irc.foonet.org 353 tester =3D #chan :@fsbot bob alice dummy teste= r") + (0.01 ":irc.foonet.org 366 tester #chan :End of NAMES list") + (0.00 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!") + (0.01 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) + +((mode 10 "MODE #chan") + (0.01 ":bob!~u@HIDDEN PRIVMSG #chan :alice: Persuade this rude= wretch willingly to die.") + (0.01 ":irc.foonet.org 324 tester #chan +Cnt") + (0.01 ":irc.foonet.org 329 tester #chan 1697299707") + (0.03 ":alice!~u@HIDDEN PRIVMSG #chan :bob: It might be yours = or hers, for aught I know.") + (0.07 ":bob!~u@HIDDEN PRIVMSG #chan :Would all themselves laug= h mortal.") + (0.04 ":dummy!~u@HIDDEN PRIVMSG tester :hi") + (0.06 ":bob!~u@HIDDEN PRIVMSG #chan :alice: It hath pleased th= e devil drunkenness to give place to the devil wrath; one unperfectness sho= ws me another, to make me frankly despise myself.") + (0.05 ":dummy!~u@HIDDEN QUIT :Quit: \2ERC\2 5.6-git (IRC clien= t for GNU Emacs 30.0.50)") + (0.08 ":alice!~u@HIDDEN PRIVMSG #chan :You speak of him when h= e was less furnished than now he is with that which makes him both without = and within.")) + +((quit 10 "QUIT :\2ERC\2") + (0.04 ":tester!~u@HIDDEN QUIT :Quit: \2ERC\2 5.x (IRC client f= or GNU Emacs)") + (0.02 "ERROR :Quit: \2ERC\2 5.x (IRC client for GNU Emacs)")) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-01-start.eld index 238d8cc73c2..8a6f2289f5d 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 3= 53 (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 1680332400 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-02-right.eld index d1ce9198e69..3eb4be4919b 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (6)))) 350 3= 53 (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 1680332400 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index d70184724ba..82c6d52cf7c 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-pref= ix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#)= 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6= =3D(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (= erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(spac= e :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wr= ap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 20= 2 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefi= x #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-p= refix #4=3D(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# lin= e-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg da= testamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp= wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(spac= e :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wr= ap-prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1#= line-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 = 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-pre= fix #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1= # line-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-= prefix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9= =3D"") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-= prefix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefi= x #8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTI= ON wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wr= ap-prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) = 500 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680= 332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 2= 7 0)) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 5= 11 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix = #1# line-prefix #11#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefi= x #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) = 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6=3D= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc= -msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(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 3= 15 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #= 3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-pref= ix #4=3D(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-p= refix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg dates= tamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp wr= ap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg msg = erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(space := width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wrap-= prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1# li= ne-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 475= (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-prefix= #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1# l= ine-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-pre= fix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd PRI= VMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9=3D= "") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-pre= fix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefix #= 8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION = wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wrap-= prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) 500= 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680332= 400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0= )) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 511 = 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix #1#= line-prefix #11#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index def97738ce6..84a1e34670c 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index be3e2b33cfd..83394f2f639 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index 098257d0b49..1605628b29f 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index def97738ce6..84a1e34670c 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/t= est/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 360b3dafafd..7a7e01de49d 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-= prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix = #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (lin= e-spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1= # line-prefix #3=3D(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 (wr= ap-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(space :width= (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefi= x #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (w= rap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg= msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :widt= h (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displ= ay #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap= -prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg un= known erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) = 468 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg unknown erc-ts 0= wrap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-= prefix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg= erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (-= 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #= 1# line-prefix #9#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-p= refix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #= 2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((= margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (line= -spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1#= line-prefix #3=3D(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 (wra= p-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg m= sg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(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 (wr= ap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :width= (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displa= y #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap-= prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg not= ice erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) 46= 8 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg notice erc-ts 0 wr= ap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-pre= fix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg er= c-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (- 27= (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #1# = line-prefix #9#)) diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld index cd3537d3c94..bb248ffb28e 100644 --- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -1 +1 @@ -#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg unknown erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0= 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-time= stamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- = 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix = #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 = erc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font= -lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-p= refix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timest= amp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #= 4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line= -prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix= #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (er= c-msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invis= ible timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wra= p-prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #= 8# field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefi= x #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (w= rap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 3= 55 430 (wrap-prefix #1# line-prefix #7#)) \ No newline at end of file +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg notice erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0 = 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 2= 7 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix #= 2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font-= lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-pr= efix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timesta= mp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #4= #) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line-= prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix = #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (erc= -msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invisi= ble timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap= -prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #8= # field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefix= #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (wr= ap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 35= 5 430 (wrap-prefix #1# line-prefix #7#)) --=20 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Fix-right-stamps-commingling-with-erc-prompt.patch From 53bb212154471469768594e7db3c5f48918e316d Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 18 Oct 2023 23:20:07 -0700 Subject: [PATCH 3/4] [5.6] Fix right stamps commingling with erc-prompt * lisp/erc/erc-stamp.el (erc-insert-timestamp-left-and-right): Fix bug that saw the prompt being inserted after messages but just inside the narrowed operating portion of the buffer, which meant remaining modification hooks would see it upon visiting. Thanks to Corwin Brust for catching this. * test/lisp/erc/erc-fill-tests.el (erc-fill-wrap--monospace): Use custom `erc-prompt' function to guarantee invariants asserted by `erc--assert-input-bounds' are preserved throughout. (Bug#60936) --- lisp/erc/erc-stamp.el | 6 ++-- test/lisp/erc/erc-fill-tests.el | 57 +++++++++++++++++---------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 57fd7f39e50..c8fd7c35392 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -704,10 +704,12 @@ erc-insert-timestamp-left-and-right (unless erc-stamp--date-format-end (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify -95 t) (add-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify -95 t) - (let ((erc--insert-marker (point-min-marker))) + (let ((erc--insert-marker (point-min-marker)) + (end-marker (point-max-marker))) (set-marker-insertion-type erc--insert-marker t) (erc-stamp--lr-date-on-pre-modify nil) - (narrow-to-region erc--insert-marker (point-max)) + (narrow-to-region erc--insert-marker end-marker) + (set-marker end-marker nil) (set-marker erc--insert-marker nil))) (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) (ts-right (with-suppressed-warnings diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index f6c4c268017..80f5fd22ac6 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -203,36 +203,39 @@ erc-fill-wrap--monospace (unless (>= emacs-major-version 29) (ert-skip "Emacs version too low, missing `buffer-text-pixel-size'")) - (erc-fill-tests--wrap-populate - - (lambda () - (should (= erc-fill--wrap-value 27)) - (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-01-start") - - (ert-info ("Shift right by one (plus)") - ;; Args are all `erc-fill-wrap-nudge' +1 because interactive "p" - (ert-with-message-capture messages - ;; M-x erc-fill-wrap-nudge RET = - (ert-simulate-command '(erc-fill-wrap-nudge 2)) - (should (string-match (rx "for further adjustment") messages))) - (should (= erc-fill--wrap-value 29)) - (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-02-right")) - - (ert-info ("Shift left by five") - ;; "M-x erc-fill-wrap-nudge RET -----" - (ert-simulate-command '(erc-fill-wrap-nudge -4)) - (should (= erc-fill--wrap-value 25)) - (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-03-left")) + (let ((erc-prompt (lambda () "ABC>"))) + (erc-fill-tests--wrap-populate - (ert-info ("Reset") - ;; M-x erc-fill-wrap-nudge RET 0 - (ert-simulate-command '(erc-fill-wrap-nudge 0)) + (lambda () (should (= erc-fill--wrap-value 27)) (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") - (erc-fill-tests--compare "monospace-04-reset"))))) + (erc-fill-tests--compare "monospace-01-start") + + (ert-info ("Shift right by one (plus)") + ;; Args are all `erc-fill-wrap-nudge' +1 because interactive "p" + (ert-with-message-capture messages + ;; M-x erc-fill-wrap-nudge RET = + (ert-simulate-command '(erc-fill-wrap-nudge 2)) + (should (string-match (rx "for further adjustment") messages))) + (should (= erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") + (erc-fill-tests--compare "monospace-02-right")) + + (ert-info ("Shift left by five") + ;; "M-x erc-fill-wrap-nudge RET -----" + (ert-simulate-command '(erc-fill-wrap-nudge -4)) + (should (= erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") + (erc-fill-tests--compare "monospace-03-left")) + + (ert-info ("Reset") + ;; M-x erc-fill-wrap-nudge RET 0 + (ert-simulate-command '(erc-fill-wrap-nudge 0)) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") + (erc-fill-tests--compare "monospace-04-reset")) + + (erc--assert-input-bounds))))) (defun erc-fill-tests--simulate-refill () ;; Simulate `erc-fill-wrap-refill-buffer' synchronously and without -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Respect-user-markers-in-erc-insert-timestamp-lef.patch From 15f2e73c4022edc1d5ba0ad9c2dea69bbabe3a97 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 18 Oct 2023 23:20:07 -0700 Subject: [PATCH 4/4] [5.6] Respect user markers in erc--insert-timestamp-left * lisp/erc/erc-stamp.el (erc-insert-timestamp-left): Convert to normal function that calls existing generic version in order to dissuade users from adding their own methods, which could complicate troubleshooting, etc. (erc--insert-timestamp-left): Rename both methods using internal convention. In `erc-stamp--display-margin-mode' implementation, don't insert before user markers. * test/lisp/erc/erc-scenarios-stamp.el: New file. (Bug#60936) --- lisp/erc/erc-stamp.el | 10 ++-- test/lisp/erc/erc-scenarios-stamp.el | 90 ++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-stamp.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index c8fd7c35392..b515513dcb7 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -492,8 +492,11 @@ erc--conceal-prompt (put-text-property erc-insert-marker (1- erc-input-marker) 'display `((margin left-margin) ,prompt)))) -(cl-defmethod erc-insert-timestamp-left (string) +(defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." + (erc--insert-timestamp-left string)) + +(cl-defmethod erc--insert-timestamp-left (string) (goto-char (point-min)) (let* ((ignore-p (and erc-timestamp-only-if-changed-flag (string-equal string erc-timestamp-last-inserted))) @@ -504,13 +507,12 @@ erc-insert-timestamp-left (erc-put-text-property 0 len 'invisible erc-stamp--invisible-property s) (insert s))) -(cl-defmethod erc-insert-timestamp-left +(cl-defmethod erc--insert-timestamp-left (string &context (erc-stamp--display-margin-mode (eql t))) (unless (and erc-timestamp-only-if-changed-flag (string-equal string erc-timestamp-last-inserted)) (goto-char (point-min)) - (insert-before-markers-and-inherit - (setq erc-timestamp-last-inserted string)) + (insert-and-inherit (setq erc-timestamp-last-inserted string)) (dolist (p erc-stamp--inherited-props) (when-let ((v (get-text-property (point) p))) (put-text-property (point-min) (point) p v))) diff --git a/test/lisp/erc/erc-scenarios-stamp.el b/test/lisp/erc/erc-scenarios-stamp.el new file mode 100644 index 00000000000..d6b5d868ce5 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-stamp.el @@ -0,0 +1,90 @@ +;;; erc-scenarios-stamp.el --- Misc `erc-stamp' 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) + +(defvar erc-scenarios-stamp--user-marker nil) + +(defun erc-scenarios-stamp--on-post-modify () + (when-let (((erc--check-msg-prop 'erc-cmd 4))) + (set-marker erc-scenarios-stamp--user-marker (point-max)) + (ert-info ("User marker correctly placed at `erc-insert-marker'") + (should (= ?\n (char-before erc-scenarios-stamp--user-marker))) + (should (= erc-scenarios-stamp--user-marker erc-insert-marker)) + (save-excursion + (goto-char erc-scenarios-stamp--user-marker) + ;; The raw message ends in " Iabefhkloqv". However, + ;; `erc-server-004' only prints up to the 5th parameter. + (should (looking-back "CEIMRUabefhiklmnoqstuv\n")))))) + +(ert-deftest erc-scenarios-stamp--left/display-margin-mode () + + (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-scenarios-stamp--user-marker (make-marker)) + (erc-stamp--current-time 704591940) + (erc-stamp--tz t) + (erc-server-flood-penalty 0.1) + (erc-timestamp-only-if-changed-flag nil) + (erc-insert-timestamp-function #'erc-insert-timestamp-left) + (erc-modules (cons 'fill-wrap erc-modules)) + (erc-timestamp-only-if-changed-flag nil) + (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") + + (add-hook 'erc-insert-post-hook #'erc-scenarios-stamp--on-post-modify + nil t) + (funcall expect 5 "This server is in debug 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 '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))) + 'erc-speaker) + "irc.foonet.org")) + (should (pcase (get-text-property (pos-bol) 'display) + (`((margin left-margin) ,s) + (eq 'timestamp (get-text-property 0 'invisible s)))))) + + ;; We set a third-party marker at the end of 004's message (on + ;; then "\n"), post-insertion. + (ert-info ("User markers untouched by subsequent message left stamp") + (save-excursion + (goto-char erc-scenarios-stamp--user-marker) + (should (looking-back "CEIMRUabefhiklmnoqstuv\n")) + (should (looking-at (rx "["))))))))) + +;;; erc-scenarios-stamp.el ends here -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 17 Oct 2023 13:48:57 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 17 09:48:57 2023 Received: from localhost ([127.0.0.1]:58905 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qskRN-0000we-9j for submit <at> debbugs.gnu.org; Tue, 17 Oct 2023 09:48:57 -0400 Received: from mail-108-mta145.mxroute.com ([136.175.108.145]:33639) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qskRL-0000wI-Lw for 60936 <at> debbugs.gnu.org; Tue, 17 Oct 2023 09:48:56 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta145.mxroute.com (ZoneMTA) with ESMTPSA id 18b3de51789000ff68.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Tue, 17 Oct 2023 13:48:25 +0000 X-Zone-Loop: 32a75792ab062be30294cb13d89c070d2cd208acecce 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=8aI3ngmfYDNGNC+vJpjTh+IGL2q5f8ffWU7AYQXgn3g=; b=QrFJooMi4mhaa9VFLBHdoRTvrq LG/OIj2jv9DLwTxxGVCgVNasATIZMaqSkjYjY3biMl0KnXWQylH541ATFap+BkdxbtwqvIoaiP2uc 5edbSJd755shtVhX9AOCDE5bJZRFFYrwVS4wpvlHYPwulArOUva/Pdt68r/d9sWWHQWvLV0TzqYc0 5dvUV7H1S/IbOPQfRTAr80pdkD5vZ5yAfNZMbIJVtTC78kfqyFISBS3zySUsttBDPm2hSr+md1GtH fMquCgbYRisGA6OAuneottJycS5gKsGrWL/9YgWxnpATBOGBa64cmEH97SCAdDVNx/30hM0jO6D1y g97ZoA6w==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <8734yak6dr.fsf@HIDDEN> (J. P.'s message of "Mon, 16 Oct 2023 07:07:44 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> <8734yak6dr.fsf@HIDDEN> Date: Tue, 17 Oct 2023 06:48:21 -0700 Message-ID: <87o7gxe4wq.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v2 (erc-display-line redux). Fix initial bug involving missing text props on multi-buffer calls to `erc-display-line'. Convert latter to internal function and reimplement interface as high-level wrapper around `erc-display-message'. "J.P." <jp@HIDDEN> writes: > "J.P." <jp@HIDDEN> writes: > >> These changes introduced a(t least one) bug. To reproduce, call >> `erc-display-line' with a list of buffers, and notice only the first >> sees its message inserted with the correct text properties. A quick way >> to simulate this is by having two clients join the same two channels >> and then having one quit. The expected text props will be missing from >> one of the inserted >> >> *** someuser (n!~u@h) has quit >> >> messages. Verify by going to the first asterisk and doing C-u C-x =. >> >> Fix forthcoming. > > The second of the attached patches should hopefully do the trick. Actually, merely hoping folks will use `erc-display-message' instead of `erc-display-line' is surely delusional. There's likely far too much code out there doing stuff like: (erc-display-line (erc-make-notice "foo") my-buffer) So I've instead converted `erc-display-line' into a high-level insertion function more aligned with the manner in which it's used in practice. It's now more or less a thin wrapper around `erc-display-message' with a bit of special casing to intercept instances of the `erc-make-notice' pattern above for rewriting as: (erc-display-message nil 'notice my-buffer "foo") Hopefully, this is an acceptable compromise. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v1-v2.diff Content-Transfer-Encoding: quoted-printable From 2288132d2ae82bf6f1af44734306193e86bd90e5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Tue, 17 Oct 2023 06:44:50 -0700 Subject: [PATCH 0/2] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (2): ; Mark erc-log test as :unstable [5.6] Restore missing metadata props in erc-display-line etc/ERC-NEWS | 23 +++ lisp/erc/erc-fill.el | 3 +- lisp/erc/erc-stamp.el | 4 +- lisp/erc/erc.el | 146 +++++++++++------- test/lisp/erc/erc-networks-tests.el | 2 +- .../lisp/erc/erc-scenarios-display-message.el | 64 ++++++++ test/lisp/erc/erc-scenarios-log.el | 2 +- test/lisp/erc/erc-tests.el | 63 ++++++++ .../base/display-message/multibuf.eld | 45 ++++++ .../resources/base/renick/queries/solo.eld | 2 +- .../base/reuse-buffers/channel/barnet.eld | 2 +- .../base/reuse-buffers/channel/foonet.eld | 2 +- .../erc/resources/erc-scenarios-common.el | 4 +- .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 22 files changed, 307 insertions(+), 73 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-display-message.el create mode 100644 test/lisp/erc/resources/base/display-message/multibuf.e= ld Interdiff: diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 404d735b9f6..282a538e04d 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -288,16 +288,28 @@ ERC also provisionally reserves the same depth interv= al for continue to modify non-ERC hooks locally whenever possible, especially in new code. =20 -*** ERC strongly favors 'erc-display-message' for message insertion. -Although less common these days, folks still sometimes resort to using -the insertion function 'erc-display-line' because it's admittedly less -awkward than the supposedly higher level 'erc-display-message'. Thus, -ancient patterns, like preformatting text with 'erc-make-notice', -still occasionally appear in newer code. However, beginning in ERC -5.6, certain preparatory business necessary for the eventual move to a -richer UI has taken up residence in 'erc-display-message'. If you -find this development disturbing, by all means voice your concerns on -the tracker. (Patches for user-friendly wrappers are most welcome.) +*** Message insertion function 'erc-display-message' heavily favored. +Displaying "local" messages, like help text and interactive-command +feedback, in ERC buffers has never been straightforward. As such, +ancient patterns, like the pairing of preformatted "notice" text with +ERC's oldest insertion function, 'erc-display-line', still appear +quite frequently in the wild despite having been largely phased out of +ERC's own code base in 2002. That this specific example has endured +makes some sense because it's probably seen as less cumbersome than +fiddling with the more powerful and complicated 'erc-display-message'. + +The latest twist in this saga comes with this release, in which a +healthy dose of \"pre-insertion business\" has been invited to take up +residence in 'erc-display-message'. While this would seem to put +antiquated patterns, like the above mentioned 'erc-make-notice' combo, +at risk of having messages ignored or subject to degraded treatment by +built-in modules, a prophylactic measure has been erected to recast +'erc-display-line' as a thin wrapper around 'erc-display-message'. +And though nothing of the sort has been done for the lower-level +'erc-display-line-1' (now an obsolete alias for 'erc-insert-line'), +some fallback code has been put in place to ensure baseline +functionality. As always, if you find these developments disturbing, +please say so on the tracker. =20 *** ERC now manages timestamp-related properties a bit differently. For starters, the 'cursor-sensor-functions' text property is absent by diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 0048956e075..e28c3563ebf 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -539,7 +539,8 @@ erc-fill-wrap (goto-char (point-min)) (let ((len (or (and erc-fill--wrap-length-function (funcall erc-fill--wrap-length-function)) - (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg))) + (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg)) + ((not (eq msg-prop 'unknown)))) (when-let ((e (erc--get-speaker-bounds)) (b (pop e)) ((or erc-fill--wrap-action-dedent-p diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 7edf735eb43..0513a5c785c 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3003,13 +3003,26 @@ erc--traverse-inserted (defvar erc--insert-marker nil "Internal override for `erc-insert-marker'.") =20 -(defun erc-display-line-1 (string buffer) - "Display STRING in `erc-mode' BUFFER. -Auxiliary function used in `erc-display-line'. The line gets filtered to -interpret the control characters. Then, `erc-insert-pre-hook' gets called. -If `erc-insert-this' is still t, STRING gets inserted into the buffer. -Afterwards, `erc-insert-modify' and `erc-insert-post-hook' get called. -If STRING is nil, the function does nothing." +(define-obsolete-function-alias 'erc-display-line-1 'erc-insert-line "30.1= ") +(defun erc-insert-line (string buffer) + "Insert STRING in an `erc-mode' BUFFER. +When STRING is nil, do nothing. Otherwise, start off by running +`erc-insert-pre-hook' in BUFFER with `erc-insert-this' bound to +t. If the latter remains non-nil afterward, insert STRING into +BUFFER, ensuring a trailing newline. After that, narrow BUFFER +around STRING, along with its final line ending, and run +`erc-insert-modify' and `erc-insert-post-hook', respectively. In +all cases, run `erc-insert-done-hook' unnarrowed before exiting, +and update positions in `buffer-undo-list'. + +In general, expect to be called from a higher-level insertion +function, like `erc-display-message', especially when modules +should consider STRING as a candidate for formatting with +enhancements like indentation, fontification, timestamping, etc. +Otherwise, when called directly, allow built-in modules to ignore +STRING, which may make it appear incongruous in situ (unless +preformatted or anticipated by third-party members of the various +modification hooks)." (when string (with-current-buffer (or buffer (process-buffer erc-server-process)) (let ((insert-position (marker-position erc-insert-marker))) @@ -3021,7 +3034,7 @@ erc-display-line-1 (when (erc-string-invisible-p string) (erc-put-text-properties 0 (length string) '(invisible intangible) string))) - (erc-log (concat "erc-display-line: " string + (erc-log (concat "erc-display-message: " string (format "(%S)" string) " in buffer " (format "%s" buffer))) (setq erc-insert-this t) @@ -3091,24 +3104,9 @@ erc-is-valid-nick-p "Check if NICK is a valid IRC nickname." (string-match (concat "\\`" erc-valid-nick-regexp "\\'") nick)) =20 -(defun erc-display-line (string &optional buffer) +(defun erc--route-insertion (string buffer) "Insert STRING in BUFFER. -Expect BUFFER to be a live `erc-mode' buffer, a list of such -buffers, or the symbols `all' or `active'. If `all', insert -STRING in all buffers for the current session. If `active', -defer to the function `erc-active-buffer', which may return the -session's server buffer if the previously active buffer has been -killed. If BUFFER is nil or a network process, pretend it's set -to the appropriate server buffer. Otherwise, use the current -buffer. - -In most cases, expect to be called from a higher-level insertion -function, like `erc-display-message', especially when modules -should consider STRING as a candidate for formatting with -indentation, fontification, timestamping, etc. Otherwise, allow -built-in modules to ignore STRING, which may make it appear -incongruous in situ (unless anticipated by third-party hook -members or otherwise preformatted)." +See `erc-display-message' for acceptable BUFFER types." (let (seen msg-props) (dolist (buf (cond ((bufferp buffer) (list buffer)) @@ -3128,12 +3126,23 @@ erc-display-line (when (buffer-live-p buf) (when msg-props (setq erc--msg-props (copy-hash-table msg-props))) - (erc-display-line-1 string buf) + (erc-insert-line string buf) (setq seen t))) (unless (or seen (null buffer)) - (erc-display-line string nil)))) + (erc--route-insertion string nil)))) =20 -(defvar erc--compose-text-properties nil +(defun erc-display-line (string &optional buffer) + "Insert STRING in BUFFER as a plain \"local\" message. +Take pains to ensure modification hooks see messages created by +the old pattern (erc-display-line (erc-make-notice) my-buffer) as +being equivalent to a `erc-display-message' TYPE of `notice'." + (let ((erc--msg-prop-overrides erc--msg-prop-overrides)) + (when (eq 'erc-notice-face (get-text-property 0 'font-lock-face string= )) + (unless (assq 'erc-msg erc--msg-prop-overrides) + (push '(erc-msg . notice) erc--msg-prop-overrides))) + (erc-display-message nil nil buffer string))) + +(defvar erc--merge-text-properties-p nil "Non-nil when `erc-put-text-property' defers to `erc--merge-prop'.") =20 ;; To save space, we could maintain a map of all readable property @@ -3452,6 +3461,15 @@ erc-display-message string MSG). Expect BUFFER to be among the sort accepted by the function `erc-display-line'. =20 +Expect BUFFER to be a live `erc-mode' buffer, a list of such +buffers, or the symbols `all' or `active'. If `all', insert +STRING in all buffers for the current session. If `active', +defer to the function `erc-active-buffer', which may return the +session's server buffer if the previously active buffer has been +killed. If BUFFER is nil or a network process, pretend it's set +to the appropriate server buffer. Otherwise, use the current +buffer. + When TYPE is a list of symbols, call handlers from left to right without influencing how they behave when encountering existing faces. As of ERC 5.6, expect a TYPE of (notice error) to insert @@ -3462,24 +3480,31 @@ erc-display-message being (erc-error-face erc-notice-face) throughout MSG when `erc-notice-highlight-type' is left at its default, `all'. =20 -As of ERC 5.6, assume user code will use this function instead of -`erc-display-line' when it's important that insert hooks treat -MSG in a manner befitting messages received from a server. That -is, expect to process most nontrivial informational messages, for -which PARSED is typically nil, when the caller desires the -inserted message to feature buttonizing and other effects." +As of ERC 5.6, assume third-party code will use this function +instead of lower-level ones, like `erc-insert-line', when needing +ERC to process arbitrary informative messages as if they'd been +sent from a server. That is, guarantee \"local\" messages, for +which PARSED is typically nil, will be subject to buttonizing, +filling, and other effects." (let ((string (if (symbolp msg) (apply #'erc-format-message msg args) msg)) (erc--msg-props (or erc--msg-props - (let* ((table (make-hash-table :size 5)) - (cmd (and parsed (erc--get-eq-comparable-cmd - (erc-response.command parsed)))) - (m (cond ((and msg (symbolp msg)) msg) - ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) - (t 'unknown)))) - (puthash 'erc-msg m table) + (let ((table (make-hash-table :size 5)) + (cmd (and parsed (erc--get-eq-comparable-cmd + (erc-response.command parsed))))) + (puthash 'erc-msg + (cond ((and msg (symbolp msg)) msg) + ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) + (type (pcase type + ((pred symbolp) type) + ((pred listp) + (intern (mapconcat #'prin1-to-string + type "-"))) + (_ 'unknown))) + (t 'unknown)) + table) (when cmd (puthash 'erc-cmd cmd table)) (and erc--msg-prop-overrides @@ -3492,7 +3517,7 @@ erc-display-message ((null type) string) ((listp type) - (let ((erc--compose-text-properties + (let ((erc--merge-text-properties-p (and (eq (car type) t) (setq type (cdr type))))) (dolist (type type) (setq string (erc-display-message-highlight type string)))) @@ -3501,13 +3526,13 @@ erc-display-message (erc-display-message-highlight type string)))) =20 (if (not (erc-response-p parsed)) - (erc-display-line string buffer) + (erc--route-insertion string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parse= d) string)) - (erc-display-line string buffer))))) + (erc--route-insertion string buffer))))) =20 (defun erc-message-type-member (position list) "Return non-nil if the erc-parsed text-property at POSITION is in LIST. @@ -6492,7 +6517,7 @@ erc-put-text-property =20 You can redefine or `defadvice' this function in order to add EmacsSpeak support." - (if erc--compose-text-properties + (if erc--merge-text-properties-p (erc--merge-prop start end property value object) (put-text-property start end property value object))) =20 diff --git a/test/lisp/erc/erc-networks-tests.el b/test/lisp/erc/erc-networ= ks-tests.el index e95d99c128f..45ef0d10a6e 100644 --- a/test/lisp/erc/erc-networks-tests.el +++ b/test/lisp/erc/erc-networks-tests.el @@ -1206,7 +1206,7 @@ erc-networks--set-name calls) (erc-mode) =20 - (cl-letf (((symbol-function 'erc-display-line) + (cl-letf (((symbol-function 'erc--route-insertion) (lambda (&rest r) (push r calls)))) =20 (ert-info ("Signals when `erc-server-announced-name' unset") diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenari= os-log.el index 9d3116d3db3..cd28ea54b2e 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -149,7 +149,7 @@ erc-scenarios-log--clear-stamp (when noninteractive (delete-directory tempdir :recursive)))) =20 (ert-deftest erc-scenarios-log--truncate () - :tags '(:expensive-test) + :tags '(:expensive-test :unstable) (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "base/assoc/bouncer-history") (dumb-server (erc-d-run "localhost" t 'foonet)) @@ -180,7 +180,7 @@ erc-scenarios-log--truncate (should-not (file-exists-p logserv)) (should-not (file-exists-p logchan)) (funcall expect 10 "*** MAXLIST=3DbeI:60") - (erc-d-t-wait-for 5 (=3D (pos-bol) (point-min))) + (should (=3D (pos-bol) (point-min))) (should (file-exists-p logserv)))) =20 (ert-info ("Log file ahead of truncation point") diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b35afaa552f..02dfc55b6d5 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1938,22 +1938,23 @@ erc-format-privmessage 2 5 (erc-speaker "Bob" font-lock-face erc-nick-default-face) 5 12 (font-lock-face erc-default-face)))))) =20 -(ert-deftest erc-display-line () +(ert-deftest erc--route-insertion () (erc-tests--send-prep) (erc-tests--set-fake-server-process "sleep" "1") (setq erc-networks--id (erc-networks--id-create 'foonet)) =20 - (let ((server-buffer (current-buffer)) - (spam-buffer (save-excursion (erc--open-target "#spam"))) - (chan-buffer (save-excursion (erc--open-target "#chan"))) - calls) - (cl-letf (((symbol-function 'erc-display-line-1) + (let* ((erc-modules) ; for `erc--open-target' + (server-buffer (current-buffer)) + (spam-buffer (save-excursion (erc--open-target "#spam"))) + (chan-buffer (save-excursion (erc--open-target "#chan"))) + calls) + (cl-letf (((symbol-function 'erc-insert-line) (lambda (&rest r) (push (cons 'line-1 r) calls)))) =20 (with-current-buffer chan-buffer =20 (ert-info ("Null `buffer' routes to live server-buffer") - (erc-display-line "null" nil) + (erc--route-insertion "null" nil) (should (equal (pop calls) `(line-1 "null" ,server-buffer))) (should-not calls)) =20 @@ -1961,14 +1962,14 @@ erc-display-line ;; Copies a let-bound `erc--msg-props' before mutating. (let* ((table (map-into '(erc-msg msg) 'hash-table)) (erc--msg-props table)) - (erc-display-line "cons" (list server-buffer spam-buffer)) + (erc--route-insertion "cons" (list server-buffer spam-buffer)) (should-not (eq table erc--msg-props))) (should (equal (pop calls) `(line-1 "cons" ,spam-buffer))) (should (equal (pop calls) `(line-1 "cons" ,server-buffer))) (should-not calls)) =20 (ert-info ("Variant `all' inserts in all session buffers") - (erc-display-line "all" 'all) + (erc--route-insertion "all" 'all) (should (equal (pop calls) `(line-1 "all" ,chan-buffer))) (should (equal (pop calls) `(line-1 "all" ,spam-buffer))) (should (equal (pop calls) `(line-1 "all" ,server-buffer))) @@ -1977,7 +1978,7 @@ erc-display-line (ert-info ("Variant `active' routes to active buffer if alive") (should (eq chan-buffer (erc-with-server-buffer erc-active-buffe= r))) (erc-set-active-buffer spam-buffer) - (erc-display-line "act" 'active) + (erc--route-insertion "act" 'active) (should (equal (pop calls) `(line-1 "act" ,spam-buffer))) (should (eq (erc-active-buffer) spam-buffer)) (should-not calls)) @@ -1985,7 +1986,7 @@ erc-display-line (ert-info ("Variant `active' falls back to current buffer") (should (eq spam-buffer (erc-active-buffer))) (kill-buffer "#spam") - (erc-display-line "nact" 'active) + (erc--route-insertion "nact" 'active) (should (equal (pop calls) `(line-1 "nact" ,server-buffer))) (should (eq (erc-with-server-buffer erc-active-buffer) server-buffer)) @@ -1993,7 +1994,7 @@ erc-display-line =20 (ert-info ("Dead single buffer defaults to live server-buffer") (should-not (get-buffer "#spam")) - (erc-display-line "dead" 'spam-buffer) + (erc--route-insertion "dead" 'spam-buffer) (should (equal (pop calls) `(line-1 "dead" ,server-buffer))) (should-not calls)))) =20 diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-01-start.eld index 238d8cc73c2..8a6f2289f5d 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 3= 53 (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 1680332400 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-02-right.eld index d1ce9198e69..3eb4be4919b 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (6)))) 350 3= 53 (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 1680332400 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index d70184724ba..82c6d52cf7c 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-pref= ix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#)= 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6= =3D(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (= erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(spac= e :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wr= ap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 20= 2 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefi= x #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-p= refix #4=3D(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# lin= e-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg da= testamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp= wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(spac= e :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wr= ap-prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1#= line-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 = 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-pre= fix #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1= # line-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-= prefix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9= =3D"") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-= prefix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefi= x #8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTI= ON wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wr= ap-prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) = 500 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680= 332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 2= 7 0)) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 5= 11 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix = #1# line-prefix #11#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefi= x #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) = 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6=3D= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc= -msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(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 3= 15 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #= 3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-pref= ix #4=3D(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-p= refix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg dates= tamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp wr= ap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg msg = erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(space := width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wrap-= prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1# li= ne-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 475= (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-prefix= #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1# l= ine-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-pre= fix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd PRI= VMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9=3D= "") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-pre= fix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefix #= 8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION = wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wrap-= prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) 500= 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680332= 400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0= )) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 511 = 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix #1#= line-prefix #11#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index def97738ce6..84a1e34670c 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index be3e2b33cfd..83394f2f639 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index 098257d0b49..1605628b29f 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index def97738ce6..84a1e34670c 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/t= est/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 360b3dafafd..7a7e01de49d 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-= prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix = #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (lin= e-spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1= # line-prefix #3=3D(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 (wr= ap-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(space :width= (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefi= x #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (w= rap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg= msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :widt= h (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displ= ay #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap= -prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg un= known erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) = 468 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg unknown erc-ts 0= wrap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-= prefix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg= erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (-= 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #= 1# line-prefix #9#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-p= refix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #= 2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((= margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (line= -spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1#= line-prefix #3=3D(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 (wra= p-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg m= sg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(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 (wr= ap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :width= (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displa= y #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap-= prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg not= ice erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) 46= 8 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg notice erc-ts 0 wr= ap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-pre= fix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg er= c-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (- 27= (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #1# = line-prefix #9#)) diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld index cd3537d3c94..bb248ffb28e 100644 --- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -1 +1 @@ -#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg unknown erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0= 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-time= stamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- = 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix = #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 = erc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font= -lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-p= refix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timest= amp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #= 4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line= -prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix= #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (er= c-msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invis= ible timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wra= p-prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #= 8# field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefi= x #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (w= rap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 3= 55 430 (wrap-prefix #1# line-prefix #7#)) \ No newline at end of file +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg notice erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0 = 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 2= 7 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix #= 2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font-= lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-pr= efix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timesta= mp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #4= #) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line-= prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix = #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (erc= -msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invisi= ble timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap= -prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #8= # field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefix= #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (wr= ap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 35= 5 430 (wrap-prefix #1# line-prefix #7#)) --=20 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Mark-erc-log-test-as-unstable.patch From e655a058018d953988608adeed658a854ecdf7e6 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 15 Oct 2023 13:43:12 -0700 Subject: [PATCH 1/2] ; Mark erc-log test as :unstable * test/lisp/erc/erc-scenarios-log.el (erc-scenarios-log--truncate): Mark :unstable for now. * test/lisp/erc/resources/base/renick/queries/solo.eld: Timeouts. * test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld: Timeouts. * test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld: Timeouts. * test/lisp/erc/resources/erc-scenarios-common.el: Timeouts. --- test/lisp/erc/erc-scenarios-log.el | 2 +- test/lisp/erc/resources/base/renick/queries/solo.eld | 2 +- test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld | 2 +- test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld | 2 +- test/lisp/erc/resources/erc-scenarios-common.el | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenarios-log.el index f7e7d61c92e..cd28ea54b2e 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -149,7 +149,7 @@ erc-scenarios-log--clear-stamp (when noninteractive (delete-directory tempdir :recursive)))) (ert-deftest erc-scenarios-log--truncate () - :tags '(:expensive-test) + :tags '(:expensive-test :unstable) (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "base/assoc/bouncer-history") (dumb-server (erc-d-run "localhost" t 'foonet)) diff --git a/test/lisp/erc/resources/base/renick/queries/solo.eld b/test/lisp/erc/resources/base/renick/queries/solo.eld index 12fa7d264e9..fa4c075adac 100644 --- a/test/lisp/erc/resources/base/renick/queries/solo.eld +++ b/test/lisp/erc/resources/base/renick/queries/solo.eld @@ -30,7 +30,7 @@ (0 ":irc.foonet.org NOTICE tester :[09:56:57] 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.") (0 ":irc.foonet.org 305 tester :You are no longer marked as being away")) -((mode 1 "MODE #foo") +((mode 10 "MODE #foo") (0 ":irc.foonet.org 324 tester #foo +nt") (0 ":irc.foonet.org 329 tester #foo 1622454985") (0.1 ":alice!~u@HIDDEN PRIVMSG #foo :bob: Farewell, pretty lady: you must hold the credit of your father.") diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld index efc2506fd6f..d106a45cf66 100644 --- a/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld +++ b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld @@ -56,7 +56,7 @@ (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":joe!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620205534") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: Chi non te vede, non te pretia.") diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld index a11cfac2e73..603afa2fc3e 100644 --- a/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld +++ b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld @@ -52,7 +52,7 @@ (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620205534") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: Thou desirest me to stop in my tale against the hair.") diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el index 5354b300b47..9e134e6932f 100644 --- a/test/lisp/erc/resources/erc-scenarios-common.el +++ b/test/lisp/erc/resources/erc-scenarios-common.el @@ -574,7 +574,7 @@ erc-scenarios-common--upstream-reconnect :password "changeme" :full-name "tester") (erc-scenarios-common-assert-initial-buf-name nil port) - (erc-d-t-wait-for 3 (eq (erc-network) 'foonet)) + (erc-d-t-wait-for 6 (eq (erc-network) 'foonet)) (erc-d-t-wait-for 3 (string= (buffer-name) "foonet")) (funcall expect 5 "foonet"))) @@ -713,7 +713,7 @@ erc-scenarios-common--join-network-id (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-foo)) (funcall expect 3 "<bob>") (erc-d-t-absent-for 0.1 "<joe>") - (funcall expect 10 "not given me"))) + (funcall expect 20 "not given me"))) (ert-info ("All #chan@barnet output received") (with-current-buffer chan-buf-bar -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Restore-missing-metadata-props-in-erc-display-li.patch Content-Transfer-Encoding: quoted-printable From 2288132d2ae82bf6f1af44734306193e86bd90e5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 15 Oct 2023 17:22:22 -0700 Subject: [PATCH 2/2] [5.6] Restore missing metadata props in erc-display-li= ne * etc/ERC-NEWS: Designate `erc-display-message' as the favored means of inserting messages. * lisp/erc/erc-fill.el (erc-fill-wrap): Skip any `unknown' `erc-msg'. * lisp/erc/erc-stamp.el (erc-stamp--current-time): Use an existing `erc-ts' text property, when present, for the current message time. * lisp/erc/erc.el (erc-display-line-1): Update doc string. (erc-display-line): Convert to a thin wrapper around `erc-display-message', and move its existing body to a new function, `erc--route-insertion'. (erc--route-insertion): Adopt former body of `erc-display-line'. Copy `erc--msg-props' hash table when inserting a message in multiple buffers. At present, only `erc-server-QUIT' uses this facility. Also, improve readability with at most one recursive call for the fall-through case. (erc--compose-text-properties, erc--merge-text-properties-p): Rename former to latter to avoid confusion with `composition' property. (erc-display-message): Update doc string. Attempt to adapt a non-nil TYPE parameter for use as the value of the `erc-msg' text property before resorting to a value of `unknown'. But only do this when PARSED is nil, and MSG is a string. Call `erc--route-insertion' instead of `erc-display-line'. Use new name for `erc--compose-text-properties'. (erc-put-text-property): Update name of variable `erc--compose-text-properties'. * test/lisp/erc-networks-tests.el (erc-networks--set-name): Mock `erc--route-insertion' instead of `erc-display-line'. * test/lisp/erc/erc-scenarios-display-message.el: New file. * test/lisp/erc/erc-tests.el (erc--route-insertion): New test. * test/lisp/erc/resources/base/display-message/multibuf.eld: New test data. * test/lisp/erc/resources/fill/snapshots/merge-01-start.eld: Update. * test/lisp/erc/resources/fill/snapshots/merge-02-right.eld: Update. * test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld: Update. * test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld: Update. * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: Update. (Bug#60936) --- etc/ERC-NEWS | 23 +++ lisp/erc/erc-fill.el | 3 +- lisp/erc/erc-stamp.el | 4 +- lisp/erc/erc.el | 146 +++++++++++------- test/lisp/erc/erc-networks-tests.el | 2 +- .../lisp/erc/erc-scenarios-display-message.el | 64 ++++++++ test/lisp/erc/erc-tests.el | 63 ++++++++ .../base/display-message/multibuf.eld | 45 ++++++ .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 17 files changed, 301 insertions(+), 67 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-display-message.el create mode 100644 test/lisp/erc/resources/base/display-message/multibuf.e= ld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 2e56539f210..282a538e04d 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -288,6 +288,29 @@ ERC also provisionally reserves the same depth interva= l for continue to modify non-ERC hooks locally whenever possible, especially in new code. =20 +*** Message insertion function 'erc-display-message' heavily favored. +Displaying "local" messages, like help text and interactive-command +feedback, in ERC buffers has never been straightforward. As such, +ancient patterns, like the pairing of preformatted "notice" text with +ERC's oldest insertion function, 'erc-display-line', still appear +quite frequently in the wild despite having been largely phased out of +ERC's own code base in 2002. That this specific example has endured +makes some sense because it's probably seen as less cumbersome than +fiddling with the more powerful and complicated 'erc-display-message'. + +The latest twist in this saga comes with this release, in which a +healthy dose of \"pre-insertion business\" has been invited to take up +residence in 'erc-display-message'. While this would seem to put +antiquated patterns, like the above mentioned 'erc-make-notice' combo, +at risk of having messages ignored or subject to degraded treatment by +built-in modules, a prophylactic measure has been erected to recast +'erc-display-line' as a thin wrapper around 'erc-display-message'. +And though nothing of the sort has been done for the lower-level +'erc-display-line-1' (now an obsolete alias for 'erc-insert-line'), +some fallback code has been put in place to ensure baseline +functionality. As always, if you find these developments disturbing, +please say so on the tracker. + *** ERC now manages timestamp-related properties a bit differently. For starters, the 'cursor-sensor-functions' text property is absent by default unless the option 'erc-echo-timestamps' is already enabled on diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 0048956e075..e28c3563ebf 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -539,7 +539,8 @@ erc-fill-wrap (goto-char (point-min)) (let ((len (or (and erc-fill--wrap-length-function (funcall erc-fill--wrap-length-function)) - (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg))) + (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg)) + ((not (eq msg-prop 'unknown)))) (when-let ((e (erc--get-speaker-bounds)) (b (pop e)) ((or erc-fill--wrap-action-dedent-p diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 394643c03cb..57fd7f39e50 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -219,7 +219,9 @@ erc-stamp--current-time (erc-compat--current-lisp-time)) =20 (cl-defmethod erc-stamp--current-time :around () - (or erc-stamp--current-time (cl-call-next-method))) + (or erc-stamp--current-time + (and erc--msg-props (gethash 'erc-ts erc--msg-props)) + (cl-call-next-method))) =20 (defvar erc-stamp--skip nil "Non-nil means inhibit `erc-add-timestamp' completely.") diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 5bf6496e926..0513a5c785c 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3003,13 +3003,26 @@ erc--traverse-inserted (defvar erc--insert-marker nil "Internal override for `erc-insert-marker'.") =20 -(defun erc-display-line-1 (string buffer) - "Display STRING in `erc-mode' BUFFER. -Auxiliary function used in `erc-display-line'. The line gets filtered to -interpret the control characters. Then, `erc-insert-pre-hook' gets called. -If `erc-insert-this' is still t, STRING gets inserted into the buffer. -Afterwards, `erc-insert-modify' and `erc-insert-post-hook' get called. -If STRING is nil, the function does nothing." +(define-obsolete-function-alias 'erc-display-line-1 'erc-insert-line "30.1= ") +(defun erc-insert-line (string buffer) + "Insert STRING in an `erc-mode' BUFFER. +When STRING is nil, do nothing. Otherwise, start off by running +`erc-insert-pre-hook' in BUFFER with `erc-insert-this' bound to +t. If the latter remains non-nil afterward, insert STRING into +BUFFER, ensuring a trailing newline. After that, narrow BUFFER +around STRING, along with its final line ending, and run +`erc-insert-modify' and `erc-insert-post-hook', respectively. In +all cases, run `erc-insert-done-hook' unnarrowed before exiting, +and update positions in `buffer-undo-list'. + +In general, expect to be called from a higher-level insertion +function, like `erc-display-message', especially when modules +should consider STRING as a candidate for formatting with +enhancements like indentation, fontification, timestamping, etc. +Otherwise, when called directly, allow built-in modules to ignore +STRING, which may make it appear incongruous in situ (unless +preformatted or anticipated by third-party members of the various +modification hooks)." (when string (with-current-buffer (or buffer (process-buffer erc-server-process)) (let ((insert-position (marker-position erc-insert-marker))) @@ -3021,7 +3034,7 @@ erc-display-line-1 (when (erc-string-invisible-p string) (erc-put-text-properties 0 (length string) '(invisible intangible) string))) - (erc-log (concat "erc-display-line: " string + (erc-log (concat "erc-display-message: " string (format "(%S)" string) " in buffer " (format "%s" buffer))) (setq erc-insert-this t) @@ -3091,39 +3104,45 @@ erc-is-valid-nick-p "Check if NICK is a valid IRC nickname." (string-match (concat "\\`" erc-valid-nick-regexp "\\'") nick)) =20 -(defun erc-display-line (string &optional buffer) - "Display STRING in the ERC BUFFER. -All screen output must be done through this function. If BUFFER is nil -or omitted, the default ERC buffer for the `erc-session-server' is used. -The BUFFER can be an actual buffer, a list of buffers, `all' or `active'. -If BUFFER =3D `all', the string is displayed in all the ERC buffers for the -current session. `active' means the current active buffer -\(`erc-active-buffer'). If the buffer can't be resolved, the current -buffer is used. `erc-display-line-1' is used to display STRING. - -If STRING is nil, the function does nothing." - (let (new-bufs) +(defun erc--route-insertion (string buffer) + "Insert STRING in BUFFER. +See `erc-display-message' for acceptable BUFFER types." + (let (seen msg-props) (dolist (buf (cond ((bufferp buffer) (list buffer)) - ((listp buffer) buffer) + ((consp buffer) + (setq msg-props erc--msg-props) + buffer) ((processp buffer) (list (process-buffer buffer))) ((eq 'all buffer) ;; Hmm, or all of the same session server? (erc-buffer-list nil erc-server-process)) - ((and (eq 'active buffer) (erc-active-buffer)) - (list (erc-active-buffer))) + ((and-let* (((eq 'active buffer)) + (b (erc-active-buffer))) + (list b))) ((erc-server-buffer-live-p) (list (process-buffer erc-server-process))) (t (list (current-buffer))))) (when (buffer-live-p buf) - (erc-display-line-1 string buf) - (push buf new-bufs))) - (when (null new-bufs) - (erc-display-line-1 string (if (erc-server-buffer-live-p) - (process-buffer erc-server-process) - (current-buffer)))))) - -(defvar erc--compose-text-properties nil + (when msg-props + (setq erc--msg-props (copy-hash-table msg-props))) + (erc-insert-line string buf) + (setq seen t))) + (unless (or seen (null buffer)) + (erc--route-insertion string nil)))) + +(defun erc-display-line (string &optional buffer) + "Insert STRING in BUFFER as a plain \"local\" message. +Take pains to ensure modification hooks see messages created by +the old pattern (erc-display-line (erc-make-notice) my-buffer) as +being equivalent to a `erc-display-message' TYPE of `notice'." + (let ((erc--msg-prop-overrides erc--msg-prop-overrides)) + (when (eq 'erc-notice-face (get-text-property 0 'font-lock-face string= )) + (unless (assq 'erc-msg erc--msg-prop-overrides) + (push '(erc-msg . notice) erc--msg-prop-overrides))) + (erc-display-message nil nil buffer string))) + +(defvar erc--merge-text-properties-p nil "Non-nil when `erc-put-text-property' defers to `erc--merge-prop'.") =20 ;; To save space, we could maintain a map of all readable property @@ -3432,14 +3451,24 @@ erc-display-message Insert MSG or text derived from MSG into an ERC buffer, possibly after applying formatting by way of either a `format-spec' known to a message-catalog entry or a TYPE known to a specialized -string handler. Additionally, derive internal metadata, faces, -and other text properties from the various overloaded parameters, -such as PARSED, when it's an `erc-response' object, and MSG, when -it's a key (symbol) for a \"message catalog\" entry. Expect -ARGS, when applicable, to be `format-spec' args known to such an -entry, and TYPE, when non-nil, to be a symbol handled by +string handler. Additionally, derive metadata, faces, and other +text properties from the various overloaded parameters, such as +PARSED, when it's an `erc-response' object, and MSG, when it's a +key (symbol) for a \"message catalog\" entry. Expect ARGS, when +applicable, to be `format-spec' args known to such an entry, and +TYPE, when non-nil, to be a symbol handled by `erc-display-message-highlight' (necessarily accompanied by a -string MSG). +string MSG). Expect BUFFER to be among the sort accepted by the +function `erc-display-line'. + +Expect BUFFER to be a live `erc-mode' buffer, a list of such +buffers, or the symbols `all' or `active'. If `all', insert +STRING in all buffers for the current session. If `active', +defer to the function `erc-active-buffer', which may return the +session's server buffer if the previously active buffer has been +killed. If BUFFER is nil or a network process, pretend it's set +to the appropriate server buffer. Otherwise, use the current +buffer. =20 When TYPE is a list of symbols, call handlers from left to right without influencing how they behave when encountering existing @@ -3451,24 +3480,31 @@ erc-display-message being (erc-error-face erc-notice-face) throughout MSG when `erc-notice-highlight-type' is left at its default, `all'. =20 -As of ERC 5.6, assume user code will use this function instead of -`erc-display-line' when it's important that insert hooks treat -MSG in a manner befitting messages received from a server. That -is, expect to process most nontrivial informational messages, for -which PARSED is typically nil, when the caller desires -buttonizing and other effects." +As of ERC 5.6, assume third-party code will use this function +instead of lower-level ones, like `erc-insert-line', when needing +ERC to process arbitrary informative messages as if they'd been +sent from a server. That is, guarantee \"local\" messages, for +which PARSED is typically nil, will be subject to buttonizing, +filling, and other effects." (let ((string (if (symbolp msg) (apply #'erc-format-message msg args) msg)) (erc--msg-props (or erc--msg-props - (let* ((table (make-hash-table :size 5)) - (cmd (and parsed (erc--get-eq-comparable-cmd - (erc-response.command parsed)))) - (m (cond ((and msg (symbolp msg)) msg) - ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) - (t 'unknown)))) - (puthash 'erc-msg m table) + (let ((table (make-hash-table :size 5)) + (cmd (and parsed (erc--get-eq-comparable-cmd + (erc-response.command parsed))))) + (puthash 'erc-msg + (cond ((and msg (symbolp msg)) msg) + ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) + (type (pcase type + ((pred symbolp) type) + ((pred listp) + (intern (mapconcat #'prin1-to-string + type "-"))) + (_ 'unknown))) + (t 'unknown)) + table) (when cmd (puthash 'erc-cmd cmd table)) (and erc--msg-prop-overrides @@ -3481,7 +3517,7 @@ erc-display-message ((null type) string) ((listp type) - (let ((erc--compose-text-properties + (let ((erc--merge-text-properties-p (and (eq (car type) t) (setq type (cdr type))))) (dolist (type type) (setq string (erc-display-message-highlight type string)))) @@ -3490,13 +3526,13 @@ erc-display-message (erc-display-message-highlight type string)))) =20 (if (not (erc-response-p parsed)) - (erc-display-line string buffer) + (erc--route-insertion string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parse= d) string)) - (erc-display-line string buffer))))) + (erc--route-insertion string buffer))))) =20 (defun erc-message-type-member (position list) "Return non-nil if the erc-parsed text-property at POSITION is in LIST. @@ -6481,7 +6517,7 @@ erc-put-text-property =20 You can redefine or `defadvice' this function in order to add EmacsSpeak support." - (if erc--compose-text-properties + (if erc--merge-text-properties-p (erc--merge-prop start end property value object) (put-text-property start end property value object))) =20 diff --git a/test/lisp/erc/erc-networks-tests.el b/test/lisp/erc/erc-networ= ks-tests.el index e95d99c128f..45ef0d10a6e 100644 --- a/test/lisp/erc/erc-networks-tests.el +++ b/test/lisp/erc/erc-networks-tests.el @@ -1206,7 +1206,7 @@ erc-networks--set-name calls) (erc-mode) =20 - (cl-letf (((symbol-function 'erc-display-line) + (cl-letf (((symbol-function 'erc--route-insertion) (lambda (&rest r) (push r calls)))) =20 (ert-info ("Signals when `erc-server-announced-name' unset") diff --git a/test/lisp/erc/erc-scenarios-display-message.el b/test/lisp/erc= /erc-scenarios-display-message.el new file mode 100644 index 00000000000..51bdf305ad5 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-display-message.el @@ -0,0 +1,64 @@ +;;; erc-scenarios-display-message.el --- erc-display-message -*- lexical-b= inding: 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))) + +(ert-deftest erc-scenarios-display-message--multibuf () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/display-message") + (dumb-server (erc-d-run "localhost" t 'multibuf)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (erc-modules (cons 'fill-wrap erc-modules)) + (erc-autojoin-channels-alist '((foonet "#chan"))) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :full-name "tester") + (funcall expect 10 "debug mode"))) + + (ert-info ("User dummy is a member of #chan") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (funcall expect 10 "dummy"))) + + (ert-info ("Dummy's QUIT notice in query contains metadata props") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "dummy")) + (funcall expect 10 "<dummy> hi") + (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)= )))) + + (ert-info ("Dummy's QUIT notice in #chan contains metadata props") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)= )))) + + (erc-cmd-QUIT ""))) + +(eval-when-compile (require 'erc-join)) + +;;; erc-scenarios-display-message.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 4f4662f5075..02dfc55b6d5 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1938,6 +1938,69 @@ erc-format-privmessage 2 5 (erc-speaker "Bob" font-lock-face erc-nick-default-face) 5 12 (font-lock-face erc-default-face)))))) =20 +(ert-deftest erc--route-insertion () + (erc-tests--send-prep) + (erc-tests--set-fake-server-process "sleep" "1") + (setq erc-networks--id (erc-networks--id-create 'foonet)) + + (let* ((erc-modules) ; for `erc--open-target' + (server-buffer (current-buffer)) + (spam-buffer (save-excursion (erc--open-target "#spam"))) + (chan-buffer (save-excursion (erc--open-target "#chan"))) + calls) + (cl-letf (((symbol-function 'erc-insert-line) + (lambda (&rest r) (push (cons 'line-1 r) calls)))) + + (with-current-buffer chan-buffer + + (ert-info ("Null `buffer' routes to live server-buffer") + (erc--route-insertion "null" nil) + (should (equal (pop calls) `(line-1 "null" ,server-buffer))) + (should-not calls)) + + (ert-info ("Cons `buffer' routes to live members") + ;; Copies a let-bound `erc--msg-props' before mutating. + (let* ((table (map-into '(erc-msg msg) 'hash-table)) + (erc--msg-props table)) + (erc--route-insertion "cons" (list server-buffer spam-buffer)) + (should-not (eq table erc--msg-props))) + (should (equal (pop calls) `(line-1 "cons" ,spam-buffer))) + (should (equal (pop calls) `(line-1 "cons" ,server-buffer))) + (should-not calls)) + + (ert-info ("Variant `all' inserts in all session buffers") + (erc--route-insertion "all" 'all) + (should (equal (pop calls) `(line-1 "all" ,chan-buffer))) + (should (equal (pop calls) `(line-1 "all" ,spam-buffer))) + (should (equal (pop calls) `(line-1 "all" ,server-buffer))) + (should-not calls)) + + (ert-info ("Variant `active' routes to active buffer if alive") + (should (eq chan-buffer (erc-with-server-buffer erc-active-buffe= r))) + (erc-set-active-buffer spam-buffer) + (erc--route-insertion "act" 'active) + (should (equal (pop calls) `(line-1 "act" ,spam-buffer))) + (should (eq (erc-active-buffer) spam-buffer)) + (should-not calls)) + + (ert-info ("Variant `active' falls back to current buffer") + (should (eq spam-buffer (erc-active-buffer))) + (kill-buffer "#spam") + (erc--route-insertion "nact" 'active) + (should (equal (pop calls) `(line-1 "nact" ,server-buffer))) + (should (eq (erc-with-server-buffer erc-active-buffer) + server-buffer)) + (should-not calls)) + + (ert-info ("Dead single buffer defaults to live server-buffer") + (should-not (get-buffer "#spam")) + (erc--route-insertion "dead" 'spam-buffer) + (should (equal (pop calls) `(line-1 "dead" ,server-buffer))) + (should-not calls)))) + + (should-not (buffer-live-p spam-buffer)) + (kill-buffer chan-buffer))) + (defvar erc-tests--ipv6-examples '("1:2:3:4:5:6:7:8" "::ffff:10.0.0.1" "::ffff:1.2.3.4" "::ffff:0.0.0.0" diff --git a/test/lisp/erc/resources/base/display-message/multibuf.eld b/te= st/lisp/erc/resources/base/display-message/multibuf.eld new file mode 100644 index 00000000000..e49a654cd06 --- /dev/null +++ b/test/lisp/erc/resources/base/display-message/multibuf.eld @@ -0,0 +1,45 @@ +;; -*- mode: lisp-data; -*- +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") + (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network test= er") + (0.01 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running v= ersion ergo-v2.11.1") + (0.01 ":irc.foonet.org 003 tester :This server was created Sat, 14 Oct 20= 23 16:08:20 UTC") + (0.02 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.11.1 BERTZios CE= IMRUabefhiklmnoqstuv Iabefhkloqv") + (0.00 ":irc.foonet.org 005 tester AWAYLEN=3D390 BOT=3DB CASEMAPPING=3Dasc= ii CHANLIMIT=3D#:100 CHANMODES=3DIbe,k,fl,CEMRUimnstu CHANNELLEN=3D64 CHANT= YPES=3D# CHATHISTORY=3D1000 ELIST=3DU EXCEPTS EXTBAN=3D,m FORWARD=3Df INVEX= :are supported by this server") + (0.01 ":irc.foonet.org 005 tester KICKLEN=3D390 MAXLIST=3DbeI:60 MAXTARGE= TS=3D4 MODES MONITOR=3D100 NETWORK=3Dfoonet NICKLEN=3D32 PREFIX=3D(qaohv)~&= @%+ STATUSMSG=3D~&@%+ TARGMAX=3DNAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PR= IVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=3D390 UTF8ONLY WHOX :are sup= ported by this server") + (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=3D1000 :are supported= by this server") + (0.00 ":irc.foonet.org 251 tester :There are 0 users and 5 invisible on 1= server(s)") + (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online") + (0.00 ":irc.foonet.org 253 tester 0 :unregistered connections") + (0.00 ":irc.foonet.org 254 tester 2 :channels formed") + (0.00 ":irc.foonet.org 255 tester :I have 5 clients and 0 servers") + (0.00 ":irc.foonet.org 265 tester 5 5 :Current local users 5, max 5") + (0.02 ":irc.foonet.org 266 tester 5 5 :Current global users 5, max 5") + (0.01 ":irc.foonet.org 422 tester :MOTD File is missing") + (0.00 ":irc.foonet.org 221 tester +i") + (0.01 ":irc.foonet.org NOTICE tester :This server is in debug mode and is= logging all user I/O. If you do not wish for everything you send to be rea= dable by the server owner(s), please disconnect.")) + +((mode 10 "MODE tester +i") + (0.00 ":irc.foonet.org 221 tester +i")) + +((join 10 "JOIN #chan") + (0.03 ":tester!~u@HIDDEN JOIN #chan") + (0.03 ":irc.foonet.org 353 tester =3D #chan :@fsbot bob alice dummy teste= r") + (0.01 ":irc.foonet.org 366 tester #chan :End of NAMES list") + (0.00 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!") + (0.01 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) + +((mode 10 "MODE #chan") + (0.01 ":bob!~u@HIDDEN PRIVMSG #chan :alice: Persuade this rude= wretch willingly to die.") + (0.01 ":irc.foonet.org 324 tester #chan +Cnt") + (0.01 ":irc.foonet.org 329 tester #chan 1697299707") + (0.03 ":alice!~u@HIDDEN PRIVMSG #chan :bob: It might be yours = or hers, for aught I know.") + (0.07 ":bob!~u@HIDDEN PRIVMSG #chan :Would all themselves laug= h mortal.") + (0.04 ":dummy!~u@HIDDEN PRIVMSG tester :hi") + (0.06 ":bob!~u@HIDDEN PRIVMSG #chan :alice: It hath pleased th= e devil drunkenness to give place to the devil wrath; one unperfectness sho= ws me another, to make me frankly despise myself.") + (0.05 ":dummy!~u@HIDDEN QUIT :Quit: \2ERC\2 5.6-git (IRC clien= t for GNU Emacs 30.0.50)") + (0.08 ":alice!~u@HIDDEN PRIVMSG #chan :You speak of him when h= e was less furnished than now he is with that which makes him both without = and within.")) + +((quit 10 "QUIT :\2ERC\2") + (0.04 ":tester!~u@HIDDEN QUIT :Quit: \2ERC\2 5.x (IRC client f= or GNU Emacs)") + (0.02 "ERROR :Quit: \2ERC\2 5.x (IRC client for GNU Emacs)")) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-01-start.eld index 238d8cc73c2..8a6f2289f5d 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 27 (6)))) 350 3= 53 (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 1680332400 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-02-right.eld index d1ce9198e69..3eb4be4919b 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg notice = erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 183= (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefix= #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (i= nvisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix = #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wra= p-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-cm= d PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (6)))) 350 3= 53 (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 1680332400 field erc-timesta= mp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width = (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-p= refix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix = #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fie= ld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0= 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 480= (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7#= ) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# li= ne-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-prefi= x #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8#= display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg ms= g erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spac= e :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (w= rap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 erc= -cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) disp= lay #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (wr= ap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-p= refix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pre= fix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix #= 1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (er= c-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #13= =3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-prefi= x #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#) = 547 551 (wrap-prefix #1# line-prefix #13#)) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index d70184724ba..82c6d52cf7c 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-pref= ix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#)= 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6= =3D(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (= erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(spac= e :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wr= ap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 20= 2 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefi= x #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-p= refix #4=3D(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# lin= e-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg da= testamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp= wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(spac= e :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wr= ap-prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1#= line-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 = 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-pre= fix #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1= # line-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-= prefix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9= =3D"") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-= prefix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefi= x #8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTI= ON wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wr= ap-prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) = 500 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680= 332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 2= 7 0)) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 5= 11 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix = #1# line-prefix #11#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefi= x #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) = 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6=3D= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc= -msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(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 3= 15 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefix #= 3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-pref= ix #4=3D(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-p= refix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg dates= tamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp wr= ap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg msg = erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(space := width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wrap-= prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1# li= ne-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 475= (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-prefix= #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1# l= ine-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-pre= fix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd PRI= VMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9=3D= "") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-pre= fix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefix #= 8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION = wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wrap-= prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) 500= 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680332= 400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0= )) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 511 = 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix #1#= line-prefix #11#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index def97738ce6..84a1e34670c 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index be3e2b33cfd..83394f2f639 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index 098257d0b49..1605628b29f 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index def97738ce6..84a1e34670c 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space := width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field = erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin= ) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 1= 92 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pref= ix #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-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :widt= h (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pref= ix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (= wrap-prefix #1# line-prefix #4#)) diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/t= est/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 360b3dafafd..7a7e01de49d 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-= prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix = #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (lin= e-spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1= # line-prefix #3=3D(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 (wr= ap-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(space :width= (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefi= x #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (w= rap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg= msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :widt= h (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displ= ay #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap= -prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg un= known erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) = 468 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg unknown erc-ts 0= wrap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-= prefix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg= erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (-= 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #= 1# line-prefix #9#)) +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg notice erc-ts 0 wrap-prefix #1# line-p= refix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #= 2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((= margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (line= -spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1#= line-prefix #3=3D(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 (wra= p-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg m= sg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(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 (wr= ap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :width= (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displa= y #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap-= prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg not= ice erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) 46= 8 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg notice erc-ts 0 wr= ap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-pre= fix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg er= c-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (- 27= (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #1# = line-prefix #9#)) diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld index cd3537d3c94..bb248ffb28e 100644 --- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -1 +1 @@ -#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg unknown erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0= 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-time= stamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- = 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix = #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 = erc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font= -lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-p= refix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timest= amp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #= 4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line= -prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix= #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (er= c-msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invis= ible timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wra= p-prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #= 8# field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefi= x #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (w= rap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 3= 55 430 (wrap-prefix #1# line-prefix #7#)) \ No newline at end of file +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg notice erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0 = 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-times= tamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 2= 7 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix #= 2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font-= lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-pr= efix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timesta= mp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #4= #) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line-= prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix = #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (erc= -msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invisi= ble timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap= -prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #8= # field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefix= #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (wr= ap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 35= 5 430 (wrap-prefix #1# line-prefix #7#)) --=20 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 16 Oct 2023 14:08:25 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon Oct 16 10:08:25 2023 Received: from localhost ([127.0.0.1]:57456 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qsOGe-00035y-64 for submit <at> debbugs.gnu.org; Mon, 16 Oct 2023 10:08:25 -0400 Received: from mail-108-mta202.mxroute.com ([136.175.108.202]:44725) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qsOGY-00035l-Ds for 60936 <at> debbugs.gnu.org; Mon, 16 Oct 2023 10:08:22 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta202.mxroute.com (ZoneMTA) with ESMTPSA id 18b38d0777d000ff68.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Mon, 16 Oct 2023 14:07:48 +0000 X-Zone-Loop: 67765541b09cb16875a13ff9032d29532d5d2bb2f54c 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=xAe5tzuWuw3xU8amRYFnCe/uNrIbpCTgJSRRSwHRA78=; b=IicMoWu7RsFN8wTI43OX5HeeGY F+CiiTSG0e8XifRZM9OMo2AvsFBHiT6Z2L7hs98JF8ipMUQJq3UhEp6pEXax61iSXNXzXlviiulkX P5GMOqs8EbeM9/9CCQXz8vr4VkvItSoG6CTkUtT32X04PpDYpj9kdSjwGjS5ENDVPmQdaFPw3LhDc TIDlWOnqDQM0dEO9YjIioTkBzZtxy1pzczrl1o88SzgMmxdw5ak/Y08dtfAL/nt0ZtfOTbCSfnueX P/DKeRt1jTJjI0yZzyapwgb04YnOGXMuQ1DLyq+lIlooJoY1AeL25Ur00t3GZQookEnowUrovK4d2 QLatsL9g==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87h6mt87al.fsf@HIDDEN> (J. P.'s message of "Sat, 14 Oct 2023 10:04:18 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> <87h6mt87al.fsf@HIDDEN> Date: Mon, 16 Oct 2023 07:07:44 -0700 Message-ID: <8734yak6dr.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain "J.P." <jp@HIDDEN> writes: > These changes introduced a(t least one) bug. To reproduce, call > `erc-display-line' with a list of buffers, and notice only the first > sees its message inserted with the correct text properties. A quick way > to simulate this is by having two clients join the same two channels > and then having one quit. The expected text props will be missing from > one of the inserted > > *** someuser (n!~u@h) has quit > > messages. Verify by going to the first asterisk and doing C-u C-x =. > > Fix forthcoming. The second of the attached patches should hopefully do the trick. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Try-waiting-for-assertion-in-erc-scenarios-log.patch From 86efc480407711c4cf196eb497a0cf595ef1b5b7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 15 Oct 2023 13:43:12 -0700 Subject: [PATCH 1/2] ; Try waiting for assertion in erc-scenarios-log * test/lisp/erc/erc-scenarios-log.el (erc-scenarios-log--truncate): Attempt to fix intermittent test failure. * test/lisp/erc/resources/base/renick/queries/solo.eld: Timeouts. * test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld: Timeouts. * test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld: Timeouts. * test/lisp/erc/resources/erc-scenarios-common.el: Timeouts. --- test/lisp/erc/erc-scenarios-log.el | 2 +- test/lisp/erc/resources/base/renick/queries/solo.eld | 2 +- test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld | 2 +- test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld | 2 +- test/lisp/erc/resources/erc-scenarios-common.el | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenarios-log.el index f7e7d61c92e..9d3116d3db3 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -180,7 +180,7 @@ erc-scenarios-log--truncate (should-not (file-exists-p logserv)) (should-not (file-exists-p logchan)) (funcall expect 10 "*** MAXLIST=beI:60") - (should (= (pos-bol) (point-min))) + (erc-d-t-wait-for 5 (= (pos-bol) (point-min))) (should (file-exists-p logserv)))) (ert-info ("Log file ahead of truncation point") diff --git a/test/lisp/erc/resources/base/renick/queries/solo.eld b/test/lisp/erc/resources/base/renick/queries/solo.eld index 12fa7d264e9..fa4c075adac 100644 --- a/test/lisp/erc/resources/base/renick/queries/solo.eld +++ b/test/lisp/erc/resources/base/renick/queries/solo.eld @@ -30,7 +30,7 @@ (0 ":irc.foonet.org NOTICE tester :[09:56:57] 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.") (0 ":irc.foonet.org 305 tester :You are no longer marked as being away")) -((mode 1 "MODE #foo") +((mode 10 "MODE #foo") (0 ":irc.foonet.org 324 tester #foo +nt") (0 ":irc.foonet.org 329 tester #foo 1622454985") (0.1 ":alice!~u@HIDDEN PRIVMSG #foo :bob: Farewell, pretty lady: you must hold the credit of your father.") diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld index efc2506fd6f..d106a45cf66 100644 --- a/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld +++ b/test/lisp/erc/resources/base/reuse-buffers/channel/barnet.eld @@ -56,7 +56,7 @@ (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":joe!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620205534") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: Chi non te vede, non te pretia.") diff --git a/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld index a11cfac2e73..603afa2fc3e 100644 --- a/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld +++ b/test/lisp/erc/resources/base/reuse-buffers/channel/foonet.eld @@ -52,7 +52,7 @@ (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620205534") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: Thou desirest me to stop in my tale against the hair.") diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el index 5354b300b47..9e134e6932f 100644 --- a/test/lisp/erc/resources/erc-scenarios-common.el +++ b/test/lisp/erc/resources/erc-scenarios-common.el @@ -574,7 +574,7 @@ erc-scenarios-common--upstream-reconnect :password "changeme" :full-name "tester") (erc-scenarios-common-assert-initial-buf-name nil port) - (erc-d-t-wait-for 3 (eq (erc-network) 'foonet)) + (erc-d-t-wait-for 6 (eq (erc-network) 'foonet)) (erc-d-t-wait-for 3 (string= (buffer-name) "foonet")) (funcall expect 5 "foonet"))) @@ -713,7 +713,7 @@ erc-scenarios-common--join-network-id (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-foo)) (funcall expect 3 "<bob>") (erc-d-t-absent-for 0.1 "<joe>") - (funcall expect 10 "not given me"))) + (funcall expect 20 "not given me"))) (ert-info ("All #chan@barnet output received") (with-current-buffer chan-buf-bar -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Restore-missing-metadata-props-in-erc-display-li.patch From 5c3a1e966876d8d25e3916c0cde21d387e995014 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 15 Oct 2023 17:22:22 -0700 Subject: [PATCH 2/2] [5.6] Restore missing metadata props in erc-display-line * etc/ERC-NEWS: Mention `erc-display-message' as favored means of inserting messages. * lisp/erc/erc-stamp.el (erc-stamp--current-time): Use an existing `erc-ts' text property, when present, for the current message time. * lisp/erc/erc.el (erc-display-line): Update doc string. Copy `erc--msg-props' hash table when inserting a message in multiple buffers. At present, only `erc-server-QUIT' uses this facility. Also, improve readability with at most one recursive call for the fall-through case. (erc-display-message): Update doc string. * test/lisp/erc/erc-scenarios-display-message.el: New file. * test/lisp/erc/erc-tests.el (erc-display-line): New test. * test/lisp/erc/resources/base/display-message/multibuf.eld: New test data. (Bug#60936) --- etc/ERC-NEWS | 11 +++ lisp/erc/erc-stamp.el | 4 +- lisp/erc/erc.el | 67 +++++++++++-------- .../lisp/erc/erc-scenarios-display-message.el | 64 ++++++++++++++++++ test/lisp/erc/erc-tests.el | 62 +++++++++++++++++ .../base/display-message/multibuf.eld | 45 +++++++++++++ 6 files changed, 224 insertions(+), 29 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-display-message.el create mode 100644 test/lisp/erc/resources/base/display-message/multibuf.eld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 2e56539f210..404d735b9f6 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -288,6 +288,17 @@ ERC also provisionally reserves the same depth interval for continue to modify non-ERC hooks locally whenever possible, especially in new code. +*** ERC strongly favors 'erc-display-message' for message insertion. +Although less common these days, folks still sometimes resort to using +the insertion function 'erc-display-line' because it's admittedly less +awkward than the supposedly higher level 'erc-display-message'. Thus, +ancient patterns, like preformatting text with 'erc-make-notice', +still occasionally appear in newer code. However, beginning in ERC +5.6, certain preparatory business necessary for the eventual move to a +richer UI has taken up residence in 'erc-display-message'. If you +find this development disturbing, by all means voice your concerns on +the tracker. (Patches for user-friendly wrappers are most welcome.) + *** ERC now manages timestamp-related properties a bit differently. For starters, the 'cursor-sensor-functions' text property is absent by default unless the option 'erc-echo-timestamps' is already enabled on diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 394643c03cb..57fd7f39e50 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -219,7 +219,9 @@ erc-stamp--current-time (erc-compat--current-lisp-time)) (cl-defmethod erc-stamp--current-time :around () - (or erc-stamp--current-time (cl-call-next-method))) + (or erc-stamp--current-time + (and erc--msg-props (gethash 'erc-ts erc--msg-props)) + (cl-call-next-method))) (defvar erc-stamp--skip nil "Non-nil means inhibit `erc-add-timestamp' completely.") diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 5bf6496e926..7edf735eb43 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3092,36 +3092,46 @@ erc-is-valid-nick-p (string-match (concat "\\`" erc-valid-nick-regexp "\\'") nick)) (defun erc-display-line (string &optional buffer) - "Display STRING in the ERC BUFFER. -All screen output must be done through this function. If BUFFER is nil -or omitted, the default ERC buffer for the `erc-session-server' is used. -The BUFFER can be an actual buffer, a list of buffers, `all' or `active'. -If BUFFER = `all', the string is displayed in all the ERC buffers for the -current session. `active' means the current active buffer -\(`erc-active-buffer'). If the buffer can't be resolved, the current -buffer is used. `erc-display-line-1' is used to display STRING. - -If STRING is nil, the function does nothing." - (let (new-bufs) + "Insert STRING in BUFFER. +Expect BUFFER to be a live `erc-mode' buffer, a list of such +buffers, or the symbols `all' or `active'. If `all', insert +STRING in all buffers for the current session. If `active', +defer to the function `erc-active-buffer', which may return the +session's server buffer if the previously active buffer has been +killed. If BUFFER is nil or a network process, pretend it's set +to the appropriate server buffer. Otherwise, use the current +buffer. + +In most cases, expect to be called from a higher-level insertion +function, like `erc-display-message', especially when modules +should consider STRING as a candidate for formatting with +indentation, fontification, timestamping, etc. Otherwise, allow +built-in modules to ignore STRING, which may make it appear +incongruous in situ (unless anticipated by third-party hook +members or otherwise preformatted)." + (let (seen msg-props) (dolist (buf (cond ((bufferp buffer) (list buffer)) - ((listp buffer) buffer) + ((consp buffer) + (setq msg-props erc--msg-props) + buffer) ((processp buffer) (list (process-buffer buffer))) ((eq 'all buffer) ;; Hmm, or all of the same session server? (erc-buffer-list nil erc-server-process)) - ((and (eq 'active buffer) (erc-active-buffer)) - (list (erc-active-buffer))) + ((and-let* (((eq 'active buffer)) + (b (erc-active-buffer))) + (list b))) ((erc-server-buffer-live-p) (list (process-buffer erc-server-process))) (t (list (current-buffer))))) (when (buffer-live-p buf) + (when msg-props + (setq erc--msg-props (copy-hash-table msg-props))) (erc-display-line-1 string buf) - (push buf new-bufs))) - (when (null new-bufs) - (erc-display-line-1 string (if (erc-server-buffer-live-p) - (process-buffer erc-server-process) - (current-buffer)))))) + (setq seen t))) + (unless (or seen (null buffer)) + (erc-display-line string nil)))) (defvar erc--compose-text-properties nil "Non-nil when `erc-put-text-property' defers to `erc--merge-prop'.") @@ -3432,14 +3442,15 @@ erc-display-message Insert MSG or text derived from MSG into an ERC buffer, possibly after applying formatting by way of either a `format-spec' known to a message-catalog entry or a TYPE known to a specialized -string handler. Additionally, derive internal metadata, faces, -and other text properties from the various overloaded parameters, -such as PARSED, when it's an `erc-response' object, and MSG, when -it's a key (symbol) for a \"message catalog\" entry. Expect -ARGS, when applicable, to be `format-spec' args known to such an -entry, and TYPE, when non-nil, to be a symbol handled by +string handler. Additionally, derive metadata, faces, and other +text properties from the various overloaded parameters, such as +PARSED, when it's an `erc-response' object, and MSG, when it's a +key (symbol) for a \"message catalog\" entry. Expect ARGS, when +applicable, to be `format-spec' args known to such an entry, and +TYPE, when non-nil, to be a symbol handled by `erc-display-message-highlight' (necessarily accompanied by a -string MSG). +string MSG). Expect BUFFER to be among the sort accepted by the +function `erc-display-line'. When TYPE is a list of symbols, call handlers from left to right without influencing how they behave when encountering existing @@ -3455,8 +3466,8 @@ erc-display-message `erc-display-line' when it's important that insert hooks treat MSG in a manner befitting messages received from a server. That is, expect to process most nontrivial informational messages, for -which PARSED is typically nil, when the caller desires -buttonizing and other effects." +which PARSED is typically nil, when the caller desires the +inserted message to feature buttonizing and other effects." (let ((string (if (symbolp msg) (apply #'erc-format-message msg args) msg)) diff --git a/test/lisp/erc/erc-scenarios-display-message.el b/test/lisp/erc/erc-scenarios-display-message.el new file mode 100644 index 00000000000..51bdf305ad5 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-display-message.el @@ -0,0 +1,64 @@ +;;; erc-scenarios-display-message.el --- erc-display-message -*- 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))) + +(ert-deftest erc-scenarios-display-message--multibuf () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/display-message") + (dumb-server (erc-d-run "localhost" t 'multibuf)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (erc-modules (cons 'fill-wrap erc-modules)) + (erc-autojoin-channels-alist '((foonet "#chan"))) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :full-name "tester") + (funcall expect 10 "debug mode"))) + + (ert-info ("User dummy is a member of #chan") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (funcall expect 10 "dummy"))) + + (ert-info ("Dummy's QUIT notice in query contains metadata props") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "dummy")) + (funcall expect 10 "<dummy> hi") + (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg))))) + + (ert-info ("Dummy's QUIT notice in #chan contains metadata props") + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (funcall expect 10 "*** dummy (~u@HIDDEN) has quit") + (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg))))) + + (erc-cmd-QUIT ""))) + +(eval-when-compile (require 'erc-join)) + +;;; erc-scenarios-display-message.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 4f4662f5075..b35afaa552f 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1938,6 +1938,68 @@ erc-format-privmessage 2 5 (erc-speaker "Bob" font-lock-face erc-nick-default-face) 5 12 (font-lock-face erc-default-face)))))) +(ert-deftest erc-display-line () + (erc-tests--send-prep) + (erc-tests--set-fake-server-process "sleep" "1") + (setq erc-networks--id (erc-networks--id-create 'foonet)) + + (let ((server-buffer (current-buffer)) + (spam-buffer (save-excursion (erc--open-target "#spam"))) + (chan-buffer (save-excursion (erc--open-target "#chan"))) + calls) + (cl-letf (((symbol-function 'erc-display-line-1) + (lambda (&rest r) (push (cons 'line-1 r) calls)))) + + (with-current-buffer chan-buffer + + (ert-info ("Null `buffer' routes to live server-buffer") + (erc-display-line "null" nil) + (should (equal (pop calls) `(line-1 "null" ,server-buffer))) + (should-not calls)) + + (ert-info ("Cons `buffer' routes to live members") + ;; Copies a let-bound `erc--msg-props' before mutating. + (let* ((table (map-into '(erc-msg msg) 'hash-table)) + (erc--msg-props table)) + (erc-display-line "cons" (list server-buffer spam-buffer)) + (should-not (eq table erc--msg-props))) + (should (equal (pop calls) `(line-1 "cons" ,spam-buffer))) + (should (equal (pop calls) `(line-1 "cons" ,server-buffer))) + (should-not calls)) + + (ert-info ("Variant `all' inserts in all session buffers") + (erc-display-line "all" 'all) + (should (equal (pop calls) `(line-1 "all" ,chan-buffer))) + (should (equal (pop calls) `(line-1 "all" ,spam-buffer))) + (should (equal (pop calls) `(line-1 "all" ,server-buffer))) + (should-not calls)) + + (ert-info ("Variant `active' routes to active buffer if alive") + (should (eq chan-buffer (erc-with-server-buffer erc-active-buffer))) + (erc-set-active-buffer spam-buffer) + (erc-display-line "act" 'active) + (should (equal (pop calls) `(line-1 "act" ,spam-buffer))) + (should (eq (erc-active-buffer) spam-buffer)) + (should-not calls)) + + (ert-info ("Variant `active' falls back to current buffer") + (should (eq spam-buffer (erc-active-buffer))) + (kill-buffer "#spam") + (erc-display-line "nact" 'active) + (should (equal (pop calls) `(line-1 "nact" ,server-buffer))) + (should (eq (erc-with-server-buffer erc-active-buffer) + server-buffer)) + (should-not calls)) + + (ert-info ("Dead single buffer defaults to live server-buffer") + (should-not (get-buffer "#spam")) + (erc-display-line "dead" 'spam-buffer) + (should (equal (pop calls) `(line-1 "dead" ,server-buffer))) + (should-not calls)))) + + (should-not (buffer-live-p spam-buffer)) + (kill-buffer chan-buffer))) + (defvar erc-tests--ipv6-examples '("1:2:3:4:5:6:7:8" "::ffff:10.0.0.1" "::ffff:1.2.3.4" "::ffff:0.0.0.0" diff --git a/test/lisp/erc/resources/base/display-message/multibuf.eld b/test/lisp/erc/resources/base/display-message/multibuf.eld new file mode 100644 index 00000000000..e49a654cd06 --- /dev/null +++ b/test/lisp/erc/resources/base/display-message/multibuf.eld @@ -0,0 +1,45 @@ +;; -*- mode: lisp-data; -*- +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") + (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") + (0.01 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version ergo-v2.11.1") + (0.01 ":irc.foonet.org 003 tester :This server was created Sat, 14 Oct 2023 16:08:20 UTC") + (0.02 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.11.1 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv") + (0.00 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# CHATHISTORY=1000 ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX :are supported by this server") + (0.01 ":irc.foonet.org 005 tester KICKLEN=390 MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8ONLY WHOX :are supported by this server") + (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=1000 :are supported by this server") + (0.00 ":irc.foonet.org 251 tester :There are 0 users and 5 invisible on 1 server(s)") + (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online") + (0.00 ":irc.foonet.org 253 tester 0 :unregistered connections") + (0.00 ":irc.foonet.org 254 tester 2 :channels formed") + (0.00 ":irc.foonet.org 255 tester :I have 5 clients and 0 servers") + (0.00 ":irc.foonet.org 265 tester 5 5 :Current local users 5, max 5") + (0.02 ":irc.foonet.org 266 tester 5 5 :Current global users 5, max 5") + (0.01 ":irc.foonet.org 422 tester :MOTD File is missing") + (0.00 ":irc.foonet.org 221 tester +i") + (0.01 ":irc.foonet.org NOTICE tester :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.")) + +((mode 10 "MODE tester +i") + (0.00 ":irc.foonet.org 221 tester +i")) + +((join 10 "JOIN #chan") + (0.03 ":tester!~u@HIDDEN JOIN #chan") + (0.03 ":irc.foonet.org 353 tester = #chan :@fsbot bob alice dummy tester") + (0.01 ":irc.foonet.org 366 tester #chan :End of NAMES list") + (0.00 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!") + (0.01 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) + +((mode 10 "MODE #chan") + (0.01 ":bob!~u@HIDDEN PRIVMSG #chan :alice: Persuade this rude wretch willingly to die.") + (0.01 ":irc.foonet.org 324 tester #chan +Cnt") + (0.01 ":irc.foonet.org 329 tester #chan 1697299707") + (0.03 ":alice!~u@HIDDEN PRIVMSG #chan :bob: It might be yours or hers, for aught I know.") + (0.07 ":bob!~u@HIDDEN PRIVMSG #chan :Would all themselves laugh mortal.") + (0.04 ":dummy!~u@HIDDEN PRIVMSG tester :hi") + (0.06 ":bob!~u@HIDDEN PRIVMSG #chan :alice: It hath pleased the devil drunkenness to give place to the devil wrath; one unperfectness shows me another, to make me frankly despise myself.") + (0.05 ":dummy!~u@HIDDEN QUIT :Quit: \2ERC\2 5.6-git (IRC client for GNU Emacs 30.0.50)") + (0.08 ":alice!~u@HIDDEN PRIVMSG #chan :You speak of him when he was less furnished than now he is with that which makes him both without and within.")) + +((quit 10 "QUIT :\2ERC\2") + (0.04 ":tester!~u@HIDDEN QUIT :Quit: \2ERC\2 5.x (IRC client for GNU Emacs)") + (0.02 "ERROR :Quit: \2ERC\2 5.x (IRC client for GNU Emacs)")) -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 14 Oct 2023 17:04:57 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Sat Oct 14 13:04:57 2023 Received: from localhost ([127.0.0.1]:50327 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qri4P-0002XP-1p for submit <at> debbugs.gnu.org; Sat, 14 Oct 2023 13:04:57 -0400 Received: from mail-108-mta42.mxroute.com ([136.175.108.42]:40187) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qri4J-0002X6-5O for 60936 <at> debbugs.gnu.org; Sat, 14 Oct 2023 13:04:55 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta42.mxroute.com (ZoneMTA) with ESMTPSA id 18b2f2568c4000ff68.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sat, 14 Oct 2023 17:04:22 +0000 X-Zone-Loop: c2f3284b99c70e0371cd561f56c012b178863eb04041 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=MEe1+SnR+l/yG2RgbCy5TLeZzWmKiGNh4JLYvLS/tQA=; b=F+gnJLLrDAn1PQMZ8wU6Ce0KVK QTRabz/Sz4Q7WWMDVl+KEAlvCWSsMiU2QLjWsPGVAcBPA5ACjKjF6hvzehyKOLlVIYzl5CpbiG1nn Iq6DXrX5hzMxnqLBajgt46jErkmw1JBT8L2fu3ocLwKA3XAbTGEqlPHy4zbIzPy5Qsx0nuo2d6vFC ghihSnQRxJGWNgM+CpqP2/+tnQVjy5WCJ/dXPPjWVAT0fyw8ZqjK+ZPpwF+RvJ6BxsYDrdR1W2rOk yExDO88LluKQQWgMTlKILZcU9G3TEddBXhyqrIHzUaWnlLuLZUrrTIyJeVBuR3YLkM8Ru4Hp8Eq4l mp8ZoOoQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87cyxi9hlc.fsf@HIDDEN> (J. P.'s message of "Fri, 13 Oct 2023 17:24:15 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> <87cyxi9hlc.fsf@HIDDEN> Date: Sat, 14 Oct 2023 10:04:18 -0700 Message-ID: <87h6mt87al.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > I've added these changes as > > https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=c68dc778 > > Although I've done so with zero discussion, as usual, others can perhaps > take some comfort in knowing that this semi-major overhaul only reaches > as far back as the latest release (but not into it). Thanks. These changes introduced a(t least one) bug. To reproduce, call `erc-display-line' with a list of buffers, and notice only the first sees its message inserted with the correct text properties. A quick way to simulate this is by having two clients join the same two channels and then having one quit. The expected text props will be missing from one of the inserted *** someuser (n!~u@h) has quit messages. Verify by going to the first asterisk and doing C-u C-x =. Fix forthcoming.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 14 Oct 2023 00:24:49 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Fri Oct 13 20:24:49 2023 Received: from localhost ([127.0.0.1]:47577 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qrSSW-00076y-UC for submit <at> debbugs.gnu.org; Fri, 13 Oct 2023 20:24:49 -0400 Received: from mail-108-mta116.mxroute.com ([136.175.108.116]:40683) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qrSSU-00076l-Ma for 60936 <at> debbugs.gnu.org; Fri, 13 Oct 2023 20:24:47 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta116.mxroute.com (ZoneMTA) with ESMTPSA id 18b2b91d372000ff68.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sat, 14 Oct 2023 00:24:19 +0000 X-Zone-Loop: 8cefc3d886557aa35c9b9978f2f1a425f60ee54a5091 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=lrDvg2sEo60JXf+BYs1B5Uj9eeSVrgUzIC+viB3Sxlc=; b=krld9Yve5k0Bs8swLkDcOWOfuB +UUSUzo3wS8rxdtIQHr31lSDv6SajQw6FN3hqBJve1z2duid6qJrL6H++6OEj6htF8Ne5pQtwAeXQ 3wdgT53YBIkHrUYhQbhs+B3o2WpVdia/Vkkll9j1Pc04BgZUGOxgDs9lHeZV7FpYqTI0CidCil6ns novPVea9cfPcYmAFI85jARjIrwjLk55NJ5nZcjBzPvXHtX9Khtiflat2dQPr74uSmBHhfhu2gAAte 4rYb3RlDztIJ1meA7HFpG5R7RTW/JcdAKmwzhqxZFs3zLx7PqoQYldWRP/ahCNkB2rs1MfWRjCPSZ /ShY7kYQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <874jj3ok58.fsf@HIDDEN> (J. P.'s message of "Fri, 06 Oct 2023 08:17:23 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> <874jj3ok58.fsf@HIDDEN> Date: Fri, 13 Oct 2023 17:24:15 -0700 Message-ID: <87cyxi9hlc.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) I've added these changes as https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=c68dc778 Although I've done so with zero discussion, as usual, others can perhaps take some comfort in knowing that this semi-major overhaul only reaches as far back as the latest release (but not into it). Thanks.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 6 Oct 2023 15:17:55 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Fri Oct 06 11:17:55 2023 Received: from localhost ([127.0.0.1]:52402 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qomaQ-0004gn-UK for submit <at> debbugs.gnu.org; Fri, 06 Oct 2023 11:17:55 -0400 Received: from mail-108-mta233.mxroute.com ([136.175.108.233]:39875) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qomaP-0004gf-G9 for 60936 <at> debbugs.gnu.org; Fri, 06 Oct 2023 11:17:53 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta233.mxroute.com (ZoneMTA) with ESMTPSA id 18b0590a8460004ae0.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 06 Oct 2023 15:17:28 +0000 X-Zone-Loop: 6ec0fb116c7ccfe65d1774d139f3a1d725feff079e75 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=59qvtcj4fqPnuiUhGgeWU1hYeTv4NTHcb0JoltIReZw=; b=OOAJySrbg5MeQW+6uZJWjiHH7u W4C+kh+g95ZKvgYN2EjdyuNnuQUG4xQfxBEEA1ZeL/5B5cbcbd+Al0x4rDWPiJlo1LLinkiEPQtU3 qjhy7O/FPl2YHs/ySSNPCmlVB760TjqnRJlGNBDCUxJsAEYRLuhiRilPFgoeguPzcVLo3EZPpp6Ih HwwOR/QSIMOOp2PrAwn5A3I+ZwgNPnsNyjVj7R1Oyvdesi9Q4i/AvkkEHjXH6QDhbsfe97jMJVal2 aJKwtfEaPYm8bFOtQ87uUJY4s0mlDZXbAV3TQZWzxrUlC+yi5GaJKoddQjDVFb7NpH2wWlHpHbXpu CWF95lCA==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87pm23yawb.fsf@HIDDEN> (J. P.'s message of "Wed, 27 Sep 2023 06:59:48 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> <87pm23yawb.fsf@HIDDEN> Date: Fri, 06 Oct 2023 08:17:23 -0700 Message-ID: <874jj3ok58.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v3. Move new meta-data related text properties to a single-character interval at the head of every message. Add facility for managing such props on behalf of modification hooks. Add utilities for retrieving data from message-delimiting props and for traversing inserted messages. In an attempt to tamp down on the growing mound of complications involved in wrangling text properties across modules, I'm proposing a general facility for managing certain props going forward. It works as follows: 1. confine meta-data related props to a one-char interval that, along with a preceding newline, delimit all message boundaries [1] 2. apply nonessential message-spanning props, like `cursor-sensor-functions', lazily and only as needed by their controlling options [2] 3. offer a means of passing state between hook stages, optionally to end up as properties in the meta-data interval 4. keep this mechanism internal for the time being, but have it manage most props introduced in 5.6 In some ways, this amounts to a major reworking of how ERC handles messages during and after insertion. Initially, I wanted to defer such an endeavor to 5.7, but it's become clear to me that doing this now will immensely fortify the implementation of various features shipping with this release. If you're a module author or would-be contributor, it's in your interest to keep an eye on how this unfolds. Happy to answer questions or concerns, as always. Thanks. [1] In an ideal world, a message's properties would live on its preceding newline. However, ERC's hooks have always visited messages along with their trailing newline. Obviously, having hooks see properties for the message to follow (or having the current message's props live on its trailing newline) would never work. [2] Props whose intervals inform their role, such as buttons, faces, and display/formatting attributes, can't easily conform to this system. But, we can still benefit from formally declaring the hook stage (and maybe specific depth range) at which such props should be added. For example, message-spanning props ought to be applied no earlier than post-modification (e.g., `erc-send-post-hook' and `erc-insert-post-hook'). --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v2-v3.diff Content-Transfer-Encoding: quoted-printable From fcb34a45afd872361b0dbc8e6bd92ba53b910faa Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 6 Oct 2023 06:52:03 -0700 Subject: [PATCH 0/7] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (7): [5.6] Allow spoofing process marker in erc-display-line-1 [5.6] Honor nil values in erc--restore-initialize-priors [5.6] Preserve format-spec args in erc-server-JOIN [5.6] Deprecate option erc-remove-parsed-property [5.6] Add helper for removing list-valued text props in ERC [5.6] Manage meta-data text props for ERC hook members [5.6] Add command to refill buffer with erc-fill-wrap-mode etc/ERC-NEWS | 36 ++- lisp/erc/erc-backend.el | 11 +- lisp/erc/erc-fill.el | 167 ++++++++---- lisp/erc/erc-goodies.el | 4 +- lisp/erc/erc-stamp.el | 237 ++++++++++++++---- lisp/erc/erc-truncate.el | 2 +- lisp/erc/erc.el | 223 +++++++++++++--- test/lisp/erc/erc-fill-tests.el | 78 ++++-- test/lisp/erc/erc-scenarios-log.el | 1 + test/lisp/erc/erc-scenarios-match.el | 205 ++++++++++++--- test/lisp/erc/erc-stamp-tests.el | 2 +- test/lisp/erc/erc-tests.el | 229 ++++++++++++++++- .../resources/base/assoc/multi-net/barnet.eld | 12 +- .../resources/base/assoc/multi-net/foonet.eld | 12 +- .../base/netid/bouncer/barnet-drop.eld | 4 +- .../base/netid/bouncer/foonet-drop.eld | 4 +- .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 25 files changed, 992 insertions(+), 253 deletions(-) Interdiff: diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index a8f7ee8a944..81c94467f25 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -153,13 +153,9 @@ easily determining what right-sided stamps would look = like before insertion, which is knowledge needed for certain UI decisions. The way ERC has chosen to address this is imperfect and boils down to asking users who've customized this option to switch to -'erc-timestamp-format' instead. Somewhat relatedly, the companion -option 'erc-timestamp-format-left', which determines the look of date -stamps, must now end in a newline. Although this has long been the -case in practice, it's now been made official. As always, if you're -affected by these changes and feel that other solutions, like -automatic migration, are justified, please make that known on the bug -list. +'erc-timestamp-format' instead. If you're affected by this and feel +that some other solution, like automatic migration, is justified, +please make that known on the bug list. =20 ** 'erc-button-alist' and 'erc-nick-popup-alist' have evolved slightly. It's no secret that the 'buttons' module treats potential nicknames @@ -225,6 +221,14 @@ atop any message. The new companion option 'erc-echo-= timestamp-zone' determines the default timezone when not specified with a prefix argument. =20 +** Option 'erc-remove-parsed-property' deprecated. +This option's nil behavior serves no practical purpose yet has the +potential to degrade the user experience by competing for space with +forthcoming features powered by next generation extensions. Anyone +with a legitimate use for this option likely also possesses the +knowledge to rig up a suitable analog with minimal effort. That said, +the road to removal is long. + ** Option 'erc-warn-about-blank-lines' is more informative. Enabled by default, this option now produces more useful feedback whenever ERC rejects prompt input containing whitespace-only lines. @@ -287,11 +291,13 @@ continue to modify non-ERC hooks locally whenever pos= sible, especially in new code. =20 *** ERC now manages timestamp-related properties a bit differently. -For starters, the 'cursor-sensor-functions' property no longer +For starters, the 'cursor-sensor-functions' text property is absent by +default unless the option 'erc-echo-timestamps' is already enabled on +module init. And when present, the property's value no longer contains unique closures and thus no longer proves effective for -traversing messages. To compensate, a new property, 'erc-timestamp', -now spans message bodies but not the newlines delimiting them. Also -affecting the 'stamp' module is the deprecation of the function +traversing inserted messages. For now, ERC only provides an internal +means of visiting messages, but a public interface is forthcoming. +Also affecting the 'stamp' module is the deprecation of the function 'erc-insert-aligned' and its removal from client code. Additionally, the module now merges its 'invisible' property with existing ones and includes all white space around stamps when doing so. @@ -306,6 +312,22 @@ folded onto the next line. Such inconsistency made st= amp detection overly complex and produced uneven results when toggling stamp visibility. =20 +*** Date stamps are independent messages. +ERC now inserts "date stamps" generated from the option +'erc-timestamp-format-left' as separate, standalone messages. (This +only matters if 'erc-insert-timestamp-function' is set to its default +value of 'erc-insert-timestamp-left-and-right'.) ERC's near-term UI +goals require exposing these stamps to existing code designed to +operate on complete messages. For example, users likely expect date +stamps to be togglable with 'erc-toggle-timestamps' while also being +immune to hiding from commands like 'erc-match-toggle-hidden-fools'. +Before this change, meeting such expectations demanded brittle +heuristics that checked for the presence of these stamps in the +leading portion of message bodies as well as special casing to act on +these areas without inflicting collateral damage. From now on, third +parties can instead use the function 'erc-stamp-date-left-p' to detect +and reuse existing code to operate. + *** The role of a module's Custom group is now more clearly defined. Associating built-in modules with Custom groups and provided library features has improved. More specifically, a module's group now enjoys diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index fb10ee31c78..bc42917375a 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1718,7 +1718,7 @@ erc--server-determine-join-display-context (if (string-match "^\\(.*\\)\^g.*$" chnl) (setq chnl (match-string 1 chnl))) (save-excursion - (let* ((str (cond + (let ((args (cond ;; If I have joined a channel ((erc-current-nick-p nick) (let ((erc--display-context @@ -1735,18 +1735,15 @@ erc--server-determine-join-display-context (erc-channel-begin-receiving-names)) (erc-update-mode-line) (run-hooks 'erc-join-hook) - (erc-make-notice - (erc-format-message 'JOIN-you ?c chnl))) + (list 'JOIN-you ?c chnl)) (t (setq buffer (erc-get-buffer chnl proc)) - (erc-make-notice - (erc-format-message - 'JOIN ?n nick ?u login ?h host ?c chnl)))))) + (list 'JOIN ?n nick ?u login ?h host ?c chnl))))) (when buffer (set-buffer buffer)) (erc-update-channel-member chnl nick nick t nil nil nil nil nil = host login) ;; on join, we want to stay in the new channel buffer ;;(set-buffer ob) - (erc-display-message parsed nil buffer str)))))) + (apply #'erc-display-message parsed 'notice buffer args)))))) =20 (define-erc-response-handler (KICK) "Handle kick messages received from the server." nil diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 608119c8d6e..8b86cf30bf4 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -158,6 +158,11 @@ erc-fill (when (or erc-fill--function erc-fill-function) ;; skip initial empty lines (goto-char (point-min)) + ;; Note the following search pattern was altered in 5.6 to adapt + ;; to a change in Emacs regexp behavior that turned out to be a + ;; regression (which has since been fixed). The patterns appear + ;; to be equivalent in practice, so this was left as is (wasn't + ;; reverted) to avoid additional git-blame(1)-related churn. (while (and (looking-at (rx bol (* (in " \t")) eol)) (zerop (forward-line 1)))) (unless (eobp) @@ -167,12 +172,10 @@ erc-fill (when-let* ((erc-fill-line-spacing) (p (point-min))) (widen) - (when (or (and-let* ((cmd (get-text-property p 'erc-command))) - (memq cmd erc-fill--spaced-commands)) + (when (or (erc--check-msg-prop 'erc-cmd erc-fill--spaced-comma= nds) (and-let* ((cmd (save-excursion (forward-line -1) - (get-text-property (point) - 'erc-command)))) + (get-text-property (point) 'erc-cm= d)))) (memq cmd erc-fill--spaced-commands))) (put-text-property (1- p) p 'line-spacing erc-fill-line-spacing))))))= )) @@ -181,15 +184,17 @@ erc-fill-static "Fills a text such that messages start at column `erc-fill-static-center= '." (save-restriction (goto-char (point-min)) - (looking-at "^\\(\\S-+\\)") - (let ((nick (match-string 1))) + (when-let (((looking-at "^\\(\\S-+\\)")) + ((not (erc--check-msg-prop 'erc-msg 'datestamp))) + (nick (match-string 1))) + (progn (let ((fill-column (- erc-fill-column (erc-timestamp-offset))) (fill-prefix (make-string erc-fill-static-center 32))) (insert (make-string (max 0 (- erc-fill-static-center (length nick) 1)) 32)) (erc-fill-regarding-timestamp)) - (erc-restore-text-properties)))) + (erc-restore-text-properties))))) =20 (defun erc-fill-variable () "Fill from `point-min' to `point-max'." @@ -423,8 +428,6 @@ fill-wrap (eq (default-value 'erc-insert-timestamp-function) #'erc-insert-timestamp-left))) (setq erc-fill--function #'erc-fill-wrap) - (add-function :after (local 'erc-stamp--insert-date-function) - #'erc-fill--wrap-stamp-insert-prefixed-date) (when erc-fill-wrap-merge (add-hook 'erc-button--prev-next-predicate-functions #'erc-fill--wrap-merged-button-p nil t)) @@ -436,9 +439,7 @@ fill-wrap (kill-local-variable 'erc-fill--function) (kill-local-variable 'erc-fill--wrap-visual-keys) (remove-hook 'erc-button--prev-next-predicate-functions - #'erc-fill--wrap-merged-button-p t) - (remove-function (local 'erc-stamp--insert-date-function) - #'erc-fill--wrap-stamp-insert-prefixed-date)) + #'erc-fill--wrap-merged-button-p t)) 'local) =20 (defvar-local erc-fill--wrap-length-function nil @@ -456,6 +457,9 @@ erc-fill--wrap-last-msg (defvar-local erc-fill--wrap-max-lull (* 24 60 60)) =20 (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\"." (prog1 (and-let* ((m (or erc-fill--wrap-last-msg (setq erc-fill--wrap-last-msg (point-min-marker)) @@ -463,14 +467,11 @@ erc-fill--wrap-continued-message-p ((< (1+ (point-min)) (- (point) 2))) (props (save-restriction (widen) - (when (eq 'erc-timestamp (field-at-pos m)) - (set-marker m (field-end m))) (and-let* - (((eq 'PRIVMSG (get-text-property m 'erc-comman= d))) - ((not (eq (get-text-property m 'erc-ctcp) - 'ACTION))) + (((eq 'PRIVMSG (get-text-property m 'erc-cmd))) + ((not (eq (get-text-property m 'erc-msg) 'ACTI= ON))) (spr (next-single-property-change m 'erc-speak= er))) - (cons (get-text-property m 'erc-timestamp) + (cons (get-text-property m 'erc-ts) (get-text-property spr 'erc-speaker))))) (ts (pop props)) (props) @@ -478,7 +479,7 @@ erc-fill--wrap-continued-message-p ((time-less-p (time-subtract (erc-stamp--current-time) ts) erc-fill--wrap-max-lull)) (speaker (next-single-property-change (point-min) 'erc-speak= er)) - ((not (eq (get-text-property speaker 'erc-ctcp) 'ACTION))) + ((not (erc--check-msg-prop 'erc-ctcp 'ACTION))) (nick (get-text-property speaker 'erc-speaker)) ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) @@ -491,27 +492,11 @@ erc-fill--wrap-measure (save-excursion (save-restriction (narrow-to-region beg end) - (let (buffer-invisibility-spec) - (list (car (buffer-text-pixel-size)))))) + (let* ((buffer-invisibility-spec) + (rv (car (buffer-text-pixel-size)))) + (if (zerop rv) 0 (list rv))))) (- end beg))) =20 -(defun erc-fill--wrap-stamp-insert-prefixed-date (&rest _) - "Apply `line-prefix' property to args. -Expect a multiline \"date\" stamp ending in a newline, similar to -the default value of `erc-timestamp-format-left'. Omit the -`line-prefix' from any trailing newlines." - (let* ((beg) - ;; Insert " " to simulate gap between <speaker> and msg beg. - (end (save-excursion (skip-chars-backward "\n") - (setq beg (pos-bol)) - (insert " ") - (point))) - (width (erc-fill--wrap-measure beg end))) - (delete-region (1- end) end) - ;; Use `point-min' instead of `beg' to cover leading newilnes. - (put-text-property (point-min) (1- end) 'line-prefix - `(space :width (- erc-fill--wrap-value ,width))))) - ;; An escape hatch for third-party code expecting speakers of ACTION ;; messages to be exempt from `line-prefix'. This could be converted ;; into a user option if users feel similarly. @@ -531,15 +516,22 @@ erc-fill-wrap (when-let ((e (erc--get-speaker-bounds)) (b (pop e)) ((or erc-fill--wrap-action-dedent-p - (not (eq (get-text-property b 'erc-ct= cp) - 'ACTION))))) + (not (erc--check-msg-prop 'erc-ctcp + 'ACTION))))) (goto-char e)) (skip-syntax-forward "^-") (forward-char) - ;; Using the `invisible' property might make more - ;; sense, but that would require coordination - ;; with other modules, like `erc-match'. - (cond ((and erc-fill-wrap-merge + (cond ((erc--check-msg-prop 'erc-msg 'datestamp) + (when erc-fill--wrap-last-msg + (set-marker erc-fill--wrap-last-msg (point-m= in))) + (save-excursion + (goto-char (point-max)) + (skip-chars-backward "\n") + (let ((beg (pos-bol))) + (insert " ") + (prog1 (erc-fill--wrap-measure beg (point)) + (delete-region (1- (point)) (point)))))) + ((and erc-fill-wrap-merge (erc-fill--wrap-continued-message-p)) (put-text-property (point-min) (point) 'display "") @@ -554,11 +546,12 @@ erc-fill-wrap (defvar erc-fill--wrap-rejigger-last-message nil "Temporary working instance of `erc-fill--wrap-last-msg'.") =20 -(defun erc-fill--wrap-rejigger-region (start finish on-next) +(defun erc-fill--wrap-rejigger-region (start finish on-next repairp) "Recalculate `line-prefix' from START to FINISH. After refilling each message, call ON-NEXT with no args. But stash and restore `erc-fill--wrap-last-msg' before doing so, in -case this module's insert hooks run by way of the process filter." +case this module's insert hooks run by way of the process filter. +With REPAIRP, destructively fill gaps and re-merge speakers." (goto-char start) (cl-assert (null erc-fill--wrap-rejigger-last-message)) (let (erc-fill--wrap-rejigger-last-message) @@ -571,24 +564,41 @@ erc-fill--wrap-rejigger-region (end (text-property-not-all beg finish 'line-prefix val))) ;; If this is a left-side stamp on its own line. (remove-text-properties beg (1+ end) '(line-prefix nil wrap-prefix n= il)) - (save-restriction - (narrow-to-region beg (1+ end)) - (if-let (((eq 'erc-timestamp (field-at-pos beg))) - ((eq 'date-left (get-text-property beg 'erc-stamp-type)))) - (progn - (goto-char (field-end beg)) - (erc-fill--wrap-stamp-insert-prefixed-date)) + (when-let ((repairp) + (dbeg (text-property-not-all beg end 'display nil)) + ((get-text-property (1+ dbeg) 'erc-speaker)) + (dval (get-text-property dbeg 'display)) + ((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-typ= e)) + (field-beginning beg) + beg)) + (erc--msg-props (map-into (text-properties-at pos) 'hash-tabl= e)) + (erc-stamp--current-time (gethash 'erc-ts erc--msg-props))) + (save-restriction + (narrow-to-region beg (1+ end)) (let ((erc-fill--wrap-last-msg erc-fill--wrap-rejigger-last-mess= age)) (erc-fill-wrap) (setq erc-fill--wrap-rejigger-last-message erc-fill--wrap-last-msg)))) (when on-next (funcall on-next)) - (goto-char end)))) - -(defun erc-fill-wrap-refill-buffer () - "Recalculate all `fill-wrap' prefixes in the current buffer." - (interactive) + ;; Skip to end of message upon encountering accidental gaps + ;; introduced by third parties (or bugs). + (if-let (((/=3D ?\n (char-after end))) + (next (erc--get-inserted-msg-bounds 'end beg))) + (progn + (cl-assert (=3D ?\n (char-after next))) + (when repairp ; eol <=3D next + (put-text-property end (pos-eol) 'line-prefix val)) + (goto-char next)) + (goto-char end))))) + +(defun erc-fill-wrap-refill-buffer (repair) + "Recalculate all `fill-wrap' prefixes in the current buffer. +With REPAIR, attempt to destructively fix merged properties." + (interactive "P") (unless erc-fill-wrap-mode (user-error "Module `fill-wrap' not active in current buffer.")) (save-excursion @@ -599,7 +609,8 @@ erc-fill-wrap-refill-buffer (callback (lambda () (progress-reporter-update rep (cl-incf seen)) (accept-process-output nil 0.000001)))) - (erc-fill--wrap-rejigger-region (point-min) erc-insert-marker call= back) + (erc-fill--wrap-rejigger-region (point-min) erc-insert-marker + callback repair) (progress-reporter-done rep))))) =20 ;; FIXME use own text property to avoid false positives. diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index b77176d8ac7..d112e63c316 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -339,8 +339,8 @@ erc-scroll-to-bottom ;;;###autoload(autoload 'erc-readonly-mode "erc-goodies" nil t) (define-erc-module readonly nil "This mode causes all inserted text to be read-only." - ((add-hook 'erc-insert-post-hook #'erc-make-read-only) - (add-hook 'erc-send-post-hook #'erc-make-read-only)) + ((add-hook 'erc-insert-post-hook #'erc-make-read-only 70) + (add-hook 'erc-send-post-hook #'erc-make-read-only 70)) ((remove-hook 'erc-insert-post-hook #'erc-make-read-only) (remove-hook 'erc-send-post-hook #'erc-make-read-only))) =20 diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 68dd1f287cf..7fc76eb2d73 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,23 +55,14 @@ erc-timestamp-format :type '(choice (const nil) (string))) =20 -(defun erc-stamp--custom-trailing-newline-p (_ value) - "Return non-nil if VALUE ends in a newline." - (string-suffix-p "\n" value)) - -(defun erc-stamp--custom-validate-date-stamp (widget) - "Fail unless WIDGET's value ends in a newline." - (unless (string-suffix-p "\n" (widget-value widget)) - (widget-put widget :error "Value lacks a trailing newline") - widget)) - (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "Format recognized by `format-time-string' for date stamps. Only considered when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. Used for displaying date -stamps on their own line, between messages. As of ERC 5.6, this -module appends a trailing newline on insertion if needed. Any -extra newlines, leading or trailing, become empty lines. For +stamps on their own line, between messages. ERC inserts this +flavor of stamp as a separate \"psuedo message\", so a final +newline isn't necessary. For compatibility, only additional +trailing newlines beyond the first become empty lines. For example, the default value results in an empty line after the previous message, followed by the timestamp on its own line, followed immediately by the next message on the next line. ERC @@ -79,11 +70,7 @@ erc-timestamp-format-left formatting specifiers should reflect that. To omit these stamps entirely, use a different `erc-insert-timestamp-function', such as `erc-timestamp-format-right'." - :type '(string :validate erc-stamp--custom-validate-date-stamp - :match erc-stamp--custom-trailing-newline-p) - :set (lambda (sym val) - (set-default sym - (if (string-suffix-p "\n" val) val (concat val "\n")= )))) + :type 'string) =20 (defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. @@ -189,9 +176,9 @@ erc-timestamp-face ;;;###autoload(autoload 'erc-timestamp-mode "erc-stamp" nil t) (define-erc-module stamp timestamp "This mode timestamps messages in the channel buffers." - ((add-hook 'erc-mode-hook #'erc-munge-invisibility-spec) - (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 60) - (add-hook 'erc-send-modify-hook #'erc-add-timestamp 60) + ((add-hook 'erc-mode-hook #'erc-stamp--setup) + (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 79) + (add-hook 'erc-send-modify-hook #'erc-add-timestamp 79) (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) (add-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear) (unless erc--updating-modules-p (erc-buffer-do #'erc-stamp--setup))) @@ -228,18 +215,27 @@ erc-stamp--current-time =20 (cl-defgeneric erc-stamp--current-time () "Return a lisp time object to associate with an IRC message. -This becomes the message's `erc-timestamp' text property." +This becomes the message's `erc-ts' text property." (erc-compat--current-lisp-time)) =20 (cl-defmethod erc-stamp--current-time :around () (or erc-stamp--current-time (cl-call-next-method))) =20 +(defvar erc-stamp--skip nil + "Non-nil means inhibit `erc-add-timestamp' completely.") + +(defvar erc-stamp--allow-unmanaged nil + "Non-nil means `erc-add-timestamp' runs unconditionally. +Escape hatch for third-parties using lower-level API functions, +such as `erc-display-line', directly.") + (defun erc-add-timestamp () "Add timestamp and text-properties to message. =20 This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (progn ; remove this `progn' on next major refactor + (unless (or erc-stamp--skip (and erc-stamp--allow-unmanaged + (not erc--msg-props))) (let* ((ct (erc-stamp--current-time)) (invisible (get-text-property (point-min) 'invisible)) (erc-stamp--invisible-property @@ -247,6 +243,8 @@ erc-add-timestamp (if invisible `(timestamp ,@(ensure-list invisible)) 'timestam= p)) (skipp (and erc-stamp--skip-when-invisible invisible)) (erc-stamp--current-time ct)) + (when erc--msg-props + (puthash 'erc-ts ct erc--msg-props)) (unless skipp (funcall erc-insert-timestamp-function (erc-format-timestamp ct erc-timestamp-format))) @@ -258,12 +256,13 @@ erc-add-timestamp (erc-away-time)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (1- (point-max)) + (when erc-stamp--allow-unmanaged + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions ;; Regions are no longer contiguous ^ - '(erc--echo-ts-csf) 'erc-timestamp ct))))) + '(erc--echo-ts-csf) 'erc-ts ct)))))) =20 (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -376,14 +375,14 @@ erc-stamp-prefix-log-filter (goto-char (point-min)) (while (progn - (when-let* (((< (point) (pos-eol))) - (end (1- (pos-eol))) - ((eq 'erc-timestamp (field-at-pos end))) - (beg (field-beginning end)) - ;; Skip a line that's just a timestamp. - ((> beg (point)))) + (when-let (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) (delete-region beg (1+ end))) - (when-let (time (get-text-property (point) 'erc-timestamp)) + (when-let (time (erc--get-inserted-msg-prop 'erc-ts)) (insert (format-time-string "[%H:%M:%S] " time))) (zerop (forward-line)))) "") @@ -595,8 +594,11 @@ erc-insert-timestamp-right ;; intervening white space unless a hard break is warranted. (pcase erc-timestamp-use-align-to ((guard erc-stamp--display-margin-mode) - (put-text-property 0 (length string) - 'display `((margin right-margin) ,string) stri= ng)) + (let ((s (propertize (substring-no-properties string) + 'invisible erc-stamp--invisible-property))) + (put-text-property 0 (length string) 'display + `((margin right-margin) ,s) + string))) ((and 't (guard (< col pos))) (insert " ") (put-text-property from (point) 'display `(space :align-to ,pos))) @@ -621,38 +623,77 @@ erc-insert-timestamp-right (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) =20 -(defvar erc-stamp--insert-date-function #'insert - "Function to insert left \"left-right date\" stamp. -A local module might use this to modify text properties, -`insert-before-markers' or renarrow the region after insertion.") - -(defun erc-stamp--decrement-date-invisibility-bounds () - "Extend `invisible' prop to previous newline before date stamp. -And apply original prop value from message body to any trailing -newlines after date." - (let ((beg (point-min))) +(defvar erc-stamp--insert-date-hook nil + "Functions appended to send and modify hooks when inserting date stamp.") + +(defvar-local erc-stamp--date-format-end nil + "Substring index marking usable portion of date stamp format.") + +(defun erc-stamp--propertize-left-date-stamp () + (add-text-properties (point-min) (1- (point-max)) + '(field erc-timestamp erc-stamp-type date-left)) + (erc--hide-message 'timestamp)) + +(defun erc-stamp-date-left-p (&optional point) + "Return non-nil if the current message is a \"date stamp\". +Expect callers to know that such stamps originate from +`erc-insert-timestamp-left-and-right' using the format string +`erc-timestamp-format-left'. Expect POINT, when non-nil, to +reside at some known or suspected time stamp. When POINT is nil, +expect to be called from a member of `erc-insert-modify-hook' or +similar." + (cond ((erc--check-msg-prop 'erc-msg 'datestamp)) + (point (eq 'date-left (get-text-property point 'erc-stamp-type))) + (t (erc--with-inserted-msg + (and-let* ((p (text-property-not-all + (point-min) (point-max) 'field 'erc-timestamp))) + (eq 'date-left (get-text-property p 'erc-stamp-type))))))) + +;; A kludge to pass state from insert hook to nested insert hook. +(defvar erc-stamp--current-datestamp-left nil) + +;; Calling `erc-display-message' from within a hook it's currently +;; running is roundabout, but it's a definite means of ensuring hooks +;; can act on the date stamp as a standalone message to do things like +;; adjust invisibility props. +(defun erc-stamp--insert-date-stamp-as-phony-message (string) + (cl-assert (string-empty-p string)) + (setq string erc-stamp--current-datestamp-left) + (cl-assert string) + (let ((erc-stamp--skip t) + (erc--msg-props (map-into `((erc-msg . datestamp) + (erc-ts . ,erc-stamp--current-time)) + 'hash-table)) + (erc-send-modify-hook `(,@erc-send-modify-hook + erc-stamp--propertize-left-date-stamp + ,@erc-stamp--insert-date-hook)) + (erc-insert-modify-hook `(,@erc-insert-modify-hook + erc-stamp--propertize-left-date-stamp + ,@erc-stamp--insert-date-hook))) + (erc-display-message nil nil (current-buffer) string) + (setq erc-timestamp-last-inserted-left string))) + +(defun erc-stamp--lr-date-on-pre-modify (_) + (unless erc-stamp--date-format-end + ;; Don't add text properties to the trailing newline. + (setq erc-stamp--date-format-end + (if (string-suffix-p "\n" erc-timestamp-format-left) -1 0))) + (when-let ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + ;; Ignore existing prop value because date stamps should + ;; never be hideable except via `timestamp'. + (rendered (let (erc-stamp--invisible-property) + (erc-format-timestamp + ct (substring erc-timestamp-format-left + 0 erc-stamp--date-format-end)))) + ((not (string-equal rendered erc-timestamp-last-inserted-left= ))) + (erc-stamp--current-datestamp-left rendered) + (erc-insert-timestamp-function + #'erc-stamp--insert-date-stamp-as-phony-message)) (save-restriction - (widen) - (when (and (> beg 4) (=3D (char-before beg) ?\n)) - (when-let ((this (get-text-property (point) 'invisible)) - (prev (get-text-property (1- beg) 'invisible)) - ((not (equal this prev)))) - (put-text-property (1- beg) beg 'invisible - (seq-difference (ensure-list prev) - (ensure-list this)))) - (put-text-property (1- beg) beg 'invisible 'timestamp))) - (cl-assert (=3D ?\n (char-before (point)))) - ;; Only decrement bounds by one. Additional newlines in the - ;; timestamp must be hidden. - (if-let ((existing (remq 'timestamp - (ensure-list erc-stamp--invisible-property)))) - (put-text-property (1- (point)) (point) 'invisible - (if (cdr existing) existing (car existing))) - (erc--remove-from-prop-value-list - (1- (point)) (point) 'invisible 'timestamp)))) - -(defvar-local erc-stamp--checked-date-string-p nil - "Non-nil if date string has been validated for current buffer.") + (narrow-to-region (or erc--insert-marker erc-insert-marker) + (or erc--insert-marker erc-insert-marker)) + (let (erc-timestamp-format erc-away-timestamp-format) + (erc-add-timestamp))))) =20 (defun erc-insert-timestamp-left-and-right (string) "Insert a stamp on either side when it changes. @@ -668,44 +709,23 @@ erc-insert-timestamp-left-and-right property to span a different interval, in order to satisfy newer folding requirements related to `erc-legacy-invisible-bounds-p'. Additionally, ensure every date stamp formatted with the option -`erc-timestamp-format-left' has the property `erc-stamp-type' set -to the symbol `date-left' so that modules can easily distinguish -between other left-sided stamps and date stamps inserted by this -function." - (unless erc-stamp--checked-date-string-p - (setq erc-stamp--checked-date-string-p t) - (unless (string-suffix-p "\n" erc-timestamp-format-left) - (setq erc-timestamp-format-left - (concat erc-timestamp-format-left "\n")) - (unless erc--target - (erc-button--display-error-notice-with-keys - (current-buffer) - "ERC only supports values of `%s' that end in a ?\\n." - " Changing value for current session to: %s." - " Update your config accordingly to silence this message." - 'erc-timestamp-format-left - (let ((print-escape-newlines t)) - (prin1-to-string erc-timestamp-format-left)))))) +`erc-timestamp-format-left' is marked as such so that modules can +easily distinguish between other left-sided stamps and date +stamps inserted by this function." + (unless erc-stamp--date-format-end + (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify -95 = t) + (add-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify -= 95 t) + (let ((erc--insert-marker (point-min-marker))) + (set-marker-insertion-type erc--insert-marker t) + (erc-stamp--lr-date-on-pre-modify nil) + (narrow-to-region erc--insert-marker (point-max)) + (set-marker erc--insert-marker nil))) (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) - (ts-left (let ((erc-stamp--invisible-property 'timestamp)) - (erc-format-timestamp ct erc-timestamp-format-left))) (ts-right (with-suppressed-warnings ((obsolete erc-timestamp-format-right)) (if erc-timestamp-format-right (erc-format-timestamp ct erc-timestamp-format-rig= ht) string)))) - ;; insert left timestamp - (unless (string-equal ts-left erc-timestamp-last-inserted-left) - (goto-char (point-min)) - (add-text-properties 0 (length ts-left) - '(field erc-timestamp erc-stamp-type date-left) - ts-left) - (funcall erc-stamp--insert-date-function ts-left) - (unless (with-suppressed-warnings - ((obsolete erc-legacy-invisible-bounds-p)) - erc-legacy-invisible-bounds-p) - (erc-stamp--decrement-date-invisibility-bounds)) - (setq erc-timestamp-last-inserted-left ts-left)) ;; insert right timestamp (let ((erc-timestamp-only-if-changed-flag t) (erc-timestamp-last-inserted erc-timestamp-last-inserted-right)) @@ -722,8 +742,9 @@ erc-format-timestamp (let ((ts (format-time-string format time erc-stamp--tz))) (erc-put-text-property 0 (length ts) 'font-lock-face 'erc-timestamp-face ts) - (erc-put-text-property 0 (length ts) 'invisible - erc-stamp--invisible-property ts) + (when erc-stamp--invisible-property + (erc-put-text-property 0 (length ts) 'invisible + erc-stamp--invisible-property ts)) ;; N.B. Later use categories instead of this harmless, but ;; inelegant, hack. -- BPT (and erc-timestamp-intangible @@ -732,6 +753,8 @@ erc-format-timestamp ts) "")) =20 +(defvar-local erc-stamp--csf-props-updated-p nil) + ;; This function is used to munge `buffer-invisibility-spec' to an ;; appropriate value. Currently, it only handles timestamps, thus its ;; location. If you add other features which affect invisibility, @@ -744,10 +767,23 @@ erc-munge-invisibility-spec (cursor-intangible-mode -1))) (if erc-echo-timestamps (progn + (dolist (hook '(erc-insert-post-hook erc-send-post-hook)) + (add-hook hook #'erc-stamp--add-csf-on-post-modify nil t)) + (erc--restore-initialize-priors erc-stamp-mode + erc-stamp--csf-props-updated-p nil) + (unless (or erc-stamp--allow-unmanaged erc-stamp--csf-props-update= d-p) + (setq erc-stamp--csf-props-updated-p t) + (let ((erc--msg-props (map-into '((erc-ts . t)) 'hash-table))) + (with-silent-modifications + (erc--traverse-inserted (point-min) erc-insert-marker + #'erc-stamp--add-csf-on-post-modify)= ))) (cursor-sensor-mode +1) ; idempotent (when (>=3D emacs-major-version 29) (add-function :before-until (local 'clear-message-function) #'erc-stamp--on-clear-message))) + (dolist (hook '(erc-insert-post-hook erc-send-post-hook)) + (remove-hook hook #'erc-stamp--add-csf-on-post-modify t)) + (kill-local-variable 'erc-stamp--csf-props-updated-p) (when (bound-and-true-p cursor-sensor-mode) (cursor-sensor-mode -1)) (remove-function (local 'clear-message-function) @@ -756,12 +792,22 @@ erc-munge-invisibility-spec (add-to-invisibility-spec 'timestamp) (remove-from-invisibility-spec 'timestamp))) =20 +(defun erc-stamp--add-csf-on-post-modify () + "Add `cursor-sensor-functions' to narrowed buffer." + (when (erc--check-msg-prop 'erc-ts) + (put-text-property (point-min) (1- (point-max)) + 'cursor-sensor-functions '(erc--echo-ts-csf)))) + (defun erc-stamp--setup () "Enable or disable buffer-local `erc-stamp-mode' modifications." (if erc-stamp-mode (erc-munge-invisibility-spec) (let (erc-echo-timestamps erc-hide-timestamps erc-timestamp-intangible) - (erc-munge-invisibility-spec)))) + (erc-munge-invisibility-spec)) + ;; Undo local mods from `erc-insert-timestamp-left-and-right'. + (remove-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify t) + (remove-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modif= y t) + (kill-local-variable 'erc-stamp--date-format-end))) =20 (defun erc-hide-timestamps () "Hide timestamp information from display." @@ -797,7 +843,7 @@ erc-stamp--last-stamp (defun erc-stamp--on-clear-message (&rest _) "Return `dont-clear-message' when operating inside the same stamp." (and erc-stamp--last-stamp erc-echo-timestamps - (eq (get-text-property (point) 'erc-timestamp) erc-stamp--last-stam= p) + (eq (erc--get-inserted-msg-prop 'erc-ts) erc-stamp--last-stamp) 'dont-clear-message)) =20 (defun erc-echo-timestamp (dir stamp &optional zone) @@ -807,7 +853,7 @@ erc-echo-timestamp interpret a \"raw\" prefix as UTC. To specify a zone for use with the option `erc-echo-timestamps', see the companion option `erc-echo-timestamp-zone'." - (interactive (list nil (get-text-property (point) 'erc-timestamp) + (interactive (list nil (erc--get-inserted-msg-prop 'erc-ts) (pcase current-prefix-arg ((and (pred numberp) v) (if (<=3D (abs v) 14) (* v 3600) v)) @@ -821,18 +867,18 @@ erc-echo-timestamp (setq erc-stamp--last-stamp nil)))) =20 (defun erc--echo-ts-csf (_window _before dir) - (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (erc-echo-timestamp dir (erc--get-inserted-msg-prop 'erc-ts))) =20 (defun erc-stamp--update-saved-position (&rest _) - (remove-function (local 'erc-stamp--insert-date-function) - #'erc-stamp--update-saved-position) - (move-marker erc-last-saved-position (1- (point)))) + (remove-hook 'erc-stamp--insert-date-hook + #'erc-stamp--update-saved-position t) + (move-marker erc-last-saved-position (1- (point-max)))) =20 (defun erc-stamp--reset-on-clear (pos) "Forget last-inserted stamps when POS is at insert marker." (when (=3D pos (1- erc-insert-marker)) - (add-function :after (local 'erc-stamp--insert-date-function) - #'erc-stamp--update-saved-position) + (add-hook 'erc-stamp--insert-date-hook + #'erc-stamp--update-saved-position 0 t) (setq erc-timestamp-last-inserted nil erc-timestamp-last-inserted-left nil erc-timestamp-last-inserted-right nil))) diff --git a/lisp/erc/erc-truncate.el b/lisp/erc/erc-truncate.el index 48d8408a85a..3350cbd13b7 100644 --- a/lisp/erc/erc-truncate.el +++ b/lisp/erc/erc-truncate.el @@ -102,7 +102,7 @@ erc-truncate-buffer-to-size ;; Truncate at message boundary (formerly line boundary ;; before 5.6). (goto-char end) - (goto-char (or (previous-single-property-change (point) 'erc-com= mand) + (goto-char (or (erc--get-inserted-msg-bounds 'beg) (pos-bol))) (setq end (point)) ;; try to save the current buffer using diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index a3321d9aabe..891689d8faa 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -135,9 +135,11 @@ erc-scripts "Running scripts at startup and with /LOAD." :group 'erc) =20 -;; Forward declarations -(defvar erc-message-parsed) +(defvar erc-message-parsed) ; only known to this file +(defvar erc--msg-props nil) +(defvar erc--msg-prop-overrides nil) =20 +;; Forward declarations (defvar tabbar--local-hlf) (defvar motif-version-string) (defvar gtk-version-string) @@ -1370,16 +1372,15 @@ erc--target-priors (defmacro erc--restore-initialize-priors (mode &rest vars) "Restore local VARS for MODE from a previous session." (declare (indent 1)) - (let ((existing (make-symbol "existing")) + (let ((priors (make-symbol "priors")) + (initp (make-symbol "initp")) ;; - restore initialize) - (while-let ((k (pop vars)) (v (pop vars))) - (push `(,k (alist-get ',k ,existing)) restore) - (push `(,k ,v) initialize)) - `(if-let* ((,existing (or erc--server-reconnecting erc--target-priors)) - ((alist-get ',mode ,existing))) - (setq ,@(mapcan #'identity (nreverse restore))) - (setq ,@(mapcan #'identity (nreverse initialize)))))) + forms) + (while-let ((k (pop vars))) + (push `(,k (if ,initp (alist-get ',k ,priors) ,(pop vars))) forms)) + `(let* ((,priors (or erc--server-reconnecting erc--target-priors)) + (,initp (and ,priors (alist-get ',mode ,priors)))) + (setq ,@(mapcan #'identity (nreverse forms)))))) =20 (defun erc--target-from-string (string) "Construct an `erc--target' variant from STRING." @@ -2859,11 +2860,10 @@ erc-toggle-debug-irc-protocol (defun erc-send-action (tgt str &optional force) "Send CTCP ACTION information described by STR to TGT." (erc-send-ctcp-message tgt (format "ACTION %s" str) force) - (let ((erc-insert-pre-hook - (cons (lambda (s) ; Leave newline be. - (put-text-property 0 (1- (length s)) 'erc-command 'PRIVMS= G s) - (put-text-property 0 (1- (length s)) 'erc-ctcp 'ACTION s)) - erc-insert-pre-hook)) + ;; Allow hooks that act on inserted PRIVMSG and NOTICES to process us. + (let ((erc--msg-prop-overrides '((erc-msg . msg) + (erc-cmd . PRIVMSG) + (erc-ctcp . ACTION))) (nick (erc-current-nick))) (setq nick (propertize nick 'erc-speaker nick)) (erc-display-message nil '(t action input) (current-buffer) @@ -2881,9 +2881,18 @@ erc-remove-parsed-property =20 The default is to remove it, since it causes ERC to take up extra memory. If you have code that relies on this property, then set -this option to nil." +this option to nil. + +Note that this option is deprecated because a value of nil is +impractical in prolonged sessions with more than a few channels. +Use `erc-insert-post-hook' or similar and the helper function +`erc-find-parsed-property' and friends to stash the current +`erc-response' object as needed. And instead of using this for +debugging purposes, try `erc-debug-irc-protocol'." :type 'boolean :group 'erc) +(make-obsolete-variable 'erc-remove-parsed-property + "impractical when non-nil" "30.1") =20 (define-inline erc--assert-input-bounds () (inline-quote @@ -2913,6 +2922,68 @@ erc--refresh-prompt (delete-region (point) (1- erc-input-marker)))) (run-hooks 'erc--refresh-prompt-hook))) =20 +(define-inline erc--check-msg-prop (prop &optional val) + "Return value for PROP in `erc--msg-props' when populated. +If VAL is a list, return non-nil if PROP appears in VAL. If VAL +is otherwise non-nil, return non-nil if VAL compares `eq' to the +stored value. Otherwise, return the stored value." + (inline-letevals (prop val) + (let ((v (make-symbol "v"))) + `(and-let* ((erc--msg-props) + (,v (gethash ,prop erc--msg-props))) + (if (consp ,val) (memq ,v ,val) (if ,val (eq ,v ,val) ,v)))))) + +(defmacro erc--get-inserted-msg-bounds (&optional only point) + `(let* ((point ,(or point '(point))) + (at-start-p (get-text-property point 'erc-msg))) + (and-let* + (,@(and (member only '(nil 'beg)) + '((b (or (and at-start-p point) + (and-let* + ((p (previous-single-property-change point + 'erc-ms= g))) + (if (=3D p (1- point)) point (1- p))))))) + ,@(and (member only '(nil 'end)) + '((e (1- (next-single-property-change + (if at-start-p (1+ point) point) + 'erc-msg nil erc-insert-marker)))))) + ,(pcase only + ('(quote beg) 'b) + ('(quote end) 'e) + (_ '(cons b e)))))) + +(defun erc--get-inserted-msg-prop (prop) + "Return the value of text property PROP for some message at point." + (and-let* ((stack-pos (erc--get-inserted-msg-bounds 'beg))) + (get-text-property stack-pos prop))) + +(defmacro erc--with-inserted-msg (&rest body) + "Simulate buffer narrowing of send insert hooks for BODY. +Note that this does not wrap BODY in `with-silent-modifications'. +Similarly, it does not bind a temporary `erc--msg-props' table." + `(when-let ((bounds (erc--get-inserted-msg-bounds))) + (save-restriction + (narrow-to-region (car bounds) (1+ (cdr bounds))) + ,@body))) + +(defun erc--traverse-inserted (beg end fn) + "Visit messages between BEG and END and run FN in narrowed buffer." + (setq end (min end (marker-position erc-insert-marker))) + (save-excursion + (goto-char beg) + (let ((b (if (get-text-property (point) 'erc-msg) + (point) + (next-single-property-change (point) 'erc-msg nil end)))) + (while-let ((b) + ((< b end)) + (e (next-single-property-change (1+ b) 'erc-msg nil end)= )) + (save-restriction + (narrow-to-region b e) + (funcall fn)) + (setq b e))))) + +(defvar erc--insert-marker nil) + (defun erc-display-line-1 (string buffer) "Display STRING in `erc-mode' BUFFER. Auxiliary function used in `erc-display-line'. The line gets filtered to @@ -2936,6 +3007,8 @@ erc-display-line-1 (format "%s" buffer))) (setq erc-insert-this t) (run-hook-with-args 'erc-insert-pre-hook string) + (setq insert-position (marker-position (or erc--insert-marker + erc-insert-marker))) (if (null erc-insert-this) ;; Leave erc-insert-this set to t as much as possible. Fran ;; Litterio <franl> has seen erc-insert-this set to nil while @@ -2955,10 +3028,17 @@ erc-display-line-1 (run-hooks 'erc-insert-post-hook) (when erc-remove-parsed-property (remove-text-properties (point-min) (point-max) - '(erc-parsed nil)))) + '(erc-parsed nil tags nil))) + (cl-assert (> (- (point-max) (point-min)) 1)) + (let ((props (if erc--msg-props + (erc--order-text-properties-from-hash + erc--msg-props) + '(erc-msg unknown)))) + (add-text-properties (point-min) (1+ (point-min)) prop= s))) (erc--refresh-prompt))))) (run-hooks 'erc-insert-done-hook) - (erc-update-undo-list (- (or (marker-position erc-insert-marker) + (erc-update-undo-list (- (or (marker-position (or erc--insert-mark= er + erc-insert-marke= r)) (point-max)) insert-position)))))) =20 @@ -3102,6 +3182,21 @@ erc--hide-message (cl-incf beg)) (erc--merge-prop (1- beg) (1- end) 'invisible value))))) =20 +(defvar erc--ranked-properties '(erc-msg erc-ts erc-cmd)) + +(defun erc--order-text-properties-from-hash (table) + "Return a plist of text props from items in table. +Ensure props in `erc--ranked-properties' appear last and in +reverse order so that they end up sorted in buffer interval +plists for retrieval by `text-properties-at' and friends." + (let (out) + (dolist (k erc--ranked-properties) + (when-let ((v (gethash k table))) + (remhash k table) + (setq out (nconc (list k v) out)))) + (maphash (lambda (k v) (setq out (nconc (list k v) out))) table) + out)) + (defun erc-display-message-highlight (type string) "Highlight STRING according to TYPE, where erc-TYPE-face is an ERC face. =20 @@ -3332,6 +3427,21 @@ erc-display-message (let ((string (if (symbolp msg) (apply #'erc-format-message msg args) msg)) + (erc--msg-props + (or erc--msg-props + (let* ((table (make-hash-table :size 5)) + (cmd (and parsed (erc--get-eq-comparable-cmd + (erc-response.command parsed)))) + (m (cond ((and msg (symbolp msg)) msg) + ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) + (t 'unknown)))) + (puthash 'erc-msg m table) + (when cmd + (puthash 'erc-cmd cmd table)) + (and erc--msg-prop-overrides + (pcase-dolist (`(,k . ,v) erc--msg-prop-overrides) + (puthash k v table))) + table))) (erc-message-parsed parsed)) (setq string (cond @@ -3350,9 +3460,6 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (put-text-property - 0 (length string) 'erc-command - (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parse= d) string)) @@ -5303,7 +5410,7 @@ erc--get-speaker-bounds Assume buffer is narrowed to the confines of an inserted message." (inline-quote (and-let* - (((memq (get-text-property (point) 'erc-command) '(PRIVMSG NOTICE))) + (((erc--check-msg-prop 'erc-msg 'msg)) (beg (or (and (get-text-property (point-min) 'erc-speaker) (point-= min)) (next-single-property-change (point-min) 'erc-speaker)))) (cons beg (next-single-property-change beg 'erc-speaker))))) @@ -5628,11 +5735,8 @@ erc-process-ctcp-query (while queries (let* ((type (upcase (car (split-string (car queries))))) (hook (intern-soft (concat "erc-ctcp-query-" type "-hook"= ))) - (erc-insert-pre-hook - (cons (lambda (s) - (put-text-property 0 (1- (length s)) 'erc-ctcp - (intern type) s)) - erc-insert-pre-hook))) + (erc--msg-prop-overrides `((erc-msg . msg) + (erc-ctcp . ,(intern type))))) (if (and hook (boundp hook)) (if (string-equal type "ACTION") (run-hook-with-args-until-success @@ -6637,7 +6741,8 @@ erc-send-current-line (when-let (((not (erc--input-split-abortp state))) (inhibit-read-only t) (old-buf (current-buffer))) - (progn ; unprogn this during next major surgery + (let ((erc--msg-prop-overrides '((erc-cmd . PRIVMSG) + (erc-msg . msg)))) (erc-set-active-buffer (current-buffer)) ;; Kill the input and the prompt (delete-region erc-input-marker (erc-end-of-input-line)) @@ -6784,17 +6889,24 @@ erc-display-msg (save-excursion (erc--assert-input-bounds) (let ((insert-position (marker-position (goto-char erc-insert-marker= ))) + (erc--msg-props (or erc--msg-props + (map-into (cons '(erc-msg . self) + erc--msg-prop-overrides) + '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) - (erc-put-text-property insert-position (point) 'erc-command 'PRIVM= SG) (insert "\n") (save-restriction (narrow-to-region insert-position (point)) (run-hooks 'erc-send-modify-hook) - (run-hooks 'erc-send-post-hook)) + (run-hooks 'erc-send-post-hook) + (cl-assert (> (- (point-max) (point-min)) 1)) + (add-text-properties (point-min) (1+ (point-min)) + (erc--order-text-properties-from-hash + erc--msg-props))) (erc--refresh-prompt))))) =20 (defun erc-command-symbol (command) @@ -8181,21 +8293,13 @@ erc-find-parsed-property "Find the next occurrence of the `erc-parsed' text property." (text-property-not-all (point-min) (point-max) 'erc-parsed nil)) =20 -(defvar erc--persistent-message-properties '(erc-command)) - (defun erc-restore-text-properties () - "Ensure the `erc-parsed' property covers the narrowed buffer. -Do this for other properties added by `erc-display-message' and -for those named in `erc--persistent-message-properties'." + "Ensure the `erc-parsed' and `tags' props cover the entire message." (when-let ((parsed-posn (erc-find-parsed-property)) - (found (erc-get-parsed-vector parsed-posn))) + (found (erc-get-parsed-vector parsed-posn))) (put-text-property (point-min) (point-max) 'erc-parsed found) (when-let ((tags (get-text-property parsed-posn 'tags))) - (put-text-property (point-min) (point-max) 'tags tags)) - (let ((to (max (point-min) (1- (point-max))))) - (dolist (prop erc--persistent-message-properties) - (when-let ((val (get-text-property parsed-posn prop))) - (put-text-property (point-min) to prop val)))))) + (put-text-property (point-min) (point-max) 'tags tags)))) =20 (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index b81d0c15558..f6c4c268017 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -31,10 +31,14 @@ erc-fill-tests--time-vals =20 (defun erc-fill-tests--insert-privmsg (speaker &rest msg-parts) (declare (indent 1)) - (let ((msg (erc-format-privmessage speaker - (apply #'concat msg-parts) nil t))) - (put-text-property 0 (length msg) 'erc-command 'PRIVMSG msg) - (erc-display-message nil nil (current-buffer) msg))) + (let* ((msg (erc-format-privmessage speaker + (apply #'concat msg-parts) nil t)) + ;; (erc--msg-prop-overrides '((erc-msg . msg) (erc-cmd . PRIVMSG)= )) + (parsed (make-erc-response :unparsed msg :sender speaker + :command "PRIVMSG" + :command-args (list "#chan" msg) + :contents msg))) + (erc-display-message parsed nil (current-buffer) msg))) =20 (defun erc-fill-tests--wrap-populate (test) (let ((original-window-buffer (window-buffer (selected-window))) @@ -75,8 +79,8 @@ erc-fill-tests--wrap-populate =20 (erc-fill-tests--insert-privmsg "alice" "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.") + "What was done to Elbow's wife, that he hath cause to complain= of?" + " Come me to what was done to her.") =20 ;; Introduce an artificial gap in properties `line-prefix' and ;; `wrap-prefix' and later ensure they're not incremented twice. @@ -111,6 +115,14 @@ erc-fill-tests--wrap-check-prefixes (should (get-text-property (pos-bol) 'line-prefix)) (should (get-text-property (1- (pos-eol)) 'line-prefix)) (should-not (get-text-property (pos-eol) 'line-prefix)) + ;; Spans entire line uninterrupted. + (let* ((val (get-text-property (pos-bol) 'line-prefix)) + (end (text-property-not-all (pos-bol) (point-max) + 'line-prefix val))) + (when (and (/=3D end (pos-eol)) (=3D ?? (char-before end))) + (setq end (text-property-not-all (1+ end) (point-max) + 'line-prefix val))) + (should (eq end (pos-eol)))) (should (equal (get-text-property (pos-bol) 'wrap-prefix) '(space :width erc-fill--wrap-value))) (should-not (get-text-property (pos-eol) 'wrap-prefix)) @@ -145,7 +157,7 @@ erc-fill-tests--compare (number-to-string erc-fill--wrap-value) (prin1-to-string got)))) (with-current-buffer (generate-new-buffer name) - (push name erc-fill-tests--buffers) + (push (current-buffer) erc-fill-tests--buffers) (with-silent-modifications (insert (setq got (read repr)))) (erc-mode)) @@ -153,15 +165,31 @@ erc-fill-tests--compare (with-temp-file expect-file (insert repr)) (if (file-exists-p expect-file) - ;; Compare set-equal over intervals. This comparison is - ;; less useful for messages treated by other modules because - ;; it doesn't compare "nested" props belonging to - ;; string-valued properties, like timestamps. - (should (equal-including-properties - (read repr) - (read (with-temp-buffer - (insert-file-contents-literally expect-file) - (buffer-string))))) + ;; Ensure string-valued properties, like timestamps, aren't + ;; recursive (signals `max-lisp-eval-depth' exceeded). + (named-let assert-equal + ((latest (read repr)) + (expect (read (with-temp-buffer + (insert-file-contents-literally expect-file) + (buffer-string))))) + (pcase latest + ((or "" 'nil) t) + ((pred stringp) + (should (equal-including-properties latest expect)) + (let ((latest-intervals (object-intervals latest)) + (expect-intervals (object-intervals expect))) + (while-let ((l-iv (pop latest-intervals)) + (x-iv (pop expect-intervals)) + (l-tab (map-into (nth 2 l-iv) 'hash-table)) + (x-tab (map-into (nth 2 x-iv) 'hash-table))) + (pcase-dolist (`(,l-k . ,l-v) (map-pairs l-tab)) + (assert-equal l-v (gethash l-k x-tab)) + (remhash l-k x-tab)) + (should (zerop (hash-table-count x-tab)))))) + ((pred sequencep) + (assert-equal (seq-first latest) (seq-first expect)) + (assert-equal (seq-rest latest) (seq-rest expect))) + (_ (should (equal latest expect))))) (message "Snapshot file missing: %S" expect-file))))) =20 ;; To inspect variable pitch, set `erc-mode-hook' to @@ -206,6 +234,13 @@ erc-fill-wrap--monospace (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") (erc-fill-tests--compare "monospace-04-reset"))))) =20 +(defun erc-fill-tests--simulate-refill () + ;; Simulate `erc-fill-wrap-refill-buffer' synchronously and without + ;; a progress reporter. + (save-excursion + (with-silent-modifications + (erc-fill--wrap-rejigger-region (point-min) erc-insert-marker nil ni= l)))) + (ert-deftest erc-fill-wrap--merge () :tags '(:unstable) (unless (>=3D emacs-major-version 29) @@ -217,7 +252,9 @@ erc-fill-wrap--merge (erc-update-channel-member "#chan" "Dummy" "Dummy" t nil nil nil nil nil "fake" "~u" nil nil t) =20 - ;; Set this here so that the first few messages are from 1970 + ;; Set this here so that the first few messages are from 1970. + ;; Following the current date stamp, the speaker isn't merged + ;; even though it's continued: "<bob> zero." (let ((erc-fill-tests--time-vals (lambda () 1680332400))) (erc-fill-tests--insert-privmsg "bob" "zero.") (erc-fill-tests--insert-privmsg "alice" "one.") @@ -239,7 +276,12 @@ erc-fill-wrap--merge (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> " "<bob> " "<alice> " "<alice> " "<bob> " "<bob> " "<Dummy> " "<Dumm= y> ") - (erc-fill-tests--compare "merge-02-right"))))) + (erc-fill-tests--compare "merge-02-right") + + (ert-info ("Command `erc-fill-wrap-refill-buffer' is idempotent") + (kill-buffer (pop erc-fill-tests--buffers)) + (erc-fill-tests--simulate-refill) ; idempotent + (erc-fill-tests--compare "merge-02-right")))))) =20 (ert-deftest erc-fill-wrap--merge-action () :tags '(:unstable) diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scena= rios-match.el index bc06d58c3e9..864f3881ab1 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -55,7 +55,8 @@ erc-scenarios-match--stamp-left-current-nick :nick "tester") ;; Module `timestamp' follows `match' in insertion hooks. (should (memq 'erc-add-timestamp - (memq 'erc-match-message erc-insert-modify-hook))) + (memq 'erc-match-message + (default-value 'erc-insert-modify-hook)))) ;; The "match type" is `current-nick'. (funcall expect 5 "tester") (should (eq (get-text-property (1- (point)) 'font-lock-face) @@ -91,7 +92,8 @@ erc-scenarios-match--invisible-stamp :nick "tester") ;; Module `timestamp' follows `match' in insertion hooks. (should (memq 'erc-add-timestamp - (memq 'erc-match-message erc-insert-modify-hook))) + (memq 'erc-match-message + (default-value 'erc-insert-modify-hook)))) (funcall expect 5 "This server is in debug mode"))) =20 (ert-info ("Ensure lines featuring \"bob\" are invisible") @@ -151,28 +153,13 @@ erc-scenarios-match--stamp-left-fools-invisible (=3D (next-single-property-change msg-beg 'invisible nil (pos-eo= l)) (pos-eol)))))))) =20 -(defun erc-scenarios-match--find-bol () - (save-excursion - (should (get-text-property (1- (point)) 'erc-command)) - (goto-char (should (previous-single-property-change (point) 'erc-comma= nd))) - (pos-bol))) - -(defun erc-scenarios-match--find-eol () - (save-excursion - (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. (defun erc-scenarios-match--stamp-right-fools-invisible () (let ((erc-insert-timestamp-function #'erc-insert-timestamp-right)) (erc-scenarios-match--invisible-stamp =20 (lambda () - (let ((beg (erc-scenarios-match--find-bol)) - (end (erc-scenarios-match--find-eol))) + (pcase-let ((`(,beg . ,end) (erc--get-inserted-msg-bounds))) ;; The end of the message is a newline. (should (=3D ?\n (char-after end))) =20 @@ -204,7 +191,7 @@ erc-scenarios-match--stamp-right-fools-invisible (should (=3D (next-single-property-change msg-end 'invisible) e= nd))))) =20 (lambda () - (let ((end (erc-scenarios-match--find-eol))) + (let ((end (cdr (erc--get-inserted-msg-bounds)))) ;; This message has a time stamp like all the others. (should (eq (field-at-pos (1- end)) 'erc-timestamp)) =20 @@ -279,7 +266,8 @@ erc-scenarios-match--fill-wrap-stamp-dedented-p =20 (ert-deftest erc-scenarios-match--stamp-both-invisible-fill-wrap () =20 - ;; Rewind the clock to known date artificially. + ;; Rewind the clock to known date artificially. We should probably + ;; use a ticks/hz cons on 29+. (let ((erc-stamp--current-time 704591940) (erc-stamp--tz t) (erc-fill-function #'erc-fill-wrap) @@ -305,29 +293,22 @@ erc-scenarios-match--stamp-both-invisible-fill-wrap (ert-info ("Line endings in Bob's messages are invisible") ;; The message proper has the `invisible' property `match-fools'. (should (eq (get-text-property (pos-bol) 'invisible) 'match-fools= )) - (let* ((mbeg (or (and (get-text-property (pos-bol) 'erc-command) - (pos-bol)) - (next-single-property-change (pos-bol) - 'erc-command))) - (mend (text-property-not-all - mbeg (point-max) 'erc-command - (get-text-property mbeg 'erc-command)))) - - (if (/=3D 1 bob-utterance-counter) - (should-not (field-at-pos mend)) - ;; For Bob's stamped message, check newline after stamp. - (should (eq (field-at-pos mend) 'erc-timestamp)) - (setq mend (field-end mend))) + (pcase-let ((`(,mbeg . ,mend) (erc--get-inserted-msg-bounds))) + (should (=3D (char-after mend) ?\n)) + (should-not (field-at-pos mend)) + (should-not (field-at-pos mbeg)) + + (when (=3D bob-utterance-counter 1) + (let ((right-stamp (field-end mbeg))) + (should (eq 'erc-timestamp (field-at-pos right-stamp))) + (should (=3D mend (field-end right-stamp))) + (should (eq (field-at-pos (1- mend)) 'erc-timestamp)))) =20 - ;; The `erc-timestamp' property spans entire messages, - ;; including stamps and filled text, which makes for - ;; convenient traversal when `erc-stamp-mode' is enabled. - (should (get-text-property (pos-bol) 'erc-timestamp)) - (should (=3D (next-single-property-change (pos-bol) 'erc-timest= amp) - mend)) + ;; The `erc-ts' property is present in prop stack. + (should (get-text-property (pos-bol) 'erc-ts)) + (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts= )) =20 ;; Line ending has the `invisible' property `match-fools'. - (should (=3D (char-after mend) ?\n)) (should (eq (get-text-property mbeg 'invisible) 'match-fools)) (should-not (get-text-property mend 'invisible)))) =20 @@ -410,22 +391,20 @@ erc-scenarios-match--stamp-both-invisible-fill-static (ert-info ("Line endings in Bob's messages are invisible") ;; The message proper has the `invisible' property `match-fools'. (should (eq (get-text-property (pos-bol) 'invisible) 'match-fools= )) - (let* ((mbeg (and (get-text-property (pos-bol) 'erc-command) - (pos-bol))) - (mend (next-single-property-change mbeg 'erc-command))) + (pcase-let ((`(,mbeg . ,mend) (erc--get-inserted-msg-bounds))) =20 - (if (/=3D 1 bob-utterance-counter) - (should-not (field-at-pos mend)) + (should (=3D (char-after mend) ?\n)) + (should-not (field-at-pos mbeg)) + (should-not (field-at-pos mend)) + (when (=3D 1 bob-utterance-counter) ;; For Bob's stamped message, check newline after stamp. - (should (eq (field-at-pos mend) 'erc-timestamp)) - (setq mend (field-end mend))) + (should (eq (field-at-pos (field-end mbeg)) 'erc-timestamp)) + (should (eq (field-at-pos (1- mend)) 'erc-timestamp))) =20 - ;; The `erc-timestamp' property spans entire messages, - ;; including stamps and filled text, which makes for - ;; convenient traversal when `erc-stamp-mode' is enabled. - (should (get-text-property (pos-bol) 'erc-timestamp)) - (should (=3D (next-single-property-change (pos-bol) 'erc-timest= amp) - mend)) + ;; The `erc-ts' property is present in the message's + ;; width 1 prop collection at its first char. + (should (get-text-property (pos-bol) 'erc-ts)) + (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts= )) =20 ;; Line ending has the `invisible' property `match-fools'. (should (=3D (char-after mend) ?\n)) @@ -510,9 +489,12 @@ erc-scenarios-match--stamp-both-invisible-fill-static-= -nooffset (field-beginning (point)))) (should (equal 'timestamp (get-text-property (1- (point)) 'invisible))) + ;; Field stops before final newline because the date stamp + ;; is (now, as of ERC 5.6) its own standalone message. + (should (=3D ?\n (char-after (field-end (point))))) ;; Stamp-only invisibility includes last newline. (should (=3D (text-property-not-all (1- (point)) (point-max) 'invisible 'timestamp) - (field-end (point)))))))))) + (1+ (field-end (point))))))))))) =20 ;;; erc-scenarios-match.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tes= ts.el index 46a05729066..cc61d599387 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -279,7 +279,7 @@ erc-echo-timestamp =20 (should-not erc-echo-timestamps) (should-not erc-stamp--last-stamp) - (insert (propertize "abc" 'erc-timestamp 433483200)) + (insert (propertize "a" 'erc-ts 433483200 'erc-msg 'msg) "bc") (goto-char (point-min)) (let ((inhibit-message t) (erc-echo-timestamp-format "%Y-%m-%d %H:%M:%S %Z") diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index bd2d656e8da..408cc4db10c 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -292,6 +292,8 @@ erc--refresh-prompt (cl-incf counter)))) erc-accidental-paste-threshold-seconds erc-insert-modify-hook + (erc-modules (remq 'stamp erc-modules)) + (erc-send-input-line-function #'ignore) (erc--input-review-functions erc--input-review-functions) erc-send-completed-hook) =20 @@ -356,7 +358,8 @@ erc--refresh-prompt (should (looking-back "#chan@ServNet 11> ")) (should (=3D (point) erc-input-marker)) (insert "/query bob") - (erc-send-current-line) + (let (erc-modules) + (erc-send-current-line)) ;; Last command not inserted (save-excursion (forward-line -1) (should (looking-at "<tester> Howdy"))) @@ -796,18 +799,15 @@ erc--valid-local-channel-p (should (erc--valid-local-channel-p "&local"))))) =20 (ert-deftest erc--restore-initialize-priors () - ;; This `pcase' expands to 100+k. Guess we could do something like - ;; (and `(,_ ((,e . ,_) . ,_) . ,_) v) first and then return a - ;; (equal `(if-let* ((,e ...)...)...) v) to cut it down to < 1k. (should (pcase (macroexpand-1 '(erc--restore-initialize-priors erc-my-mo= de foo (ignore 1 2 3) - bar #'spam)) - (`(if-let* ((,e (or erc--server-reconnecting erc--target-prior= s)) - ((alist-get 'erc-my-mode ,e))) - (setq foo (alist-get 'foo ,e) - bar (alist-get 'bar ,e)) - (setq foo (ignore 1 2 3) - bar #'spam)) + bar #'spam + baz nil)) + (`(let* ((,p (or erc--server-reconnecting erc--target-priors)) + (,q (and ,p (alist-get 'erc-my-mode ,p)))) + (setq foo (if ,q (alist-get 'foo ,p) (ignore 1 2 3)) + bar (if ,q (alist-get 'bar ,p) #'spam) + baz (if ,q (alist-get 'baz ,p) nil))) t)))) =20 (ert-deftest erc--target-from-string () @@ -1434,6 +1434,44 @@ erc-process-input-line =20 (should-not calls)))))) =20 +(ert-deftest erc--order-text-properties-from-hash () + (let ((table (map-into '((a . 1) + (erc-ts . 0) + (erc-msg . s005) + (b . 2) + (erc-cmd . 5) + (c . 3)) + 'hash-table))) + (with-temp-buffer + (erc-mode) + (insert "abc\n") + (add-text-properties 1 2 (erc--order-text-properties-from-hash table= )) + (should (equal '( erc-msg s005 + erc-ts 0 + erc-cmd 5 + a 1 + b 2 + c 3) + (text-properties-at (point-min))))))) + +(ert-deftest erc--check-msg-prop () + (let ((erc--msg-props (map-into '((a . 1) (b . x)) 'hash-table))) + (should (eq 1 (erc--check-msg-prop 'a))) + (should (erc--check-msg-prop 'a 1)) + (should-not (erc--check-msg-prop 'a 2)) + + (should (eq 'x (erc--check-msg-prop 'b))) + (should (erc--check-msg-prop 'b 'x)) + (should-not (erc--check-msg-prop 'b 1)) + + (should (erc--check-msg-prop 'a '(1 42))) + (should-not (erc--check-msg-prop 'a '(2 42))) + + (let ((props '(42 x))) + (should (erc--check-msg-prop 'b props))) + (let ((v '(42 y))) + (should-not (erc--check-msg-prop 'b v))))) + (defmacro erc-tests--equal-including-properties (a b) (list (if (< emacs-major-version 29) 'ert-equal-including-properties diff --git a/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld b/test= /lisp/erc/resources/base/assoc/multi-net/barnet.eld index c62a22a11c7..4c2b1d61e24 100644 --- a/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld +++ b/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 1 "PASS :changeme")) -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((pass 10 "PASS :changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester") (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running vers= ion oragono-2.6.0-7481bf0385b95b16") (0 ":irc.barnet.org 003 tester :This server was created Tue, 04 May 2021 = 05:06:19 UTC") @@ -18,16 +18,16 @@ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.barnet.org 422 tester :MOTD File is missing")) =20 -((mode-user 8 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0 ":irc.barnet.org 221 tester +i") (0 ":irc.barnet.org NOTICE tester :This server is in debug mode and is lo= gging all user I/O. If you do not wish for everything you send to be readab= le by the server owner(s), please disconnect.")) =20 -((join 2 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.barnet.org 353 tester =3D #chan :@mike joe tester") (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")) =20 -((mode 2 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620104779") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!") diff --git a/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld b/test= /lisp/erc/resources/base/assoc/multi-net/foonet.eld index f30b7deca11..bfa324642ce 100644 --- a/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld +++ b/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 1 "PASS :changeme")) -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((pass 10 "PASS :changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running vers= ion oragono-2.6.0-7481bf0385b95b16") (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 = 05:06:18 UTC") @@ -18,16 +18,16 @@ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) =20 -((mode-user 8 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0 ":irc.foonet.org 221 tester +i") (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is lo= gging all user I/O. If you do not wish for everything you send to be readab= le by the server owner(s), please disconnect.")) =20 -((join 2 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.foonet.org 353 tester =3D #chan :alice tester @bob") (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")) =20 -((mode 2 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620104779") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!") diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld b/t= est/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld index 686a47f68a3..04959954c4f 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld @@ -22,14 +22,14 @@ (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":irc.barnet.org 305 tester :You are no longer marked as being away")) =20 -((join 1 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.barnet.org 353 tester =3D #chan :@joe mike tester") (0 ":irc.barnet.org 366 tester #chan :End of NAMES list") (0.1 ":joe!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) =20 -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620805269") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: But you have outface= d them all.") diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld b/t= est/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld index b99621cc311..7b9b3bdee6c 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld @@ -22,14 +22,14 @@ (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":irc.foonet.org 305 tester :You are no longer marked as being away")) =20 -((join 1 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.foonet.org 353 tester =3D #chan :@alice bob tester") (0 ":irc.foonet.org 366 tester #chan :End of NAMES list") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) =20 -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620805271") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :bob: He cannot be heard = of. Out of doubt he is transported.") diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-01-start.eld index 689bacc7012..238d8cc73c2 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 20 (erc-timestamp 0 line= -prefix (space :width (- 27 (18))) field erc-timestamp) 20 21 (erc-timestam= p 0 field erc-timestamp) 21 183 (erc-timestamp 0 wrap-prefix #2=3D(space :w= idth 27) line-prefix #3=3D(space :width (- 27 (4)))) 183 190 (erc-timestamp= 0 field erc-timestamp wrap-prefix #2# line-prefix #3# display #1=3D(#7=3D(= margin right-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible ti= mestamp invisible timestamp font-lock-face erc-timestamp-face)))) 191 192 (= erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 27 (8))) = erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-prefix #= 4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #2# line= -prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-command PRIVM= SG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-command PR= IVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-prefix #5=3D(space :wi= dth (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-timestamp 0 wrap-prefix #= 2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-timestamp 0 wrap-prefi= x #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-timestamp 0 wrap-pr= efix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (erc-timestamp 0 wrap= -prefix #2# line-prefix #5# erc-command PRIVMSG) 436 454 (erc-timestamp 168= 0332400 line-prefix (space :width (- 27 (18))) field erc-timestamp) 454 455= (erc-timestamp 1680332400 field erc-timestamp) 455 456 (erc-timestamp 1680= 332400 wrap-prefix #2# line-prefix #6=3D(space :width (- 27 (6))) erc-comma= nd PRIVMSG) 456 459 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 6# erc-command PRIVMSG) 459 466 (erc-timestamp 1680332400 wrap-prefix #2# l= ine-prefix #6# erc-command PRIVMSG) 466 473 (erc-timestamp 1680332400 field= erc-timestamp wrap-prefix #2# line-prefix #6# display #8=3D(#7# #("[07:00]= " 0 7 (display #8# isearch-open-invisible timestamp invisible timestamp fon= t-lock-face erc-timestamp-face)))) 474 475 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #9=3D(space :width (- 27 (8))) erc-command PRIVMSG) 4= 75 480 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9# erc-comman= d PRIVMSG) 480 486 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9= # erc-command PRIVMSG) 487 488 (erc-timestamp 1680332400 wrap-prefix #2# li= ne-prefix #10=3D(space :width (- 27 0)) display #11=3D"" erc-command PRIVMS= G) 488 493 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #10# displ= ay #11# erc-command PRIVMSG) 493 495 (erc-timestamp 1680332400 wrap-prefix = #2# line-prefix #10# display #11# erc-command PRIVMSG) 495 499 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #10# erc-command PRIVMSG) 500 501= (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #12=3D(space :width = (- 27 (6))) erc-command PRIVMSG) 501 504 (erc-timestamp 1680332400 wrap-pre= fix #2# line-prefix #12# erc-command PRIVMSG) 504 512 (erc-timestamp 168033= 2400 wrap-prefix #2# line-prefix #12# erc-command PRIVMSG) 513 514 (erc-tim= estamp 1680332400 wrap-prefix #2# line-prefix #13=3D(space :width (- 27 0))= display #11# erc-command PRIVMSG) 514 517 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #13# display #11# erc-command PRIVMSG) 517 519 (erc-t= imestamp 1680332400 wrap-prefix #2# line-prefix #13# display #11# erc-comma= nd PRIVMSG) 519 524 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 13# erc-command PRIVMSG) 525 526 (erc-timestamp 1680332400 wrap-prefix #2# = line-prefix #14=3D(space :width (- 27 (8))) erc-command PRIVMSG) 526 531 (e= rc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-command PRIVMS= G) 531 538 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-c= ommand PRIVMSG) 539 540 (erc-timestamp 1680332400 wrap-prefix #2# line-pref= ix #15=3D(space :width (- 27 0)) display #11# erc-command PRIVMSG) 540 545 = (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #15# display #11# erc= -command PRIVMSG) 545 547 (erc-timestamp 1680332400 wrap-prefix #2# line-pr= efix #15# display #11# erc-command PRIVMSG) 547 551 (erc-timestamp 16803324= 00 wrap-prefix #2# line-prefix #15# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-02-right.eld index 9fa23a7d332..d1ce9198e69 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 20 (erc-timestamp 0 line= -prefix (space :width (- 29 (18))) field erc-timestamp) 20 21 (erc-timestam= p 0 field erc-timestamp) 21 183 (erc-timestamp 0 wrap-prefix #2=3D(space :w= idth 29) line-prefix #3=3D(space :width (- 29 (4)))) 183 190 (erc-timestamp= 0 field erc-timestamp wrap-prefix #2# line-prefix #3# display #1=3D(#7=3D(= margin right-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible ti= mestamp invisible timestamp font-lock-face erc-timestamp-face)))) 191 192 (= erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 29 (8))) = erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-prefix #= 4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #2# line= -prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-command PRIVM= SG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-command PR= IVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-prefix #5=3D(space :wi= dth (- 29 (6))) erc-command PRIVMSG) 350 353 (erc-timestamp 0 wrap-prefix #= 2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-timestamp 0 wrap-prefi= x #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-timestamp 0 wrap-pr= efix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (erc-timestamp 0 wrap= -prefix #2# line-prefix #5# erc-command PRIVMSG) 436 454 (erc-timestamp 168= 0332400 line-prefix (space :width (- 29 (18))) field erc-timestamp) 454 455= (erc-timestamp 1680332400 field erc-timestamp) 455 456 (erc-timestamp 1680= 332400 wrap-prefix #2# line-prefix #6=3D(space :width (- 29 (6))) erc-comma= nd PRIVMSG) 456 459 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 6# erc-command PRIVMSG) 459 466 (erc-timestamp 1680332400 wrap-prefix #2# l= ine-prefix #6# erc-command PRIVMSG) 466 473 (erc-timestamp 1680332400 field= erc-timestamp wrap-prefix #2# line-prefix #6# display #8=3D(#7# #("[07:00]= " 0 7 (display #8# isearch-open-invisible timestamp invisible timestamp fon= t-lock-face erc-timestamp-face)))) 474 475 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #9=3D(space :width (- 29 (8))) erc-command PRIVMSG) 4= 75 480 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9# erc-comman= d PRIVMSG) 480 486 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9= # erc-command PRIVMSG) 487 488 (erc-timestamp 1680332400 wrap-prefix #2# li= ne-prefix #10=3D(space :width (- 29 0)) display #11=3D"" erc-command PRIVMS= G) 488 493 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #10# displ= ay #11# erc-command PRIVMSG) 493 495 (erc-timestamp 1680332400 wrap-prefix = #2# line-prefix #10# display #11# erc-command PRIVMSG) 495 499 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #10# erc-command PRIVMSG) 500 501= (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #12=3D(space :width = (- 29 (6))) erc-command PRIVMSG) 501 504 (erc-timestamp 1680332400 wrap-pre= fix #2# line-prefix #12# erc-command PRIVMSG) 504 512 (erc-timestamp 168033= 2400 wrap-prefix #2# line-prefix #12# erc-command PRIVMSG) 513 514 (erc-tim= estamp 1680332400 wrap-prefix #2# line-prefix #13=3D(space :width (- 29 0))= display #11# erc-command PRIVMSG) 514 517 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #13# display #11# erc-command PRIVMSG) 517 519 (erc-t= imestamp 1680332400 wrap-prefix #2# line-prefix #13# display #11# erc-comma= nd PRIVMSG) 519 524 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 13# erc-command PRIVMSG) 525 526 (erc-timestamp 1680332400 wrap-prefix #2# = line-prefix #14=3D(space :width (- 29 (8))) erc-command PRIVMSG) 526 531 (e= rc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-command PRIVMS= G) 531 538 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-c= ommand PRIVMSG) 539 540 (erc-timestamp 1680332400 wrap-prefix #2# line-pref= ix #15=3D(space :width (- 29 0)) display #11# erc-command PRIVMSG) 540 545 = (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #15# display #11# erc= -command PRIVMSG) 545 547 (erc-timestamp 1680332400 wrap-prefix #2# line-pr= efix #15# display #11# erc-command PRIVMSG) 547 551 (erc-timestamp 16803324= 00 wrap-prefix #2# line-prefix #15# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index a3d533c87b5..d70184724ba 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18))) = field erc-timestamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (er= c-timestamp 0 wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :w= idth (- 27 (4)))) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix = #2# line-prefix #3# display #1=3D(#7=3D(margin right-margin) #("[00:00]" 0 = 7 (display #1# invisible timestamp font-lock-face erc-timestamp-face)))) 19= 1 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 27= (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-p= refix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# lin= e-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# = line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #= 2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-comman= d PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-com= mand PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-prefix #5=3D(sp= ace :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-timestamp 0 wrap-p= refix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-timestamp 0 wra= p-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-timestamp 0 = wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (erc-timestamp= 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 436 454 (erc-timest= amp 1680332400 line-prefix (space :width (- 27 (18))) field erc-timestamp) = 454 455 (erc-timestamp 1680332400 field erc-timestamp) 455 456 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #6=3D(space :width (- 27 (6))) er= c-command PRIVMSG) 456 459 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #6# erc-command PRIVMSG) 459 466 (erc-timestamp 1680332400 wrap-prefi= x #2# line-prefix #6# erc-command PRIVMSG) 466 473 (erc-timestamp 168033240= 0 field erc-timestamp wrap-prefix #2# line-prefix #6# display #8=3D(#7# #("= [07:00]" 0 7 (display #8# invisible timestamp font-lock-face erc-timestamp-= face)))) 474 476 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9= =3D(space :width (- 27 (6))) erc-ctcp ACTION erc-command PRIVMSG) 476 479 (= erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9# erc-ctcp ACTION er= c-command PRIVMSG) 479 483 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #9# erc-ctcp ACTION erc-command PRIVMSG) 484 485 (erc-timestamp 16803= 32400 wrap-prefix #2# line-prefix #10=3D(space :width (- 27 (6))) erc-comma= nd PRIVMSG) 485 488 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 10# erc-command PRIVMSG) 488 494 (erc-timestamp 1680332400 wrap-prefix #2# = line-prefix #10# erc-command PRIVMSG) 495 497 (erc-timestamp 1680332400 wra= p-prefix #2# line-prefix #11=3D(space :width (- 27 (2))) erc-ctcp ACTION er= c-command PRIVMSG) 497 500 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #11# erc-ctcp ACTION erc-command PRIVMSG) 500 506 (erc-timestamp 1680= 332400 wrap-prefix #2# line-prefix #11# erc-ctcp ACTION erc-command PRIVMSG= ) 507 508 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #12=3D(spac= e :width (- 27 (6))) erc-command PRIVMSG) 508 511 (erc-timestamp 1680332400= wrap-prefix #2# line-prefix #12# erc-command PRIVMSG) 511 518 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #12# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-pref= ix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#)= 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6= =3D(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (= erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(spac= e :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wr= ap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 20= 2 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefi= x #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-p= refix #4=3D(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# lin= e-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg da= testamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp= wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(spac= e :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wr= ap-prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1#= line-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 = 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-pre= fix #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1= # line-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-= prefix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9= =3D"") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-= prefix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefi= x #8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTI= ON wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wr= ap-prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) = 500 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680= 332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 2= 7 0)) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 5= 11 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix = #1# line-prefix #11#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index 80c9e1d80f5..def97738ce6 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (- 27 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 27 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index e675695f660..be3e2b33cfd 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 29 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 29) line-prefix #3=3D(space :width (- 29 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 29 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 29 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index a6070c2e3ff..098257d0b49 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 25 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 25) line-prefix #3=3D(space :width (- 25 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 25 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 25 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index 80c9e1d80f5..def97738ce6 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (- 27 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 27 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/t= est/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 2b8766c27f4..360b3dafafd 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18= ))) field erc-timestamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183= (erc-timestamp 0 wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(spac= e :width (- 27 (4)))) 183 190 (erc-timestamp 0 field erc-timestamp wrap-pre= fix #2# line-prefix #3# display #1=3D((margin right-margin) #("[00:00]" 0 7= (display #1# isearch-open-invisible timestamp invisible timestamp font-loc= k-face erc-timestamp-face)))) 190 191 (line-spacing 0.5) 191 192 (erc-times= tamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 27 (8))) erc-comma= nd PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-co= mmand PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc= -command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# = erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #2# line-prefix #= 4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-command PRIVMSG) 316 3= 48 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 34= 8 349 (line-spacing 0.5) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pref= ix #5=3D(space :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-timesta= mp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-time= stamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-t= imestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (er= c-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 435 436 = (line-spacing 0.5) 436 437 (erc-timestamp 0 wrap-prefix #2# line-prefix #6= =3D(space :width (- 27 0)) display #7=3D"" erc-command PRIVMSG) 437 440 (er= c-timestamp 0 wrap-prefix #2# line-prefix #6# display #7# erc-command PRIVM= SG) 440 442 (erc-timestamp 0 wrap-prefix #2# line-prefix #6# display #7# er= c-command PRIVMSG) 442 466 (erc-timestamp 0 wrap-prefix #2# line-prefix #6#= erc-command PRIVMSG) 466 467 (line-spacing 0.5) 467 484 (erc-timestamp 0 w= rap-prefix #2# line-prefix (space :width (- 27 (4)))) 485 502 (erc-timestam= p 0 wrap-prefix #2# line-prefix (space :width (- 27 (4)))) 502 503 (line-sp= acing 0.5) 503 504 (erc-timestamp 0 wrap-prefix #2# line-prefix #8=3D(space= :width (- 27 (6))) erc-command PRIVMSG) 504 507 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #8# erc-command PRIVMSG) 507 525 (erc-timestamp 0 wrap-p= refix #2# line-prefix #8# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-= prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix = #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (lin= e-spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1= # line-prefix #3=3D(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 (wr= ap-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(space :width= (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefi= x #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (w= rap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg= msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :widt= h (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displ= ay #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap= -prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg un= known erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) = 468 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg unknown erc-ts 0= wrap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-= prefix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg= erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (-= 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #= 1# line-prefix #9#)) diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld index f62b65cd170..cd3537d3c94 100644 --- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -1 +1 @@ -#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 9 (erc= -timestamp 0 display (#4=3D(margin left-margin) #("[00:00]" 0 7 (invisible = timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-pre= fix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 27 (4)))) 9 17= 1 (erc-timestamp 0 wrap-prefix #1# line-prefix #2#) 172 179 (erc-timestamp = 0 display (#4# #("[00:00]" 0 7 (invisible timestamp font-lock-face erc-time= stamp-face))) field erc-timestamp wrap-prefix #1# line-prefix #3=3D(space := width (- 27 (8)))) 179 180 (erc-timestamp 0 wrap-prefix #1# line-prefix #3#= erc-command PRIVMSG) 180 185 (erc-timestamp 0 wrap-prefix #1# line-prefix = #3# erc-command PRIVMSG) 185 187 (erc-timestamp 0 wrap-prefix #1# line-pref= ix #3# erc-command PRIVMSG) 187 190 (erc-timestamp 0 wrap-prefix #1# line-p= refix #3# erc-command PRIVMSG) 190 303 (erc-timestamp 0 wrap-prefix #1# lin= e-prefix #3# erc-command PRIVMSG) 303 304 (erc-timestamp 0 erc-command PRIV= MSG) 304 336 (erc-timestamp 0 wrap-prefix #1# line-prefix #3# erc-command P= RIVMSG) 337 344 (erc-timestamp 0 display (#4# #("[00:00]" 0 7 (invisible ti= mestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefi= x #1# line-prefix #5=3D(space :width (- 27 (6)))) 344 345 (erc-timestamp 0 = wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 345 348 (erc-timestamp= 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 348 350 (erc-timest= amp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 350 355 (erc-tim= estamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 355 430 (erc-= timestamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg unknown erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0= 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-time= stamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- = 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix = #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 = erc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font= -lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-p= refix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timest= amp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #= 4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line= -prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix= #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (er= c-msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invis= ible timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wra= p-prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #= 8# field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefi= x #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (w= rap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 3= 55 430 (wrap-prefix #1# line-prefix #7#)) \ No newline at end of file --=20 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Allow-spoofing-process-marker-in-erc-display-lin.patch From 69aa1ebcac9044efc78c922dcb7805144cc237a7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 2 Oct 2023 22:59:22 -0700 Subject: [PATCH 1/7] [5.6] Allow spoofing process marker in erc-display-line-1 * lisp/erc/erc.el (erc--insert-marker): New internal variable for overriding `erc-insert-marker' when displaying messages at a non-default location in the buffer. (erc-display-line-1): Favor `erc--insert-marker' over `erc-insert-marker' when non-nil. * test/lisp/erc/resources/base/assoc/multi-net/barnet.eld: Timeouts. * test/lisp/erc/resources/base/assoc/multi-net/foonet.eld: Timeouts. * test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld: Timeouts. * test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld: Timeouts. --- lisp/erc/erc.el | 7 ++++++- .../erc/resources/base/assoc/multi-net/barnet.eld | 12 ++++++------ .../erc/resources/base/assoc/multi-net/foonet.eld | 12 ++++++------ .../erc/resources/base/netid/bouncer/barnet-drop.eld | 4 ++-- .../erc/resources/base/netid/bouncer/foonet-drop.eld | 4 ++-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index fb236f1f189..b78f8bc6210 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2909,6 +2909,8 @@ erc--refresh-prompt (delete-region (point) (1- erc-input-marker)))) (run-hooks 'erc--refresh-prompt-hook))) +(defvar erc--insert-marker nil) + (defun erc-display-line-1 (string buffer) "Display STRING in `erc-mode' BUFFER. Auxiliary function used in `erc-display-line'. The line gets filtered to @@ -2932,6 +2934,8 @@ erc-display-line-1 (format "%s" buffer))) (setq erc-insert-this t) (run-hook-with-args 'erc-insert-pre-hook string) + (setq insert-position (marker-position (or erc--insert-marker + erc-insert-marker))) (if (null erc-insert-this) ;; Leave erc-insert-this set to t as much as possible. Fran ;; Litterio <franl> has seen erc-insert-this set to nil while @@ -2954,7 +2958,8 @@ erc-display-line-1 '(erc-parsed nil)))) (erc--refresh-prompt))))) (run-hooks 'erc-insert-done-hook) - (erc-update-undo-list (- (or (marker-position erc-insert-marker) + (erc-update-undo-list (- (or (marker-position (or erc--insert-marker + erc-insert-marker)) (point-max)) insert-position)))))) diff --git a/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld b/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld index c62a22a11c7..4c2b1d61e24 100644 --- a/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld +++ b/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 1 "PASS :changeme")) -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((pass 10 "PASS :changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester") (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version oragono-2.6.0-7481bf0385b95b16") (0 ":irc.barnet.org 003 tester :This server was created Tue, 04 May 2021 05:06:19 UTC") @@ -18,16 +18,16 @@ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.barnet.org 422 tester :MOTD File is missing")) -((mode-user 8 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0 ":irc.barnet.org 221 tester +i") (0 ":irc.barnet.org NOTICE tester :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.")) -((join 2 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.barnet.org 353 tester = #chan :@mike joe tester") (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")) -((mode 2 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620104779") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!") diff --git a/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld b/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld index f30b7deca11..bfa324642ce 100644 --- a/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld +++ b/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 1 "PASS :changeme")) -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((pass 10 "PASS :changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16") (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 05:06:18 UTC") @@ -18,16 +18,16 @@ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 8 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0 ":irc.foonet.org 221 tester +i") (0 ":irc.foonet.org NOTICE tester :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.")) -((join 2 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob") (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")) -((mode 2 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620104779") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!") diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld b/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld index 686a47f68a3..04959954c4f 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld @@ -22,14 +22,14 @@ (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":irc.barnet.org 305 tester :You are no longer marked as being away")) -((join 1 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester") (0 ":irc.barnet.org 366 tester #chan :End of NAMES list") (0.1 ":joe!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620805269") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: But you have outfaced them all.") diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld b/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld index b99621cc311..7b9b3bdee6c 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld @@ -22,14 +22,14 @@ (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":irc.foonet.org 305 tester :You are no longer marked as being away")) -((join 1 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester") (0 ":irc.foonet.org 366 tester #chan :End of NAMES list") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 1 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620805271") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :bob: He cannot be heard of. Out of doubt he is transported.") -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Honor-nil-values-in-erc-restore-initialize-prior.patch From ffcc811bdc69f089059ff907c4a265c406c965fc Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 5 Oct 2023 00:16:46 -0700 Subject: [PATCH 2/7] [5.6] Honor nil values in erc--restore-initialize-priors * lisp/erc/erc.el (erc--restore-initialize-priors): Don't produce invalid empty `setq' when given VARS that initialize to nil. * test/lisp/erc/erc-tests.el (erc--restore-initialize-priors): Fix expected expansion. --- lisp/erc/erc.el | 17 ++++++++--------- test/lisp/erc/erc-tests.el | 17 +++++++---------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index b78f8bc6210..a3ba1548084 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1366,16 +1366,15 @@ erc--target-priors (defmacro erc--restore-initialize-priors (mode &rest vars) "Restore local VARS for MODE from a previous session." (declare (indent 1)) - (let ((existing (make-symbol "existing")) + (let ((priors (make-symbol "priors")) + (initp (make-symbol "initp")) ;; - restore initialize) - (while-let ((k (pop vars)) (v (pop vars))) - (push `(,k (alist-get ',k ,existing)) restore) - (push `(,k ,v) initialize)) - `(if-let* ((,existing (or erc--server-reconnecting erc--target-priors)) - ((alist-get ',mode ,existing))) - (setq ,@(mapcan #'identity (nreverse restore))) - (setq ,@(mapcan #'identity (nreverse initialize)))))) + forms) + (while-let ((k (pop vars))) + (push `(,k (if ,initp (alist-get ',k ,priors) ,(pop vars))) forms)) + `(let* ((,priors (or erc--server-reconnecting erc--target-priors)) + (,initp (and ,priors (alist-get ',mode ,priors)))) + (setq ,@(mapcan #'identity (nreverse forms)))))) (defun erc--target-from-string (string) "Construct an `erc--target' variant from STRING." diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 8a68eca6196..64b503832f3 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -796,18 +796,15 @@ erc--valid-local-channel-p (should (erc--valid-local-channel-p "&local"))))) (ert-deftest erc--restore-initialize-priors () - ;; This `pcase' expands to 100+k. Guess we could do something like - ;; (and `(,_ ((,e . ,_) . ,_) . ,_) v) first and then return a - ;; (equal `(if-let* ((,e ...)...)...) v) to cut it down to < 1k. (should (pcase (macroexpand-1 '(erc--restore-initialize-priors erc-my-mode foo (ignore 1 2 3) - bar #'spam)) - (`(if-let* ((,e (or erc--server-reconnecting erc--target-priors)) - ((alist-get 'erc-my-mode ,e))) - (setq foo (alist-get 'foo ,e) - bar (alist-get 'bar ,e)) - (setq foo (ignore 1 2 3) - bar #'spam)) + bar #'spam + baz nil)) + (`(let* ((,p (or erc--server-reconnecting erc--target-priors)) + (,q (and ,p (alist-get 'erc-my-mode ,p)))) + (setq foo (if ,q (alist-get 'foo ,p) (ignore 1 2 3)) + bar (if ,q (alist-get 'bar ,p) #'spam) + baz (if ,q (alist-get 'baz ,p) nil))) t)))) (ert-deftest erc--target-from-string () -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Preserve-format-spec-args-in-erc-server-JOIN.patch From 62c6585251a1d0a604499f103f87884a1b33de3b Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 4 Oct 2023 20:39:03 -0700 Subject: [PATCH 3/7] [5.6] Preserve format-spec args in erc-server-JOIN * lisp/erc/erc-backend.el (erc-server-JOIN): Let `erc-display-message' handle formatting instead of baking out a string. The text ultimately inserted remains unchanged, but forwarding the original `format-spec' arguments now has the side effect of influencing text properties, which conveys richer meaning for modules to act upon when doing things like deciding whether to hide a message. --- lisp/erc/erc-backend.el | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index fb10ee31c78..bc42917375a 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1718,7 +1718,7 @@ erc--server-determine-join-display-context (if (string-match "^\\(.*\\)\^g.*$" chnl) (setq chnl (match-string 1 chnl))) (save-excursion - (let* ((str (cond + (let ((args (cond ;; If I have joined a channel ((erc-current-nick-p nick) (let ((erc--display-context @@ -1735,18 +1735,15 @@ erc--server-determine-join-display-context (erc-channel-begin-receiving-names)) (erc-update-mode-line) (run-hooks 'erc-join-hook) - (erc-make-notice - (erc-format-message 'JOIN-you ?c chnl))) + (list 'JOIN-you ?c chnl)) (t (setq buffer (erc-get-buffer chnl proc)) - (erc-make-notice - (erc-format-message - 'JOIN ?n nick ?u login ?h host ?c chnl)))))) + (list 'JOIN ?n nick ?u login ?h host ?c chnl))))) (when buffer (set-buffer buffer)) (erc-update-channel-member chnl nick nick t nil nil nil nil nil host login) ;; on join, we want to stay in the new channel buffer ;;(set-buffer ob) - (erc-display-message parsed nil buffer str)))))) + (apply #'erc-display-message parsed 'notice buffer args)))))) (define-erc-response-handler (KICK) "Handle kick messages received from the server." nil -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Deprecate-option-erc-remove-parsed-property.patch From 866a2681dacc4307d9f6b177dbab5beccc740f4c Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Tue, 3 Oct 2023 00:00:19 -0700 Subject: [PATCH 4/7] [5.6] Deprecate option erc-remove-parsed-property * etc/ERC-NEWS: Add entry for `erc-remove-parsed-property'. * lisp/erc/erc.el (erc-remove-parsed-property): Deprecate option because the potential for inadvertent self harm outweighs the potential benefits. Additionally, replicating this functionality via hooks is trivial. (erc-display-line-1): Remove quasi-deprecated `tags' property. --- etc/ERC-NEWS | 8 ++++++++ lisp/erc/erc.el | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index fadd97b65df..284b91bb41f 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -221,6 +221,14 @@ atop any message. The new companion option 'erc-echo-timestamp-zone' determines the default timezone when not specified with a prefix argument. +** Option 'erc-remove-parsed-property' deprecated. +This option's nil behavior serves no practical purpose yet has the +potential to degrade the user experience by competing for space with +forthcoming features powered by next generation extensions. Anyone +with a legitimate use for this option likely also possesses the +knowledge to rig up a suitable analog with minimal effort. That said, +the road to removal is long. + ** Option 'erc-warn-about-blank-lines' is more informative. Enabled by default, this option now produces more useful feedback whenever ERC rejects prompt input containing whitespace-only lines. diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index a3ba1548084..aedec60321b 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2876,9 +2876,18 @@ erc-remove-parsed-property The default is to remove it, since it causes ERC to take up extra memory. If you have code that relies on this property, then set -this option to nil." +this option to nil. + +Note that this option is deprecated because a value of nil is +impractical in prolonged sessions with more than a few channels. +Use `erc-insert-post-hook' or similar and the helper function +`erc-find-parsed-property' and friends to stash the current +`erc-response' object as needed. And instead of using this for +debugging purposes, try `erc-debug-irc-protocol'." :type 'boolean :group 'erc) +(make-obsolete-variable 'erc-remove-parsed-property + "impractical when non-nil" "30.1") (define-inline erc--assert-input-bounds () (inline-quote @@ -2954,7 +2963,7 @@ erc-display-line-1 (run-hooks 'erc-insert-post-hook) (when erc-remove-parsed-property (remove-text-properties (point-min) (point-max) - '(erc-parsed nil)))) + '(erc-parsed nil tags nil)))) (erc--refresh-prompt))))) (run-hooks 'erc-insert-done-hook) (erc-update-undo-list (- (or (marker-position (or erc--insert-marker -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Add-helper-for-removing-list-valued-text-props-i.patch From a9638d22c67ffed2fd25f4ecf10f0d3a2aac5ea9 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Tue, 3 Oct 2023 23:15:40 -0700 Subject: [PATCH 5/7] [5.6] Add helper for removing list-valued text props in ERC * lisp/erc/erc.el (erc--remove-from-prop-value-list): New function for removing `invisible' and `face' prop members cleanly. * test/lisp/erc/erc-tests.el (erc--remove-from-prop-value-list, erc--remove-from-prop-value-list/many): New tests. (Bug#60936) --- lisp/erc/erc.el | 24 ++++++ test/lisp/erc/erc-tests.el | 169 +++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index aedec60321b..f3c480f918b 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3061,6 +3061,30 @@ erc--merge-prop old (get-text-property pos prop object) end (next-single-property-change pos prop object to))))) +(defun erc--remove-from-prop-value-list (from to prop val &optional object) + "Remove VAL from text prop value between FROM and TO. +If current value is VAL itself, remove the property entirely. +When VAL is a list, act as if this function were called +repeatedly with VAL set to each of VAL's members." + (let ((old (get-text-property from prop object)) + (pos from) + (end (next-single-property-change from prop object to)) + new) + (while (< pos to) + (when old + (if (setq new (and (consp old) (if (consp val) + (seq-difference old val) + (remq val old)))) + (put-text-property pos end prop + (if (cdr new) new (car new)) object) + (when (pcase val + ((pred consp) (or (consp old) (memq old val))) + (_ (if (consp old) (memq val old) (eq old val)))) + (remove-text-properties pos end (list prop nil) object)))) + (setq pos end + old (get-text-property pos prop object) + end (next-single-property-change pos prop object to))))) + (defvar erc-legacy-invisible-bounds-p nil "Whether to hide trailing rather than preceding newlines. Beginning in ERC 5.6, invisibility extends from a message's diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 64b503832f3..11717217eb2 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1475,6 +1475,175 @@ erc--merge-prop (when noninteractive (kill-buffer)))) +(ert-deftest erc--remove-from-prop-value-list () + (with-current-buffer (get-buffer-create "*erc-test*") + ;; Non-list match. + (insert "abc\n") + (put-text-property 1 2 'erc-test 'a) + (put-text-property 2 3 'erc-test 'b) + (put-text-property 3 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 1 2 (erc-test b) + 2 3 (erc-test c)))) + + (erc--remove-from-prop-value-list 1 4 'erc-test 'b) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'a) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "abc")) + + ;; List match. + (goto-char (point-min)) + (insert "def\n") + (put-text-property 1 2 'erc-test '(d x)) + (put-text-property 2 3 'erc-test '(e y)) + (put-text-property 3 4 'erc-test '(f z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x)) + 1 2 (erc-test (e y)) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'y) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x)) + 1 2 (erc-test e) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'd) + (erc--remove-from-prop-value-list 1 4 'erc-test 'f) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test x) + 1 2 (erc-test e) + 2 3 (erc-test z)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'e) + (erc--remove-from-prop-value-list 1 4 'erc-test 'z) + (erc--remove-from-prop-value-list 1 4 'erc-test 'x) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "def")) + + ;; List match. + (goto-char (point-min)) + (insert "ghi\n") + (put-text-property 1 2 'erc-test '(g x)) + (put-text-property 2 3 'erc-test '(h x)) + (put-text-property 3 4 'erc-test '(i y)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test (g x)) + 1 2 (erc-test (h x)) + 2 3 (erc-test (i y))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'x) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test g) + 1 2 (erc-test h) + 2 3 (erc-test (i y))))) + (erc--remove-from-prop-value-list 1 2 'erc-test 'g) ; narrowed + (erc--remove-from-prop-value-list 3 4 'erc-test 'i) ; narrowed + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 1 2 (erc-test h) + 2 3 (erc-test y)))) + + ;; Pathological (,c) case (hopefully not created by ERC) + (goto-char (point-min)) + (insert "jkl\n") + (put-text-property 1 2 'erc-test '(j x)) + (put-text-property 2 3 'erc-test '(k)) + (put-text-property 3 4 'erc-test '(k)) + (erc--remove-from-prop-value-list 1 4 'erc-test 'k) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("jkl" 0 1 (erc-test (j x))))) + + (when noninteractive + (kill-buffer)))) + +(ert-deftest erc--remove-from-prop-value-list/many () + (with-current-buffer (get-buffer-create "*erc-test*") + ;; Non-list match. + (insert "abc\n") + (put-text-property 1 2 'erc-test 'a) + (put-text-property 2 3 'erc-test 'b) + (put-text-property 3 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 1 2 (erc-test b) + 2 3 (erc-test c)))) + + (erc--remove-from-prop-value-list 1 4 'erc-test '(a b)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'a) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(c)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "abc")) + + ;; List match. + (goto-char (point-min)) + (insert "def\n") + (put-text-property 1 2 'erc-test '(d x y)) + (put-text-property 2 3 'erc-test '(e y)) + (put-text-property 3 4 'erc-test '(f z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x y)) + 1 2 (erc-test (e y)) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(d y f)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test x) + 1 2 (erc-test e) + 2 3 (erc-test z)))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(e z x)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "def")) + + ;; Narrowed beg. + (goto-char (point-min)) + (insert "ghi\n") + (put-text-property 1 2 'erc-test '(g x)) + (put-text-property 2 3 'erc-test '(h x)) + (put-text-property 3 4 'erc-test '(i x)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test (g x)) + 1 2 (erc-test (h x)) + 2 3 (erc-test (i x))))) + (erc--remove-from-prop-value-list 1 3 'erc-test '(x g i)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 1 2 (erc-test h) + 2 3 (erc-test (i x))))) + + ;; Narrowed middle. + (goto-char (point-min)) + (insert "jkl\n") + (put-text-property 1 2 'erc-test '(j x)) + (put-text-property 2 3 'erc-test '(k)) + (put-text-property 3 4 'erc-test '(l y z)) + (erc--remove-from-prop-value-list 3 4 'erc-test '(k x y z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("jkl" + 0 1 (erc-test (j x)) + 1 2 (erc-test (k)) + 2 3 (erc-test l)))) + + (when noninteractive + (kill-buffer)))) + (ert-deftest erc--split-string-shell-cmd () ;; Leading and trailing space -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Manage-meta-data-text-props-for-ERC-hook-members.patch Content-Transfer-Encoding: quoted-printable From ef4974d8e232b0d5e5df31a30f2fd904f970c60f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 21 Sep 2023 23:54:31 -0700 Subject: [PATCH 6/7] [5.6] Manage meta-data text props for ERC hook members * etc/ERC-NEWS: Mention that `cursor-sensor-functions' is only added when `erc-echo-timestamps' is enabled, and mention that date stamps are now inserted as separate messages. * lisp/erc/erc-fill.el (erc-fill): Look for `erc-cmd' instead of `erc-command' text prop. (erc-fill-static): Skip date stamps. (erc-fill-wrap-mode, erc-fill-wrap-enable, erc-fill-wrap-disable): Don't use removed hook `erc-stamp--insert-date-function' because date stamps are now separate messages. (erc-fill--wrap-continued-message-p): Restore accidentally excised doc string. Derive context about current message from text props at `point-min', and use updated names and utility functions. (erc-fill--wrap-stamp-insert-prefixed-date): Remove function, originally meant to be new in ERC 5.6, and move logic for date-stamp measuring directly to `erc-fill-wrap' itself. (erc-fill--wrap-measure): New helper function. (erc-fill-wrap): Use helper `erc-fill--wrap-measure' and incorporate date-stamp detection and width measuring from removed helper. * lisp/erc/erc-goodies.el (erc-readonly-mode, erc-readonly-enable): Set hook depth to an explicit 70. * lisp/erc/erc-stamp.el (erc-timestamp-format-left): Mention that a trailing newline is implicit if not provided and that users who don't want date stamps should use `erc-timestamp-format-right' instead. (erc-stamp-mode, erc-stamp-enable): Call `erc-stamp--setup' instead of `erc-munge-invisibility-spec', and bump hook depth for `erc-add-timestamp' to 79. (erc-stamp--skip): New internal variable. (erc-stamp--allow-unmanaged): New variable for legacy code to force `erc-add-timestamps' to run when `erc--msg-props' is nil. (erc-add-timestamp): Gate on new flags `erc-stamp--skip' and `erc-stamp--allow-unmanaged'. Don't add `erc-ts' text prop directly. Instead, use `erc--msg-props' facility to defer until after modification hooks. Don't add `cursor-senor-functions' directly either unless compatibility flag is enabled. Instead, expect this to be handled by a post-modify hook. (erc-stamp-prefix-log-filter): Use updated name for timestamp property. (erc-stamp--inherited-props): Add doc string. (erc-insert-timestamp-right): Fix bug involving object cycle where the time-stamp string would appear in its own `display' property. (erc-stamp--insert-date-function, erc-stamp--insert-date-hook): Remove unused internal function-valued interface variable and replace with the latter, a normal hook. (erc-stamp--date-format-end, erc-stamp--propertize-left-date-stamp): New function and auxiliary variable to apply date stamp properties at the post-modify stage. Add text property `erc-stamp-type' to inserted date stamps to help folks distinguish between them and other left-sided stamps. (erc-stamp-date-left-p): New public function for third-party code to detect whether a message is a date stamp. (erc-stamp--current-datestamp-left, erc-stamp--insert-date-stamp-as-phony-message, erc-stamp--lr-date-on-pre-modify): New functions and state variable to help ERC treat date stamps as separate messages while working within the established mechanism for processing inserted messages. Shadow `erc-stamp--invisible-property' when calling `erc-format-timestamp' in order to prevent date stamps from inheriting other `invisible' props. These date stamps are special in that they have no business being hidden along with the current message. (erc-insert-timestamp-left-and-right): On initial run in any buffer, record whether date stamp needs massaging on insertion. Move all business for inserting date stamps to post-modify hooks, but run them forcibly if this is the very first date stamp in the current buffer. Also mention intervals of relevant text props in doc string. (erc-format-timestamp): Don't add `invisible' prop to stamp unless `erc-stamp--invisible-property' is non-nil. (erc-stamp--csf-props-updated-p): New local variable. (erc-munge-invisibility-spec): Restore `cursor-sensor-functions' text property for existing messages when a user enables the option mid-session. Add and remove hooks for use with automatic timestamp echoing. (erc-stamp--add-csf-on-post-modify): New function to add `cursor-sensor-functions' property on post-modify hooks. (erc-stamp--setup): Perform some additional teardown. (erc-stamp--on-clear-message): Update timestamp text-property name to `erc-ts'. (erc-echo-timestamp, erc--echo-ts-csf): Use utility to find time-stamp text prop in current message. (erc-stamp--update-saved-position, erc-stamp--reset-on-clear): Use hook `erc-stamp--insert-date-hook' instead of excised variable `erc-stamp--insert-date-function'. * lisp/erc/erc-truncate.el (erc-truncate-buffer-to-size): Use internal utility to find beginning of message. * lisp/erc/erc.el (erc--msg-props, erc--msg-props-overrides): New internal variables for initializing and conveying message meta-data text properties among insert and send hooks. (erc-insert-modify-hook): Mention reserved depth ranges for built-in members in doc string. (erc-send-action): Use convenience variable to modifying text props instead of overriding `erc-insert-pre-hook'. (erc--check-msg-prop, erc--get-inserted-msg-bounds, erc--get-inserted-msg-prop, erc--with-inserted-msg, erc--traverse-inserted): New utility functions and macros to help modules find meta-data and message-delimiting text props. (erc-display-line-1): Ensure the first character of every message in an ERC buffer has the `erc-msg' property. (erc--hide-message): Don't bother offsetting start of first message in a buffer. (erc--ranked-properties, erc--order-text-properties-from-hash): New variable and function to convert `erc--msg-props' into a plist suitable for `add-text-properties'. (erc-display-message): Bind `erc--msg-props' for use by all hooks. Respect `erc--msg-prop-overrides' when non-nil. Don't add `erc-command' property. (erc--own-property-names): Add `erc-stamp-type'. (erc--get-speaker-bounds): Use helper to find message start. (erc-process-ctcp-query, erc-send-current-line): Use convenience variable to leverage framework for manipulating message meta-data instead of overriding `erc-insert-pre-hook'. (erc-display-msg): Bind `erc--msg-props' for use by all send-related hooks. Add text props from table after `erc-send-post-hook'. (erc-restore-text-properties): Improve doc string. (erc--get-eq-comparable-cmd): Use `if-let' instead of `if-let*'. * test/lisp/erc/erc-fill-tests.el (erc-fill-tests--insert-privmsg): Make fake message more realistic. (erc-fill-tests--wrap-populate): Shorten overlong line. (erc-fill-tests--wrap-check-prefixes): Make test utility more vigilant in asserting no gaps exist in `line-prefix' property interval. (erc-fill-tests--compare): Compare text props on text prop values that are themselves strings. * test/lisp/erc/erc-scenarios-log.el (erc-scenarios-log--clear-stamp): Ensure `erc-stamp' is loaded. * test/lisp/erc/erc-scenarios-match.el (erc-scenarios-match--stamp-left-current-nick, erc-scenarios-match--invisible-stamp): Use `default-value' for `erc-insert-modify-hook' in ordering assertion. (erc-scenarios-match--find-bol, erc-scenarios-match--find-eol): Remove unused assertion helper functions. (erc-scenarios-match--stamp-right-fools-invisible): Remove misplaced ERT tag from function and use utility to find message bounds. (erc-scenarios-match--stamp-right-fools-invisible): Use utility to find message end. (erc-scenarios-match--fill-wrap-stamp-dedented-p): New assertion utility function. (erc-scenarios-match--stamp-both-invisible-fill-wrap) New test. (erc-scenarios-match--stamp-both-invisible-fill-static): Expect `erc-cmd' at beginning of inserted message's filled line, even if it starts with whitespace. Also, add new function parameter `assert-ds', a callback to run when visiting the second date stamp, which is followed by a hidden message. In the test of the same name, expect the date stamp's invisibility interval to begin at the newline after the previous message and to not contain any existing invisibility props, namely, those belonging to the subsequent hidden "fools" message. Also use unified meta-data text prop names. (erc-scenarios-match--stamp-both-invisible-fill-static--nooffset): Expect the date stamp's invisibility interval to match its field's instead of starting and ending sooner. * test/lisp/erc/erc-stamp-tests.el: Put well-known meta-data prop at the start of the message. * test/lisp/erc/erc-tests.el (erc--refresh-prompt): Prevent modules from mutating hooks. (erc--order-text-properties-from-hash, erc--check-msg-props): New tests. * test/lisp/erc/resources/fill/snapshots/merge-01-start.eld: Update test data. * test/lisp/erc/resources/fill/snapshots/merge-02-right.eld: Update test data. * test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld: Update. * test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld: Update. * test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld: Update. * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: Update. (Bug#60936) --- etc/ERC-NEWS | 28 ++- lisp/erc/erc-fill.el | 97 ++++--- lisp/erc/erc-goodies.el | 4 +- lisp/erc/erc-stamp.el | 237 ++++++++++++++---- lisp/erc/erc-truncate.el | 2 +- lisp/erc/erc.el | 164 ++++++++++-- test/lisp/erc/erc-fill-tests.el | 60 +++-- test/lisp/erc/erc-scenarios-log.el | 1 + test/lisp/erc/erc-scenarios-match.el | 205 ++++++++++++--- test/lisp/erc/erc-stamp-tests.el | 2 +- test/lisp/erc/erc-tests.el | 43 +++- .../fill/snapshots/merge-01-start.eld | 2 +- .../fill/snapshots/merge-02-right.eld | 2 +- .../fill/snapshots/merge-wrap-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../fill/snapshots/spacing-01-mono.eld | 2 +- .../fill/snapshots/stamps-left-01.eld | 2 +- 20 files changed, 654 insertions(+), 207 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 284b91bb41f..81c94467f25 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -149,7 +149,7 @@ minor-mode maps, and new third-party modules should do = the same. =20 ** Option 'erc-timestamp-format-right' deprecated. Having to account for this option prevented other ERC modules from -easily determining what right-hand stamps would look like before +easily determining what right-sided stamps would look like before insertion, which is knowledge needed for certain UI decisions. The way ERC has chosen to address this is imperfect and boils down to asking users who've customized this option to switch to @@ -291,11 +291,13 @@ continue to modify non-ERC hooks locally whenever pos= sible, especially in new code. =20 *** ERC now manages timestamp-related properties a bit differently. -For starters, the 'cursor-sensor-functions' property no longer +For starters, the 'cursor-sensor-functions' text property is absent by +default unless the option 'erc-echo-timestamps' is already enabled on +module init. And when present, the property's value no longer contains unique closures and thus no longer proves effective for -traversing messages. To compensate, a new property, 'erc-timestamp', -now spans message bodies but not the newlines delimiting them. Also -affecting the 'stamp' module is the deprecation of the function +traversing inserted messages. For now, ERC only provides an internal +means of visiting messages, but a public interface is forthcoming. +Also affecting the 'stamp' module is the deprecation of the function 'erc-insert-aligned' and its removal from client code. Additionally, the module now merges its 'invisible' property with existing ones and includes all white space around stamps when doing so. @@ -310,6 +312,22 @@ folded onto the next line. Such inconsistency made st= amp detection overly complex and produced uneven results when toggling stamp visibility. =20 +*** Date stamps are independent messages. +ERC now inserts "date stamps" generated from the option +'erc-timestamp-format-left' as separate, standalone messages. (This +only matters if 'erc-insert-timestamp-function' is set to its default +value of 'erc-insert-timestamp-left-and-right'.) ERC's near-term UI +goals require exposing these stamps to existing code designed to +operate on complete messages. For example, users likely expect date +stamps to be togglable with 'erc-toggle-timestamps' while also being +immune to hiding from commands like 'erc-match-toggle-hidden-fools'. +Before this change, meeting such expectations demanded brittle +heuristics that checked for the presence of these stamps in the +leading portion of message bodies as well as special casing to act on +these areas without inflicting collateral damage. From now on, third +parties can instead use the function 'erc-stamp-date-left-p' to detect +and reuse existing code to operate. + *** The role of a module's Custom group is now more clearly defined. Associating built-in modules with Custom groups and provided library features has improved. More specifically, a module's group now enjoys diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 0e6b5a3efb8..62a9597d481 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -158,6 +158,11 @@ erc-fill (when (or erc-fill--function erc-fill-function) ;; skip initial empty lines (goto-char (point-min)) + ;; Note the following search pattern was altered in 5.6 to adapt + ;; to a change in Emacs regexp behavior that turned out to be a + ;; regression (which has since been fixed). The patterns appear + ;; to be equivalent in practice, so this was left as is (wasn't + ;; reverted) to avoid additional git-blame(1)-related churn. (while (and (looking-at (rx bol (* (in " \t")) eol)) (zerop (forward-line 1)))) (unless (eobp) @@ -167,12 +172,10 @@ erc-fill (when-let* ((erc-fill-line-spacing) (p (point-min))) (widen) - (when (or (and-let* ((cmd (get-text-property p 'erc-command))) - (memq cmd erc-fill--spaced-commands)) + (when (or (erc--check-msg-prop 'erc-cmd erc-fill--spaced-comma= nds) (and-let* ((cmd (save-excursion (forward-line -1) - (get-text-property (point) - 'erc-command)))) + (get-text-property (point) 'erc-cm= d)))) (memq cmd erc-fill--spaced-commands))) (put-text-property (1- p) p 'line-spacing erc-fill-line-spacing))))))= )) @@ -181,15 +184,17 @@ erc-fill-static "Fills a text such that messages start at column `erc-fill-static-center= '." (save-restriction (goto-char (point-min)) - (looking-at "^\\(\\S-+\\)") - (let ((nick (match-string 1))) + (when-let (((looking-at "^\\(\\S-+\\)")) + ((not (erc--check-msg-prop 'erc-msg 'datestamp))) + (nick (match-string 1))) + (progn (let ((fill-column (- erc-fill-column (erc-timestamp-offset))) (fill-prefix (make-string erc-fill-static-center 32))) (insert (make-string (max 0 (- erc-fill-static-center (length nick) 1)) 32)) (erc-fill-regarding-timestamp)) - (erc-restore-text-properties)))) + (erc-restore-text-properties))))) =20 (defun erc-fill-variable () "Fill from `point-min' to `point-max'." @@ -423,8 +428,6 @@ fill-wrap (eq (default-value 'erc-insert-timestamp-function) #'erc-insert-timestamp-left))) (setq erc-fill--function #'erc-fill-wrap) - (add-function :after (local 'erc-stamp--insert-date-function) - #'erc-fill--wrap-stamp-insert-prefixed-date) (when erc-fill-wrap-merge (add-hook 'erc-button--prev-next-predicate-functions #'erc-fill--wrap-merged-button-p nil t)) @@ -436,9 +439,7 @@ fill-wrap (kill-local-variable 'erc-fill--function) (kill-local-variable 'erc-fill--wrap-visual-keys) (remove-hook 'erc-button--prev-next-predicate-functions - #'erc-fill--wrap-merged-button-p t) - (remove-function (local 'erc-stamp--insert-date-function) - #'erc-fill--wrap-stamp-insert-prefixed-date)) + #'erc-fill--wrap-merged-button-p t)) 'local) =20 (defvar-local erc-fill--wrap-length-function nil @@ -456,6 +457,9 @@ erc-fill--wrap-last-msg (defvar-local erc-fill--wrap-max-lull (* 24 60 60)) =20 (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\"." (prog1 (and-let* ((m (or erc-fill--wrap-last-msg (setq erc-fill--wrap-last-msg (point-min-marker)) @@ -463,14 +467,11 @@ erc-fill--wrap-continued-message-p ((< (1+ (point-min)) (- (point) 2))) (props (save-restriction (widen) - (when (eq 'erc-timestamp (field-at-pos m)) - (set-marker m (field-end m))) (and-let* - (((eq 'PRIVMSG (get-text-property m 'erc-comman= d))) - ((not (eq (get-text-property m 'erc-ctcp) - 'ACTION))) + (((eq 'PRIVMSG (get-text-property m 'erc-cmd))) + ((not (eq (get-text-property m 'erc-msg) 'ACTI= ON))) (spr (next-single-property-change m 'erc-speak= er))) - (cons (get-text-property m 'erc-timestamp) + (cons (get-text-property m 'erc-ts) (get-text-property spr 'erc-speaker))))) (ts (pop props)) (props) @@ -478,30 +479,23 @@ erc-fill--wrap-continued-message-p ((time-less-p (time-subtract (erc-stamp--current-time) ts) erc-fill--wrap-max-lull)) (speaker (next-single-property-change (point-min) 'erc-speak= er)) - ((not (eq (get-text-property speaker 'erc-ctcp) 'ACTION))) + ((not (erc--check-msg-prop 'erc-ctcp 'ACTION))) (nick (get-text-property speaker 'erc-speaker)) ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) =20 -(defun erc-fill--wrap-stamp-insert-prefixed-date (&rest args) - "Apply `line-prefix' property to args." - (let* ((ts-left (car args)) - (start) - ;; Insert " " to simulate gap between <speaker> and msg beg. - (end (save-excursion (skip-chars-backward "\n") - (setq start (pos-bol)) - (insert " ") - (point))) - (width (if (and erc-fill-wrap-use-pixels - (fboundp 'buffer-text-pixel-size)) - (save-restriction (narrow-to-region start end) - (list (car (buffer-text-pixel-size))= )) - (length (string-trim-left ts-left))))) - (delete-region (1- end) end) - ;; Use `point-min' instead of `start' to cover leading newilnes. - (put-text-property (point-min) (point) 'line-prefix - `(space :width (- erc-fill--wrap-value ,width)))) - args) +(defun erc-fill--wrap-measure (beg end) + "Return display spec width for inserted region between BEG and END. +Ignore any `invisible' props that may be present when figuring." + (if (and erc-fill-wrap-use-pixels (fboundp 'buffer-text-pixel-size)) + ;; `buffer-text-pixel-size' can move point! + (save-excursion + (save-restriction + (narrow-to-region beg end) + (let* ((buffer-invisibility-spec) + (rv (car (buffer-text-pixel-size)))) + (if (zerop rv) 0 (list rv))))) + (- end beg))) =20 ;; An escape hatch for third-party code expecting speakers of ACTION ;; messages to be exempt from `line-prefix'. This could be converted @@ -522,25 +516,28 @@ erc-fill-wrap (when-let ((e (erc--get-speaker-bounds)) (b (pop e)) ((or erc-fill--wrap-action-dedent-p - (not (eq (get-text-property b 'erc-ct= cp) - 'ACTION))))) + (not (erc--check-msg-prop 'erc-ctcp + 'ACTION))))) (goto-char e)) (skip-syntax-forward "^-") (forward-char) - ;; Using the `invisible' property might make more - ;; sense, but that would require coordination - ;; with other modules, like `erc-match'. - (cond ((and erc-fill-wrap-merge + (cond ((erc--check-msg-prop 'erc-msg 'datestamp) + (when erc-fill--wrap-last-msg + (set-marker erc-fill--wrap-last-msg (point-m= in))) + (save-excursion + (goto-char (point-max)) + (skip-chars-backward "\n") + (let ((beg (pos-bol))) + (insert " ") + (prog1 (erc-fill--wrap-measure beg (point)) + (delete-region (1- (point)) (point)))))) + ((and erc-fill-wrap-merge (erc-fill--wrap-continued-message-p)) (put-text-property (point-min) (point) 'display "") 0) - ((and erc-fill-wrap-use-pixels - (fboundp 'buffer-text-pixel-size)) - (save-restriction - (narrow-to-region (point-min) (point)) - (list (car (buffer-text-pixel-size))))) - (t (- (point) (point-min)))))))) + (t + (erc-fill--wrap-measure (point-min) (point))))= )))) (erc-put-text-properties (point-min) (1- (point-max)) ; exclude "\n" '(line-prefix wrap-prefix) nil `((space :width (- erc-fill--wrap-value ,le= n)) diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index b77176d8ac7..d112e63c316 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -339,8 +339,8 @@ erc-scroll-to-bottom ;;;###autoload(autoload 'erc-readonly-mode "erc-goodies" nil t) (define-erc-module readonly nil "This mode causes all inserted text to be read-only." - ((add-hook 'erc-insert-post-hook #'erc-make-read-only) - (add-hook 'erc-send-post-hook #'erc-make-read-only)) + ((add-hook 'erc-insert-post-hook #'erc-make-read-only 70) + (add-hook 'erc-send-post-hook #'erc-make-read-only 70)) ((remove-hook 'erc-insert-post-hook #'erc-make-read-only) (remove-hook 'erc-send-post-hook #'erc-make-read-only))) =20 diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0f3163bf68d..7fc76eb2d73 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,21 +55,22 @@ erc-timestamp-format :type '(choice (const nil) (string))) =20 -;; FIXME remove surrounding whitespace from default value and have -;; `erc-insert-timestamp-left-and-right' add it before insertion. - (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" - "If set to a string, messages will be timestamped. -This string is processed using `format-time-string'. -Good examples are \"%T\" and \"%H:%M\". - -This timestamp is used for timestamps on the left side of the -screen when `erc-insert-timestamp-function' is set to -`erc-insert-timestamp-left-and-right'. - -If nil, timestamping is turned off." - :type '(choice (const nil) - (string))) + "Format recognized by `format-time-string' for date stamps. +Only considered when `erc-insert-timestamp-function' is set to +`erc-insert-timestamp-left-and-right'. Used for displaying date +stamps on their own line, between messages. ERC inserts this +flavor of stamp as a separate \"psuedo message\", so a final +newline isn't necessary. For compatibility, only additional +trailing newlines beyond the first become empty lines. For +example, the default value results in an empty line after the +previous message, followed by the timestamp on its own line, +followed immediately by the next message on the next line. ERC +expects to display these stamps less frequently, so the +formatting specifiers should reflect that. To omit these stamps +entirely, use a different `erc-insert-timestamp-function', such +as `erc-timestamp-format-right'." + :type 'string) =20 (defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. @@ -175,9 +176,9 @@ erc-timestamp-face ;;;###autoload(autoload 'erc-timestamp-mode "erc-stamp" nil t) (define-erc-module stamp timestamp "This mode timestamps messages in the channel buffers." - ((add-hook 'erc-mode-hook #'erc-munge-invisibility-spec) - (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 60) - (add-hook 'erc-send-modify-hook #'erc-add-timestamp 60) + ((add-hook 'erc-mode-hook #'erc-stamp--setup) + (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 79) + (add-hook 'erc-send-modify-hook #'erc-add-timestamp 79) (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) (add-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear) (unless erc--updating-modules-p (erc-buffer-do #'erc-stamp--setup))) @@ -214,18 +215,27 @@ erc-stamp--current-time =20 (cl-defgeneric erc-stamp--current-time () "Return a lisp time object to associate with an IRC message. -This becomes the message's `erc-timestamp' text property." +This becomes the message's `erc-ts' text property." (erc-compat--current-lisp-time)) =20 (cl-defmethod erc-stamp--current-time :around () (or erc-stamp--current-time (cl-call-next-method))) =20 +(defvar erc-stamp--skip nil + "Non-nil means inhibit `erc-add-timestamp' completely.") + +(defvar erc-stamp--allow-unmanaged nil + "Non-nil means `erc-add-timestamp' runs unconditionally. +Escape hatch for third-parties using lower-level API functions, +such as `erc-display-line', directly.") + (defun erc-add-timestamp () "Add timestamp and text-properties to message. =20 This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (progn ; remove this `progn' on next major refactor + (unless (or erc-stamp--skip (and erc-stamp--allow-unmanaged + (not erc--msg-props))) (let* ((ct (erc-stamp--current-time)) (invisible (get-text-property (point-min) 'invisible)) (erc-stamp--invisible-property @@ -233,6 +243,8 @@ erc-add-timestamp (if invisible `(timestamp ,@(ensure-list invisible)) 'timestam= p)) (skipp (and erc-stamp--skip-when-invisible invisible)) (erc-stamp--current-time ct)) + (when erc--msg-props + (puthash 'erc-ts ct erc--msg-props)) (unless skipp (funcall erc-insert-timestamp-function (erc-format-timestamp ct erc-timestamp-format))) @@ -244,12 +256,13 @@ erc-add-timestamp (erc-away-time)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (1- (point-max)) + (when erc-stamp--allow-unmanaged + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions ;; Regions are no longer contiguous ^ - '(erc--echo-ts-csf) 'erc-timestamp ct))))) + '(erc--echo-ts-csf) 'erc-ts ct)))))) =20 (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -362,19 +375,27 @@ erc-stamp-prefix-log-filter (goto-char (point-min)) (while (progn - (when-let* (((< (point) (pos-eol))) - (end (1- (pos-eol))) - ((eq 'erc-timestamp (field-at-pos end))) - (beg (field-beginning end)) - ;; Skip a line that's just a timestamp. - ((> beg (point)))) + (when-let (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) (delete-region beg (1+ end))) - (when-let (time (get-text-property (point) 'erc-timestamp)) + (when-let (time (erc--get-inserted-msg-prop 'erc-ts)) (insert (format-time-string "[%H:%M:%S] " time))) (zerop (forward-line)))) "") =20 -(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) +;; These are currently extended manually, but we could also bind +;; `text-property-default-nonsticky' and call `insert-and-inherit' +;; instead of `insert', but we'd have to pair the props with differing +;; boolean values for left and right stamps. Also, since this hook +;; runs last, we can't expect overriding sticky props to be absent, +;; even though, as of 5.6, `front-sticky' is only added by the +;; `readonly' module after hooks run. +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix) + "Extant properties at the start of a message inherited by the stamp.") =20 (declare-function erc--remove-text-properties "erc" (string)) =20 @@ -573,8 +594,11 @@ erc-insert-timestamp-right ;; intervening white space unless a hard break is warranted. (pcase erc-timestamp-use-align-to ((guard erc-stamp--display-margin-mode) - (put-text-property 0 (length string) - 'display `((margin right-margin) ,string) stri= ng)) + (let ((s (propertize (substring-no-properties string) + 'invisible erc-stamp--invisible-property))) + (put-text-property 0 (length string) 'display + `((margin right-margin) ,s) + string))) ((and 't (guard (< col pos))) (insert " ") (put-text-property from (point) 'display `(space :align-to ,pos))) @@ -599,30 +623,109 @@ erc-insert-timestamp-right (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) =20 -(defvar erc-stamp--insert-date-function #'insert - "Function to insert left \"left-right date\" stamp. -A local module might use this to modify text properties, -`insert-before-markers' or renarrow the region after insertion.") +(defvar erc-stamp--insert-date-hook nil + "Functions appended to send and modify hooks when inserting date stamp.") + +(defvar-local erc-stamp--date-format-end nil + "Substring index marking usable portion of date stamp format.") + +(defun erc-stamp--propertize-left-date-stamp () + (add-text-properties (point-min) (1- (point-max)) + '(field erc-timestamp erc-stamp-type date-left)) + (erc--hide-message 'timestamp)) + +(defun erc-stamp-date-left-p (&optional point) + "Return non-nil if the current message is a \"date stamp\". +Expect callers to know that such stamps originate from +`erc-insert-timestamp-left-and-right' using the format string +`erc-timestamp-format-left'. Expect POINT, when non-nil, to +reside at some known or suspected time stamp. When POINT is nil, +expect to be called from a member of `erc-insert-modify-hook' or +similar." + (cond ((erc--check-msg-prop 'erc-msg 'datestamp)) + (point (eq 'date-left (get-text-property point 'erc-stamp-type))) + (t (erc--with-inserted-msg + (and-let* ((p (text-property-not-all + (point-min) (point-max) 'field 'erc-timestamp))) + (eq 'date-left (get-text-property p 'erc-stamp-type))))))) + +;; A kludge to pass state from insert hook to nested insert hook. +(defvar erc-stamp--current-datestamp-left nil) + +;; Calling `erc-display-message' from within a hook it's currently +;; running is roundabout, but it's a definite means of ensuring hooks +;; can act on the date stamp as a standalone message to do things like +;; adjust invisibility props. +(defun erc-stamp--insert-date-stamp-as-phony-message (string) + (cl-assert (string-empty-p string)) + (setq string erc-stamp--current-datestamp-left) + (cl-assert string) + (let ((erc-stamp--skip t) + (erc--msg-props (map-into `((erc-msg . datestamp) + (erc-ts . ,erc-stamp--current-time)) + 'hash-table)) + (erc-send-modify-hook `(,@erc-send-modify-hook + erc-stamp--propertize-left-date-stamp + ,@erc-stamp--insert-date-hook)) + (erc-insert-modify-hook `(,@erc-insert-modify-hook + erc-stamp--propertize-left-date-stamp + ,@erc-stamp--insert-date-hook))) + (erc-display-message nil nil (current-buffer) string) + (setq erc-timestamp-last-inserted-left string))) + +(defun erc-stamp--lr-date-on-pre-modify (_) + (unless erc-stamp--date-format-end + ;; Don't add text properties to the trailing newline. + (setq erc-stamp--date-format-end + (if (string-suffix-p "\n" erc-timestamp-format-left) -1 0))) + (when-let ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + ;; Ignore existing prop value because date stamps should + ;; never be hideable except via `timestamp'. + (rendered (let (erc-stamp--invisible-property) + (erc-format-timestamp + ct (substring erc-timestamp-format-left + 0 erc-stamp--date-format-end)))) + ((not (string-equal rendered erc-timestamp-last-inserted-left= ))) + (erc-stamp--current-datestamp-left rendered) + (erc-insert-timestamp-function + #'erc-stamp--insert-date-stamp-as-phony-message)) + (save-restriction + (narrow-to-region (or erc--insert-marker erc-insert-marker) + (or erc--insert-marker erc-insert-marker)) + (let (erc-timestamp-format erc-away-timestamp-format) + (erc-add-timestamp))))) =20 (defun erc-insert-timestamp-left-and-right (string) "Insert a stamp on either side when it changes. When the deprecated option `erc-timestamp-format-right' is nil, use STRING, which originates from `erc-timestamp-format', for the right-hand stamp. Use `erc-timestamp-format-left' for the -left-hand stamp and expect it to change less frequently." +left-hand stamp and expect it to change less frequently. Include +line endings found in `erc-timestamp-format-left' (or affixed by +ERC) as part of the `erc-timestamp' field, which extends to the +start of the message proper. Do this so other code knows the +stamp is part of the subsequent IRC message even though it may +appear on its own line. However, allow the stamp's `invisible' +property to span a different interval, in order to satisfy newer +folding requirements related to `erc-legacy-invisible-bounds-p'. +Additionally, ensure every date stamp formatted with the option +`erc-timestamp-format-left' is marked as such so that modules can +easily distinguish between other left-sided stamps and date +stamps inserted by this function." + (unless erc-stamp--date-format-end + (add-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify -95 = t) + (add-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modify -= 95 t) + (let ((erc--insert-marker (point-min-marker))) + (set-marker-insertion-type erc--insert-marker t) + (erc-stamp--lr-date-on-pre-modify nil) + (narrow-to-region erc--insert-marker (point-max)) + (set-marker erc--insert-marker nil))) (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) (ts-right (with-suppressed-warnings ((obsolete erc-timestamp-format-right)) (if erc-timestamp-format-right (erc-format-timestamp ct erc-timestamp-format-rig= ht) string)))) - ;; insert left timestamp - (unless (string-equal ts-left erc-timestamp-last-inserted-left) - (goto-char (point-min)) - (erc-put-text-property 0 (length ts-left) 'field 'erc-timestamp ts-l= eft) - (funcall erc-stamp--insert-date-function ts-left) - (setq erc-timestamp-last-inserted-left ts-left)) ;; insert right timestamp (let ((erc-timestamp-only-if-changed-flag t) (erc-timestamp-last-inserted erc-timestamp-last-inserted-right)) @@ -639,8 +742,9 @@ erc-format-timestamp (let ((ts (format-time-string format time erc-stamp--tz))) (erc-put-text-property 0 (length ts) 'font-lock-face 'erc-timestamp-face ts) - (erc-put-text-property 0 (length ts) 'invisible - erc-stamp--invisible-property ts) + (when erc-stamp--invisible-property + (erc-put-text-property 0 (length ts) 'invisible + erc-stamp--invisible-property ts)) ;; N.B. Later use categories instead of this harmless, but ;; inelegant, hack. -- BPT (and erc-timestamp-intangible @@ -649,6 +753,8 @@ erc-format-timestamp ts) "")) =20 +(defvar-local erc-stamp--csf-props-updated-p nil) + ;; This function is used to munge `buffer-invisibility-spec' to an ;; appropriate value. Currently, it only handles timestamps, thus its ;; location. If you add other features which affect invisibility, @@ -661,10 +767,23 @@ erc-munge-invisibility-spec (cursor-intangible-mode -1))) (if erc-echo-timestamps (progn + (dolist (hook '(erc-insert-post-hook erc-send-post-hook)) + (add-hook hook #'erc-stamp--add-csf-on-post-modify nil t)) + (erc--restore-initialize-priors erc-stamp-mode + erc-stamp--csf-props-updated-p nil) + (unless (or erc-stamp--allow-unmanaged erc-stamp--csf-props-update= d-p) + (setq erc-stamp--csf-props-updated-p t) + (let ((erc--msg-props (map-into '((erc-ts . t)) 'hash-table))) + (with-silent-modifications + (erc--traverse-inserted (point-min) erc-insert-marker + #'erc-stamp--add-csf-on-post-modify)= ))) (cursor-sensor-mode +1) ; idempotent (when (>=3D emacs-major-version 29) (add-function :before-until (local 'clear-message-function) #'erc-stamp--on-clear-message))) + (dolist (hook '(erc-insert-post-hook erc-send-post-hook)) + (remove-hook hook #'erc-stamp--add-csf-on-post-modify t)) + (kill-local-variable 'erc-stamp--csf-props-updated-p) (when (bound-and-true-p cursor-sensor-mode) (cursor-sensor-mode -1)) (remove-function (local 'clear-message-function) @@ -673,12 +792,22 @@ erc-munge-invisibility-spec (add-to-invisibility-spec 'timestamp) (remove-from-invisibility-spec 'timestamp))) =20 +(defun erc-stamp--add-csf-on-post-modify () + "Add `cursor-sensor-functions' to narrowed buffer." + (when (erc--check-msg-prop 'erc-ts) + (put-text-property (point-min) (1- (point-max)) + 'cursor-sensor-functions '(erc--echo-ts-csf)))) + (defun erc-stamp--setup () "Enable or disable buffer-local `erc-stamp-mode' modifications." (if erc-stamp-mode (erc-munge-invisibility-spec) (let (erc-echo-timestamps erc-hide-timestamps erc-timestamp-intangible) - (erc-munge-invisibility-spec)))) + (erc-munge-invisibility-spec)) + ;; Undo local mods from `erc-insert-timestamp-left-and-right'. + (remove-hook 'erc-insert-pre-hook #'erc-stamp--lr-date-on-pre-modify t) + (remove-hook 'erc-send-pre-functions #'erc-stamp--lr-date-on-pre-modif= y t) + (kill-local-variable 'erc-stamp--date-format-end))) =20 (defun erc-hide-timestamps () "Hide timestamp information from display." @@ -714,7 +843,7 @@ erc-stamp--last-stamp (defun erc-stamp--on-clear-message (&rest _) "Return `dont-clear-message' when operating inside the same stamp." (and erc-stamp--last-stamp erc-echo-timestamps - (eq (get-text-property (point) 'erc-timestamp) erc-stamp--last-stam= p) + (eq (erc--get-inserted-msg-prop 'erc-ts) erc-stamp--last-stamp) 'dont-clear-message)) =20 (defun erc-echo-timestamp (dir stamp &optional zone) @@ -724,7 +853,7 @@ erc-echo-timestamp interpret a \"raw\" prefix as UTC. To specify a zone for use with the option `erc-echo-timestamps', see the companion option `erc-echo-timestamp-zone'." - (interactive (list nil (get-text-property (point) 'erc-timestamp) + (interactive (list nil (erc--get-inserted-msg-prop 'erc-ts) (pcase current-prefix-arg ((and (pred numberp) v) (if (<=3D (abs v) 14) (* v 3600) v)) @@ -738,18 +867,18 @@ erc-echo-timestamp (setq erc-stamp--last-stamp nil)))) =20 (defun erc--echo-ts-csf (_window _before dir) - (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (erc-echo-timestamp dir (erc--get-inserted-msg-prop 'erc-ts))) =20 (defun erc-stamp--update-saved-position (&rest _) - (remove-function (local 'erc-stamp--insert-date-function) - #'erc-stamp--update-saved-position) - (move-marker erc-last-saved-position (1- (point)))) + (remove-hook 'erc-stamp--insert-date-hook + #'erc-stamp--update-saved-position t) + (move-marker erc-last-saved-position (1- (point-max)))) =20 (defun erc-stamp--reset-on-clear (pos) "Forget last-inserted stamps when POS is at insert marker." (when (=3D pos (1- erc-insert-marker)) - (add-function :after (local 'erc-stamp--insert-date-function) - #'erc-stamp--update-saved-position) + (add-hook 'erc-stamp--insert-date-hook + #'erc-stamp--update-saved-position 0 t) (setq erc-timestamp-last-inserted nil erc-timestamp-last-inserted-left nil erc-timestamp-last-inserted-right nil))) diff --git a/lisp/erc/erc-truncate.el b/lisp/erc/erc-truncate.el index 48d8408a85a..3350cbd13b7 100644 --- a/lisp/erc/erc-truncate.el +++ b/lisp/erc/erc-truncate.el @@ -102,7 +102,7 @@ erc-truncate-buffer-to-size ;; Truncate at message boundary (formerly line boundary ;; before 5.6). (goto-char end) - (goto-char (or (previous-single-property-change (point) 'erc-com= mand) + (goto-char (or (erc--get-inserted-msg-bounds 'beg) (pos-bol))) (setq end (point)) ;; try to save the current buffer using diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index f3c480f918b..891689d8faa 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -135,9 +135,11 @@ erc-scripts "Running scripts at startup and with /LOAD." :group 'erc) =20 -;; Forward declarations -(defvar erc-message-parsed) +(defvar erc-message-parsed) ; only known to this file +(defvar erc--msg-props nil) +(defvar erc--msg-prop-overrides nil) =20 +;; Forward declarations (defvar tabbar--local-hlf) (defvar motif-version-string) (defvar gtk-version-string) @@ -1139,9 +1141,13 @@ erc-insert-modify-hook "Insertion hook for functions that will change the text's appearance. This hook is called just after `erc-insert-pre-hook' when the value of `erc-insert-this' is t. -While this hook is run, narrowing is in effect and `current-buffer' is -the buffer where the text got inserted. One possible value to add here -is `erc-fill'." + +ERC runs this hook with the buffer narrowed to the bounds of the +inserted message plus a trailing newline. Built-in modules place +their hook members at depths between 20 and 80, with those from +the stamp module always running last. Use the functions +`erc-find-parsed-property' and `erc-get-parsed-vector' to locate +and extract the `erc-response' object for the inserted message." :group 'erc-hooks :type 'hook) =20 @@ -2854,11 +2860,10 @@ erc-toggle-debug-irc-protocol (defun erc-send-action (tgt str &optional force) "Send CTCP ACTION information described by STR to TGT." (erc-send-ctcp-message tgt (format "ACTION %s" str) force) - (let ((erc-insert-pre-hook - (cons (lambda (s) ; Leave newline be. - (put-text-property 0 (1- (length s)) 'erc-command 'PRIVMS= G s) - (put-text-property 0 (1- (length s)) 'erc-ctcp 'ACTION s)) - erc-insert-pre-hook)) + ;; Allow hooks that act on inserted PRIVMSG and NOTICES to process us. + (let ((erc--msg-prop-overrides '((erc-msg . msg) + (erc-cmd . PRIVMSG) + (erc-ctcp . ACTION))) (nick (erc-current-nick))) (setq nick (propertize nick 'erc-speaker nick)) (erc-display-message nil '(t action input) (current-buffer) @@ -2917,6 +2922,66 @@ erc--refresh-prompt (delete-region (point) (1- erc-input-marker)))) (run-hooks 'erc--refresh-prompt-hook))) =20 +(define-inline erc--check-msg-prop (prop &optional val) + "Return value for PROP in `erc--msg-props' when populated. +If VAL is a list, return non-nil if PROP appears in VAL. If VAL +is otherwise non-nil, return non-nil if VAL compares `eq' to the +stored value. Otherwise, return the stored value." + (inline-letevals (prop val) + (let ((v (make-symbol "v"))) + `(and-let* ((erc--msg-props) + (,v (gethash ,prop erc--msg-props))) + (if (consp ,val) (memq ,v ,val) (if ,val (eq ,v ,val) ,v)))))) + +(defmacro erc--get-inserted-msg-bounds (&optional only point) + `(let* ((point ,(or point '(point))) + (at-start-p (get-text-property point 'erc-msg))) + (and-let* + (,@(and (member only '(nil 'beg)) + '((b (or (and at-start-p point) + (and-let* + ((p (previous-single-property-change point + 'erc-ms= g))) + (if (=3D p (1- point)) point (1- p))))))) + ,@(and (member only '(nil 'end)) + '((e (1- (next-single-property-change + (if at-start-p (1+ point) point) + 'erc-msg nil erc-insert-marker)))))) + ,(pcase only + ('(quote beg) 'b) + ('(quote end) 'e) + (_ '(cons b e)))))) + +(defun erc--get-inserted-msg-prop (prop) + "Return the value of text property PROP for some message at point." + (and-let* ((stack-pos (erc--get-inserted-msg-bounds 'beg))) + (get-text-property stack-pos prop))) + +(defmacro erc--with-inserted-msg (&rest body) + "Simulate buffer narrowing of send insert hooks for BODY. +Note that this does not wrap BODY in `with-silent-modifications'. +Similarly, it does not bind a temporary `erc--msg-props' table." + `(when-let ((bounds (erc--get-inserted-msg-bounds))) + (save-restriction + (narrow-to-region (car bounds) (1+ (cdr bounds))) + ,@body))) + +(defun erc--traverse-inserted (beg end fn) + "Visit messages between BEG and END and run FN in narrowed buffer." + (setq end (min end (marker-position erc-insert-marker))) + (save-excursion + (goto-char beg) + (let ((b (if (get-text-property (point) 'erc-msg) + (point) + (next-single-property-change (point) 'erc-msg nil end)))) + (while-let ((b) + ((< b end)) + (e (next-single-property-change (1+ b) 'erc-msg nil end)= )) + (save-restriction + (narrow-to-region b e) + (funcall fn)) + (setq b e))))) + (defvar erc--insert-marker nil) =20 (defun erc-display-line-1 (string buffer) @@ -2963,7 +3028,13 @@ erc-display-line-1 (run-hooks 'erc-insert-post-hook) (when erc-remove-parsed-property (remove-text-properties (point-min) (point-max) - '(erc-parsed nil tags nil)))) + '(erc-parsed nil tags nil))) + (cl-assert (> (- (point-max) (point-min)) 1)) + (let ((props (if erc--msg-props + (erc--order-text-properties-from-hash + erc--msg-props) + '(erc-msg unknown)))) + (add-text-properties (point-min) (1+ (point-min)) prop= s))) (erc--refresh-prompt))))) (run-hooks 'erc-insert-done-hook) (erc-update-undo-list (- (or (marker-position (or erc--insert-mark= er @@ -3094,7 +3165,11 @@ erc-legacy-invisible-bounds-p =20 (defun erc--hide-message (value) "Apply `invisible' text-property with VALUE to current message. -Expect to run in a narrowed buffer during message insertion." +Expect to run in a narrowed buffer during message insertion. +Begin the invisible interval at the previous message's trailing +newline and end before the current message's. If the preceding +message ends in a double newline or there is no previous message, +don't bother including the preceding newline." (if erc-legacy-invisible-bounds-p ;; Before ERC 5.6, this also used to add an `intangible' ;; property, but the docs say it's now obsolete. @@ -3103,8 +3178,25 @@ erc--hide-message (end (point-max))) (save-restriction (widen) + (when (or (<=3D beg 4) (=3D ?\n (char-before (- beg 2)))) + (cl-incf beg)) (erc--merge-prop (1- beg) (1- end) 'invisible value))))) =20 +(defvar erc--ranked-properties '(erc-msg erc-ts erc-cmd)) + +(defun erc--order-text-properties-from-hash (table) + "Return a plist of text props from items in table. +Ensure props in `erc--ranked-properties' appear last and in +reverse order so that they end up sorted in buffer interval +plists for retrieval by `text-properties-at' and friends." + (let (out) + (dolist (k erc--ranked-properties) + (when-let ((v (gethash k table))) + (remhash k table) + (setq out (nconc (list k v) out)))) + (maphash (lambda (k v) (setq out (nconc (list k v) out))) table) + out)) + (defun erc-display-message-highlight (type string) "Highlight STRING according to TYPE, where erc-TYPE-face is an ERC face. =20 @@ -3335,6 +3427,21 @@ erc-display-message (let ((string (if (symbolp msg) (apply #'erc-format-message msg args) msg)) + (erc--msg-props + (or erc--msg-props + (let* ((table (make-hash-table :size 5)) + (cmd (and parsed (erc--get-eq-comparable-cmd + (erc-response.command parsed)))) + (m (cond ((and msg (symbolp msg)) msg) + ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg)) + (t 'unknown)))) + (puthash 'erc-msg m table) + (when cmd + (puthash 'erc-cmd cmd table)) + (and erc--msg-prop-overrides + (pcase-dolist (`(,k . ,v) erc--msg-prop-overrides) + (puthash k v table))) + table))) (erc-message-parsed parsed)) (setq string (cond @@ -3353,9 +3460,6 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (put-text-property - 0 (length string) 'erc-command - (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parse= d) string)) @@ -4818,6 +4922,7 @@ 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 @@ -5305,7 +5410,7 @@ erc--get-speaker-bounds Assume buffer is narrowed to the confines of an inserted message." (inline-quote (and-let* - (((memq (get-text-property (point) 'erc-command) '(PRIVMSG NOTICE))) + (((erc--check-msg-prop 'erc-msg 'msg)) (beg (or (and (get-text-property (point-min) 'erc-speaker) (point-= min)) (next-single-property-change (point-min) 'erc-speaker)))) (cons beg (next-single-property-change beg 'erc-speaker))))) @@ -5630,11 +5735,8 @@ erc-process-ctcp-query (while queries (let* ((type (upcase (car (split-string (car queries))))) (hook (intern-soft (concat "erc-ctcp-query-" type "-hook"= ))) - (erc-insert-pre-hook - (cons (lambda (s) - (put-text-property 0 (1- (length s)) 'erc-ctcp - (intern type) s)) - erc-insert-pre-hook))) + (erc--msg-prop-overrides `((erc-msg . msg) + (erc-ctcp . ,(intern type))))) (if (and hook (boundp hook)) (if (string-equal type "ACTION") (run-hook-with-args-until-success @@ -6639,7 +6741,8 @@ erc-send-current-line (when-let (((not (erc--input-split-abortp state))) (inhibit-read-only t) (old-buf (current-buffer))) - (progn ; unprogn this during next major surgery + (let ((erc--msg-prop-overrides '((erc-cmd . PRIVMSG) + (erc-msg . msg)))) (erc-set-active-buffer (current-buffer)) ;; Kill the input and the prompt (delete-region erc-input-marker (erc-end-of-input-line)) @@ -6786,17 +6889,24 @@ erc-display-msg (save-excursion (erc--assert-input-bounds) (let ((insert-position (marker-position (goto-char erc-insert-marker= ))) + (erc--msg-props (or erc--msg-props + (map-into (cons '(erc-msg . self) + erc--msg-prop-overrides) + '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) - (erc-put-text-property insert-position (point) 'erc-command 'PRIVM= SG) (insert "\n") (save-restriction (narrow-to-region insert-position (point)) (run-hooks 'erc-send-modify-hook) - (run-hooks 'erc-send-post-hook)) + (run-hooks 'erc-send-post-hook) + (cl-assert (> (- (point-max) (point-min)) 1)) + (add-text-properties (point-min) (1+ (point-min)) + (erc--order-text-properties-from-hash + erc--msg-props))) (erc--refresh-prompt))))) =20 (defun erc-command-symbol (command) @@ -8184,8 +8294,8 @@ erc-find-parsed-property (text-property-not-all (point-min) (point-max) 'erc-parsed nil)) =20 (defun erc-restore-text-properties () - "Restore the property `erc-parsed' for the region." - (when-let* ((parsed-posn (erc-find-parsed-property)) + "Ensure the `erc-parsed' and `tags' props cover the entire message." + (when-let ((parsed-posn (erc-find-parsed-property)) (found (erc-get-parsed-vector parsed-posn))) (put-text-property (point-min) (point-max) 'erc-parsed found) (when-let ((tags (get-text-property parsed-posn 'tags))) @@ -8214,7 +8324,7 @@ erc--get-eq-comparable-cmd See also `erc-message-type'." ;; IRC numerics are three-digit numbers, possibly with leading 0s. ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) - (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n= )) + (if-let ((n (string-to-number command)) ((zerop n))) (intern command) n)) =20 ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index b81d0c15558..8f0c8f9ccf4 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -31,10 +31,14 @@ erc-fill-tests--time-vals =20 (defun erc-fill-tests--insert-privmsg (speaker &rest msg-parts) (declare (indent 1)) - (let ((msg (erc-format-privmessage speaker - (apply #'concat msg-parts) nil t))) - (put-text-property 0 (length msg) 'erc-command 'PRIVMSG msg) - (erc-display-message nil nil (current-buffer) msg))) + (let* ((msg (erc-format-privmessage speaker + (apply #'concat msg-parts) nil t)) + ;; (erc--msg-prop-overrides '((erc-msg . msg) (erc-cmd . PRIVMSG)= )) + (parsed (make-erc-response :unparsed msg :sender speaker + :command "PRIVMSG" + :command-args (list "#chan" msg) + :contents msg))) + (erc-display-message parsed nil (current-buffer) msg))) =20 (defun erc-fill-tests--wrap-populate (test) (let ((original-window-buffer (window-buffer (selected-window))) @@ -75,8 +79,8 @@ erc-fill-tests--wrap-populate =20 (erc-fill-tests--insert-privmsg "alice" "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.") + "What was done to Elbow's wife, that he hath cause to complain= of?" + " Come me to what was done to her.") =20 ;; Introduce an artificial gap in properties `line-prefix' and ;; `wrap-prefix' and later ensure they're not incremented twice. @@ -111,6 +115,14 @@ erc-fill-tests--wrap-check-prefixes (should (get-text-property (pos-bol) 'line-prefix)) (should (get-text-property (1- (pos-eol)) 'line-prefix)) (should-not (get-text-property (pos-eol) 'line-prefix)) + ;; Spans entire line uninterrupted. + (let* ((val (get-text-property (pos-bol) 'line-prefix)) + (end (text-property-not-all (pos-bol) (point-max) + 'line-prefix val))) + (when (and (/=3D end (pos-eol)) (=3D ?? (char-before end))) + (setq end (text-property-not-all (1+ end) (point-max) + 'line-prefix val))) + (should (eq end (pos-eol)))) (should (equal (get-text-property (pos-bol) 'wrap-prefix) '(space :width erc-fill--wrap-value))) (should-not (get-text-property (pos-eol) 'wrap-prefix)) @@ -145,7 +157,7 @@ erc-fill-tests--compare (number-to-string erc-fill--wrap-value) (prin1-to-string got)))) (with-current-buffer (generate-new-buffer name) - (push name erc-fill-tests--buffers) + (push (current-buffer) erc-fill-tests--buffers) (with-silent-modifications (insert (setq got (read repr)))) (erc-mode)) @@ -153,15 +165,31 @@ erc-fill-tests--compare (with-temp-file expect-file (insert repr)) (if (file-exists-p expect-file) - ;; Compare set-equal over intervals. This comparison is - ;; less useful for messages treated by other modules because - ;; it doesn't compare "nested" props belonging to - ;; string-valued properties, like timestamps. - (should (equal-including-properties - (read repr) - (read (with-temp-buffer - (insert-file-contents-literally expect-file) - (buffer-string))))) + ;; Ensure string-valued properties, like timestamps, aren't + ;; recursive (signals `max-lisp-eval-depth' exceeded). + (named-let assert-equal + ((latest (read repr)) + (expect (read (with-temp-buffer + (insert-file-contents-literally expect-file) + (buffer-string))))) + (pcase latest + ((or "" 'nil) t) + ((pred stringp) + (should (equal-including-properties latest expect)) + (let ((latest-intervals (object-intervals latest)) + (expect-intervals (object-intervals expect))) + (while-let ((l-iv (pop latest-intervals)) + (x-iv (pop expect-intervals)) + (l-tab (map-into (nth 2 l-iv) 'hash-table)) + (x-tab (map-into (nth 2 x-iv) 'hash-table))) + (pcase-dolist (`(,l-k . ,l-v) (map-pairs l-tab)) + (assert-equal l-v (gethash l-k x-tab)) + (remhash l-k x-tab)) + (should (zerop (hash-table-count x-tab)))))) + ((pred sequencep) + (assert-equal (seq-first latest) (seq-first expect)) + (assert-equal (seq-rest latest) (seq-rest expect))) + (_ (should (equal latest expect))))) (message "Snapshot file missing: %S" expect-file))))) =20 ;; To inspect variable pitch, set `erc-mode-hook' to diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenari= os-log.el index fd030d90c2f..f7e7d61c92e 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -81,6 +81,7 @@ erc-scenarios-log--kill-hook =20 (ert-deftest erc-scenarios-log--clear-stamp () :tags '(:expensive-test) + (require 'erc-stamp) (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "base/assoc/bouncer-history") (dumb-server (erc-d-run "localhost" t 'foonet)) diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scena= rios-match.el index cd899fddb98..864f3881ab1 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -55,7 +55,8 @@ erc-scenarios-match--stamp-left-current-nick :nick "tester") ;; Module `timestamp' follows `match' in insertion hooks. (should (memq 'erc-add-timestamp - (memq 'erc-match-message erc-insert-modify-hook))) + (memq 'erc-match-message + (default-value 'erc-insert-modify-hook)))) ;; The "match type" is `current-nick'. (funcall expect 5 "tester") (should (eq (get-text-property (1- (point)) 'font-lock-face) @@ -91,7 +92,8 @@ erc-scenarios-match--invisible-stamp :nick "tester") ;; Module `timestamp' follows `match' in insertion hooks. (should (memq 'erc-add-timestamp - (memq 'erc-match-message erc-insert-modify-hook))) + (memq 'erc-match-message + (default-value 'erc-insert-modify-hook)))) (funcall expect 5 "This server is in debug mode"))) =20 (ert-info ("Ensure lines featuring \"bob\" are invisible") @@ -151,29 +153,13 @@ erc-scenarios-match--stamp-left-fools-invisible (=3D (next-single-property-change msg-beg 'invisible nil (pos-eo= l)) (pos-eol)))))))) =20 -(defun erc-scenarios-match--find-bol () - (save-excursion - (should (get-text-property (1- (point)) 'erc-command)) - (goto-char (should (previous-single-property-change (point) 'erc-comma= nd))) - (pos-bol))) - -(defun erc-scenarios-match--find-eol () - (save-excursion - (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. (defun erc-scenarios-match--stamp-right-fools-invisible () - :tags '(:expensive-test) (let ((erc-insert-timestamp-function #'erc-insert-timestamp-right)) (erc-scenarios-match--invisible-stamp =20 (lambda () - (let ((beg (erc-scenarios-match--find-bol)) - (end (erc-scenarios-match--find-eol))) + (pcase-let ((`(,beg . ,end) (erc--get-inserted-msg-bounds))) ;; The end of the message is a newline. (should (=3D ?\n (char-after end))) =20 @@ -205,7 +191,7 @@ erc-scenarios-match--stamp-right-fools-invisible (should (=3D (next-single-property-change msg-end 'invisible) e= nd))))) =20 (lambda () - (let ((end (erc-scenarios-match--find-eol))) + (let ((end (cdr (erc--get-inserted-msg-bounds)))) ;; This message has a time stamp like all the others. (should (eq (field-at-pos (1- end)) 'erc-timestamp)) =20 @@ -271,7 +257,117 @@ erc-scenarios-match--stamp-right-invisible-fill-wrap (let ((inv-beg (next-single-property-change (1- (pos-bol)) 'invisib= le))) (should (eq (get-text-property inv-beg 'invisible) 'timestamp))))= ))) =20 -(defun erc-scenarios-match--stamp-both-invisible-fill-static () +(defun erc-scenarios-match--fill-wrap-stamp-dedented-p (point) + (pcase (get-text-property point 'line-prefix) + (`(space :width (- erc-fill--wrap-value (,n))) + (if (display-graphic-p) (< 100 n 200) (< 10 n 30))) + (`(space :width (- erc-fill--wrap-value ,n)) + (< 10 n 30)))) + +(ert-deftest erc-scenarios-match--stamp-both-invisible-fill-wrap () + + ;; Rewind the clock to known date artificially. We should probably + ;; use a ticks/hz cons on 29+. + (let ((erc-stamp--current-time 704591940) + (erc-stamp--tz t) + (erc-fill-function #'erc-fill-wrap) + (bob-utterance-counter 0)) + + (erc-scenarios-match--invisible-stamp + + (lambda () + (ert-info ("Baseline check") + ;; False date printed initially before anyone speaks. + (when (zerop bob-utterance-counter) + (save-excursion + (goto-char (point-min)) + (search-forward "[Wed Apr 29 1992]") + ;; First stamp in a buffer is not invisible from previous + ;; newline (before stamp's own leading newline). + (should (=3D 4 (match-beginning 0))) + (should (get-text-property 3 'invisible)) + (should-not (get-text-property 2 'invisible)) + (should (erc-scenarios-match--fill-wrap-stamp-dedented-p 4)) + (search-forward "[23:59]")))) + + (ert-info ("Line endings in Bob's messages are invisible") + ;; The message proper has the `invisible' property `match-fools'. + (should (eq (get-text-property (pos-bol) 'invisible) 'match-fools= )) + (pcase-let ((`(,mbeg . ,mend) (erc--get-inserted-msg-bounds))) + (should (=3D (char-after mend) ?\n)) + (should-not (field-at-pos mend)) + (should-not (field-at-pos mbeg)) + + (when (=3D bob-utterance-counter 1) + (let ((right-stamp (field-end mbeg))) + (should (eq 'erc-timestamp (field-at-pos right-stamp))) + (should (=3D mend (field-end right-stamp))) + (should (eq (field-at-pos (1- mend)) 'erc-timestamp)))) + + ;; The `erc-ts' property is present in prop stack. + (should (get-text-property (pos-bol) 'erc-ts)) + (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts= )) + + ;; Line ending has the `invisible' property `match-fools'. + (should (eq (get-text-property mbeg 'invisible) 'match-fools)) + (should-not (get-text-property mend 'invisible)))) + + ;; Only the message right after Alice speaks contains stamps. + (when (=3D 1 bob-utterance-counter) + + (ert-info ("Date stamp occupying previous line is invisible") + (should (eq 'match-fools (get-text-property (point) 'invisible)= )) + (save-excursion + (forward-line -1) + (goto-char (pos-bol)) + (should (looking-at (rx "[Mon May 4 1992]"))) + (ert-info ("Stamp's NL `invisible' as fool, not timestamp") + (let ((end (match-end 0))) + (should (eq (char-after end) ?\n)) + (should (eq 'timestamp + (get-text-property (1- end) 'invisible))) + (should (eq 'match-fools + (get-text-property end 'invisible))))) + (should (erc-scenarios-match--fill-wrap-stamp-dedented-p (poi= nt))) + ;; Date stamp has a combined `invisible' property value + ;; that starts at the previous message's trailing newline + ;; and extends until the start of the message proper. + (should (equal ?\n (char-before (point)))) + (should (equal ?\n (char-before (1- (point))))) + (let ((val (get-text-property (- (point) 2) 'invisible))) + (should (equal val 'timestamp)) + (should (=3D (text-property-not-all (- (point) 2) (point-ma= x) + 'invisible val) + (pos-eol)))))) + + (ert-info ("Current message's RHS stamp is hidden") + ;; Right stamp has `match-fools' property. + (save-excursion + (should-not (field-at-pos (point))) + (should (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp))) + + ;; Stamp invisibility starts where message's ends. + (let ((msgend (next-single-property-change (pos-bol) 'invisible= ))) + ;; Stamp has a combined `invisible' property value. + (should (equal (get-text-property msgend 'invisible) + '(timestamp match-fools))) + + ;; Combined `invisible' property spans entire timestamp. + (should (=3D (next-single-property-change msgend 'invisible) + (pos-eol)))))) + + (cl-incf bob-utterance-counter)) + + ;; Alice. + (lambda () + ;; Set clock ahead a week or so. + (setq erc-stamp--current-time 704962800) + + ;; This message has no time stamp and is completely visible. + (should-not (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp)) + (should-not (next-single-property-change (pos-bol) 'invisible)))))) + +(defun erc-scenarios-match--stamp-both-invisible-fill-static (assert-ds) (should (eq erc-insert-timestamp-function #'erc-insert-timestamp-left-and-right)) =20 @@ -295,21 +391,20 @@ erc-scenarios-match--stamp-both-invisible-fill-static (ert-info ("Line endings in Bob's messages are invisible") ;; 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))) + (pcase-let ((`(,mbeg . ,mend) (erc--get-inserted-msg-bounds))) =20 - (if (/=3D 1 bob-utterance-counter) - (should-not (field-at-pos mend)) + (should (=3D (char-after mend) ?\n)) + (should-not (field-at-pos mbeg)) + (should-not (field-at-pos mend)) + (when (=3D 1 bob-utterance-counter) ;; For Bob's stamped message, check newline after stamp. - (should (eq (field-at-pos mend) 'erc-timestamp)) - (setq mend (field-end mend))) + (should (eq (field-at-pos (field-end mbeg)) 'erc-timestamp)) + (should (eq (field-at-pos (1- mend)) 'erc-timestamp))) =20 - ;; The `erc-timestamp' property spans entire messages, - ;; including stamps and filled text, which makes for - ;; convenient traversal when `erc-stamp-mode' is enabled. - (should (get-text-property (pos-bol) 'erc-timestamp)) - (should (=3D (next-single-property-change (pos-bol) 'erc-timest= amp) - mend)) + ;; The `erc-ts' property is present in the message's + ;; width 1 prop collection at its first char. + (should (get-text-property (pos-bol) 'erc-ts)) + (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts= )) =20 ;; Line ending has the `invisible' property `match-fools'. (should (=3D (char-after mend) ?\n)) @@ -327,12 +422,8 @@ erc-scenarios-match--stamp-both-invisible-fill-static (forward-line -1) (goto-char (pos-bol)) (should (looking-at (rx "[Mon May 4 1992]"))) - ;; 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 match-fools))) - (should (=3D (next-single-property-change (point) 'invisible) - (1+ (pos-eol)))))) + (should (=3D ?\n (char-after (- (point) 2)))) ; welcome!\n + (funcall assert-ds))) ; "assert date stamp" =20 (ert-info ("Folding preserved despite invisibility") ;; Message has a trailing time stamp, but it's been folded @@ -365,13 +456,45 @@ erc-scenarios-match--stamp-both-invisible-fill-static =20 (ert-deftest erc-scenarios-match--stamp-both-invisible-fill-static () :tags '(:expensive-test) - (erc-scenarios-match--stamp-both-invisible-fill-static)) + (erc-scenarios-match--stamp-both-invisible-fill-static + + (lambda () + ;; Date stamp has an `invisible' property that starts from the + ;; newline delimiting the current and previous messages and + ;; extends until the stamp's final newline. It is not combined + ;; with the old value, `match-fools'. + (let ((delim-pos (- (point) 2))) + (should (equal 'timestamp (get-text-property delim-pos 'invisible))) + ;; Stamp-only invisibility ends before its last newline. + (should (=3D (text-property-not-all delim-pos (point-max) + 'invisible 'timestamp) + (match-end 0))))))) ; pos-eol =20 (ert-deftest erc-scenarios-match--stamp-both-invisible-fill-static--nooffs= et () :tags '(:expensive-test) (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) (should-not erc-legacy-invisible-bounds-p) + (let ((erc-legacy-invisible-bounds-p t)) - (erc-scenarios-match--stamp-both-invisible-fill-static)))) + (erc-scenarios-match--stamp-both-invisible-fill-static + + (lambda () + ;; Date stamp has an `invisible' property that covers its + ;; format string exactly. It is not combined with the old + ;; value, `match-fools'. + (let ((delim-prev (- (point) 2))) + (should-not (get-text-property delim-prev 'invisible)) + (should (eq 'erc-timestamp (field-at-pos (point)))) + (should (=3D (next-single-property-change delim-prev 'invisible) + (field-beginning (point)))) + (should (equal 'timestamp + (get-text-property (1- (point)) 'invisible))) + ;; Field stops before final newline because the date stamp + ;; is (now, as of ERC 5.6) its own standalone message. + (should (=3D ?\n (char-after (field-end (point))))) + ;; Stamp-only invisibility includes last newline. + (should (=3D (text-property-not-all (1- (point)) (point-max) + 'invisible 'timestamp) + (1+ (field-end (point))))))))))) =20 ;;; erc-scenarios-match.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tes= ts.el index 46a05729066..cc61d599387 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -279,7 +279,7 @@ erc-echo-timestamp =20 (should-not erc-echo-timestamps) (should-not erc-stamp--last-stamp) - (insert (propertize "abc" 'erc-timestamp 433483200)) + (insert (propertize "a" 'erc-ts 433483200 'erc-msg 'msg) "bc") (goto-char (point-min)) (let ((inhibit-message t) (erc-echo-timestamp-format "%Y-%m-%d %H:%M:%S %Z") diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 11717217eb2..408cc4db10c 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -292,6 +292,8 @@ erc--refresh-prompt (cl-incf counter)))) erc-accidental-paste-threshold-seconds erc-insert-modify-hook + (erc-modules (remq 'stamp erc-modules)) + (erc-send-input-line-function #'ignore) (erc--input-review-functions erc--input-review-functions) erc-send-completed-hook) =20 @@ -356,7 +358,8 @@ erc--refresh-prompt (should (looking-back "#chan@ServNet 11> ")) (should (=3D (point) erc-input-marker)) (insert "/query bob") - (erc-send-current-line) + (let (erc-modules) + (erc-send-current-line)) ;; Last command not inserted (save-excursion (forward-line -1) (should (looking-at "<tester> Howdy"))) @@ -1431,6 +1434,44 @@ erc-process-input-line =20 (should-not calls)))))) =20 +(ert-deftest erc--order-text-properties-from-hash () + (let ((table (map-into '((a . 1) + (erc-ts . 0) + (erc-msg . s005) + (b . 2) + (erc-cmd . 5) + (c . 3)) + 'hash-table))) + (with-temp-buffer + (erc-mode) + (insert "abc\n") + (add-text-properties 1 2 (erc--order-text-properties-from-hash table= )) + (should (equal '( erc-msg s005 + erc-ts 0 + erc-cmd 5 + a 1 + b 2 + c 3) + (text-properties-at (point-min))))))) + +(ert-deftest erc--check-msg-prop () + (let ((erc--msg-props (map-into '((a . 1) (b . x)) 'hash-table))) + (should (eq 1 (erc--check-msg-prop 'a))) + (should (erc--check-msg-prop 'a 1)) + (should-not (erc--check-msg-prop 'a 2)) + + (should (eq 'x (erc--check-msg-prop 'b))) + (should (erc--check-msg-prop 'b 'x)) + (should-not (erc--check-msg-prop 'b 1)) + + (should (erc--check-msg-prop 'a '(1 42))) + (should-not (erc--check-msg-prop 'a '(2 42))) + + (let ((props '(42 x))) + (should (erc--check-msg-prop 'b props))) + (let ((v '(42 y))) + (should-not (erc--check-msg-prop 'b v))))) + (defmacro erc-tests--equal-including-properties (a b) (list (if (< emacs-major-version 29) 'ert-equal-including-properties diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-01-start.eld index 689bacc7012..238d8cc73c2 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 20 (erc-timestamp 0 line= -prefix (space :width (- 27 (18))) field erc-timestamp) 20 21 (erc-timestam= p 0 field erc-timestamp) 21 183 (erc-timestamp 0 wrap-prefix #2=3D(space :w= idth 27) line-prefix #3=3D(space :width (- 27 (4)))) 183 190 (erc-timestamp= 0 field erc-timestamp wrap-prefix #2# line-prefix #3# display #1=3D(#7=3D(= margin right-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible ti= mestamp invisible timestamp font-lock-face erc-timestamp-face)))) 191 192 (= erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 27 (8))) = erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-prefix #= 4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #2# line= -prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-command PRIVM= SG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-command PR= IVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-prefix #5=3D(space :wi= dth (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-timestamp 0 wrap-prefix #= 2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-timestamp 0 wrap-prefi= x #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-timestamp 0 wrap-pr= efix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (erc-timestamp 0 wrap= -prefix #2# line-prefix #5# erc-command PRIVMSG) 436 454 (erc-timestamp 168= 0332400 line-prefix (space :width (- 27 (18))) field erc-timestamp) 454 455= (erc-timestamp 1680332400 field erc-timestamp) 455 456 (erc-timestamp 1680= 332400 wrap-prefix #2# line-prefix #6=3D(space :width (- 27 (6))) erc-comma= nd PRIVMSG) 456 459 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 6# erc-command PRIVMSG) 459 466 (erc-timestamp 1680332400 wrap-prefix #2# l= ine-prefix #6# erc-command PRIVMSG) 466 473 (erc-timestamp 1680332400 field= erc-timestamp wrap-prefix #2# line-prefix #6# display #8=3D(#7# #("[07:00]= " 0 7 (display #8# isearch-open-invisible timestamp invisible timestamp fon= t-lock-face erc-timestamp-face)))) 474 475 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #9=3D(space :width (- 27 (8))) erc-command PRIVMSG) 4= 75 480 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9# erc-comman= d PRIVMSG) 480 486 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9= # erc-command PRIVMSG) 487 488 (erc-timestamp 1680332400 wrap-prefix #2# li= ne-prefix #10=3D(space :width (- 27 0)) display #11=3D"" erc-command PRIVMS= G) 488 493 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #10# displ= ay #11# erc-command PRIVMSG) 493 495 (erc-timestamp 1680332400 wrap-prefix = #2# line-prefix #10# display #11# erc-command PRIVMSG) 495 499 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #10# erc-command PRIVMSG) 500 501= (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #12=3D(space :width = (- 27 (6))) erc-command PRIVMSG) 501 504 (erc-timestamp 1680332400 wrap-pre= fix #2# line-prefix #12# erc-command PRIVMSG) 504 512 (erc-timestamp 168033= 2400 wrap-prefix #2# line-prefix #12# erc-command PRIVMSG) 513 514 (erc-tim= estamp 1680332400 wrap-prefix #2# line-prefix #13=3D(space :width (- 27 0))= display #11# erc-command PRIVMSG) 514 517 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #13# display #11# erc-command PRIVMSG) 517 519 (erc-t= imestamp 1680332400 wrap-prefix #2# line-prefix #13# display #11# erc-comma= nd PRIVMSG) 519 524 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 13# erc-command PRIVMSG) 525 526 (erc-timestamp 1680332400 wrap-prefix #2# = line-prefix #14=3D(space :width (- 27 (8))) erc-command PRIVMSG) 526 531 (e= rc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-command PRIVMS= G) 531 538 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-c= ommand PRIVMSG) 539 540 (erc-timestamp 1680332400 wrap-prefix #2# line-pref= ix #15=3D(space :width (- 27 0)) display #11# erc-command PRIVMSG) 540 545 = (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #15# display #11# erc= -command PRIVMSG) 545 547 (erc-timestamp 1680332400 wrap-prefix #2# line-pr= efix #15# display #11# erc-command PRIVMSG) 547 551 (erc-timestamp 16803324= 00 wrap-prefix #2# line-prefix #15# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 27 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 27 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 27 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 27 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 27 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 27 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 27 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 27 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/te= st/lisp/erc/resources/fill/snapshots/merge-02-right.eld index 9fa23a7d332..d1ce9198e69 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 20 (erc-timestamp 0 line= -prefix (space :width (- 29 (18))) field erc-timestamp) 20 21 (erc-timestam= p 0 field erc-timestamp) 21 183 (erc-timestamp 0 wrap-prefix #2=3D(space :w= idth 29) line-prefix #3=3D(space :width (- 29 (4)))) 183 190 (erc-timestamp= 0 field erc-timestamp wrap-prefix #2# line-prefix #3# display #1=3D(#7=3D(= margin right-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible ti= mestamp invisible timestamp font-lock-face erc-timestamp-face)))) 191 192 (= erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 29 (8))) = erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-prefix #= 4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #2# line= -prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-command PRIVM= SG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-command PR= IVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-prefix #5=3D(space :wi= dth (- 29 (6))) erc-command PRIVMSG) 350 353 (erc-timestamp 0 wrap-prefix #= 2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-timestamp 0 wrap-prefi= x #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-timestamp 0 wrap-pr= efix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (erc-timestamp 0 wrap= -prefix #2# line-prefix #5# erc-command PRIVMSG) 436 454 (erc-timestamp 168= 0332400 line-prefix (space :width (- 29 (18))) field erc-timestamp) 454 455= (erc-timestamp 1680332400 field erc-timestamp) 455 456 (erc-timestamp 1680= 332400 wrap-prefix #2# line-prefix #6=3D(space :width (- 29 (6))) erc-comma= nd PRIVMSG) 456 459 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 6# erc-command PRIVMSG) 459 466 (erc-timestamp 1680332400 wrap-prefix #2# l= ine-prefix #6# erc-command PRIVMSG) 466 473 (erc-timestamp 1680332400 field= erc-timestamp wrap-prefix #2# line-prefix #6# display #8=3D(#7# #("[07:00]= " 0 7 (display #8# isearch-open-invisible timestamp invisible timestamp fon= t-lock-face erc-timestamp-face)))) 474 475 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #9=3D(space :width (- 29 (8))) erc-command PRIVMSG) 4= 75 480 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9# erc-comman= d PRIVMSG) 480 486 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9= # erc-command PRIVMSG) 487 488 (erc-timestamp 1680332400 wrap-prefix #2# li= ne-prefix #10=3D(space :width (- 29 0)) display #11=3D"" erc-command PRIVMS= G) 488 493 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #10# displ= ay #11# erc-command PRIVMSG) 493 495 (erc-timestamp 1680332400 wrap-prefix = #2# line-prefix #10# display #11# erc-command PRIVMSG) 495 499 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #10# erc-command PRIVMSG) 500 501= (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #12=3D(space :width = (- 29 (6))) erc-command PRIVMSG) 501 504 (erc-timestamp 1680332400 wrap-pre= fix #2# line-prefix #12# erc-command PRIVMSG) 504 512 (erc-timestamp 168033= 2400 wrap-prefix #2# line-prefix #12# erc-command PRIVMSG) 513 514 (erc-tim= estamp 1680332400 wrap-prefix #2# line-prefix #13=3D(space :width (- 29 0))= display #11# erc-command PRIVMSG) 514 517 (erc-timestamp 1680332400 wrap-p= refix #2# line-prefix #13# display #11# erc-command PRIVMSG) 517 519 (erc-t= imestamp 1680332400 wrap-prefix #2# line-prefix #13# display #11# erc-comma= nd PRIVMSG) 519 524 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 13# erc-command PRIVMSG) 525 526 (erc-timestamp 1680332400 wrap-prefix #2# = line-prefix #14=3D(space :width (- 29 (8))) erc-command PRIVMSG) 526 531 (e= rc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-command PRIVMS= G) 531 538 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #14# erc-c= ommand PRIVMSG) 539 540 (erc-timestamp 1680332400 wrap-prefix #2# line-pref= ix #15=3D(space :width (- 29 0)) display #11# erc-command PRIVMSG) 540 545 = (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #15# display #11# erc= -command PRIVMSG) 545 547 (erc-timestamp 1680332400 wrap-prefix #2# line-pr= efix #15# display #11# erc-command PRIVMSG) 547 551 (erc-timestamp 16803324= 00 wrap-prefix #2# line-prefix #15# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n<alice> one.\n<alice> two.\n<bob> thr= ee.\n<bob> four.\n<Dummy> five.\n<Dummy> six.\n" 2 3 (erc-msg datestamp erc= -ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=3D(spac= e :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc-msg unknown= erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space :width (- 29 (4)))) 22 18= 3 (wrap-prefix #1# line-prefix #2#) 183 190 (field erc-timestamp wrap-prefi= x #1# line-prefix #2# display (#6=3D(margin right-margin) #("[00:00]" 0 7 (= invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) 192 197 (wrap-prefix= #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-prefix #3#) 199 202 (wr= ap-prefix #1# line-prefix #3#) 202 315 (wrap-prefix #1# line-prefix #3#) 31= 6 348 (wrap-prefix #1# line-prefix #3#) 349 350 (erc-msg msg erc-ts 0 erc-c= md PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :width (- 29 (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# lin= e-prefix #4#) 436 437 (erc-msg datestamp erc-ts 1680332400 field erc-timest= amp) 437 454 (field erc-timestamp wrap-prefix #1# line-prefix (space :width= (- 29 (18)))) 455 456 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-= prefix #1# line-prefix #5=3D(space :width (- 29 (6)))) 456 459 (wrap-prefix= #1# line-prefix #5#) 459 466 (wrap-prefix #1# line-prefix #5#) 466 473 (fi= eld erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" = 0 7 (invisible timestamp)))) 474 475 (erc-msg msg erc-ts 1680332400 erc-cmd= PRIVMSG wrap-prefix #1# line-prefix #7=3D(space :width (- 29 (8)))) 475 48= 0 (wrap-prefix #1# line-prefix #7#) 480 486 (wrap-prefix #1# line-prefix #7= #) 487 488 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# l= ine-prefix #8=3D(space :width (- 29 0)) display #9=3D"") 488 493 (wrap-pref= ix #1# line-prefix #8# display #9#) 493 495 (wrap-prefix #1# line-prefix #8= # display #9#) 495 499 (wrap-prefix #1# line-prefix #8#) 500 501 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #10=3D(spa= ce :width (- 29 (6)))) 501 504 (wrap-prefix #1# line-prefix #10#) 504 512 (= wrap-prefix #1# line-prefix #10#) 513 514 (erc-msg msg erc-ts 1680332400 er= c-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 29 0)) dis= play #9#) 514 517 (wrap-prefix #1# line-prefix #11# display #9#) 517 519 (w= rap-prefix #1# line-prefix #11# display #9#) 519 524 (wrap-prefix #1# line-= prefix #11#) 525 526 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-pr= efix #1# line-prefix #12=3D(space :width (- 29 (8)))) 526 531 (wrap-prefix = #1# line-prefix #12#) 531 538 (wrap-prefix #1# line-prefix #12#) 539 540 (e= rc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #1= 3=3D(space :width (- 29 0)) display #9#) 540 545 (wrap-prefix #1# line-pref= ix #13# display #9#) 545 547 (wrap-prefix #1# line-prefix #13# display #9#)= 547 551 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index a3d533c87b5..d70184724ba 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 loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18))) = field erc-timestamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (er= c-timestamp 0 wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :w= idth (- 27 (4)))) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix = #2# line-prefix #3# display #1=3D(#7=3D(margin right-margin) #("[00:00]" 0 = 7 (display #1# invisible timestamp font-lock-face erc-timestamp-face)))) 19= 1 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 27= (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-p= refix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# lin= e-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# = line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #= 2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-comman= d PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-com= mand PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-prefix #5=3D(sp= ace :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-timestamp 0 wrap-p= refix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-timestamp 0 wra= p-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-timestamp 0 = wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (erc-timestamp= 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 436 454 (erc-timest= amp 1680332400 line-prefix (space :width (- 27 (18))) field erc-timestamp) = 454 455 (erc-timestamp 1680332400 field erc-timestamp) 455 456 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #6=3D(space :width (- 27 (6))) er= c-command PRIVMSG) 456 459 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #6# erc-command PRIVMSG) 459 466 (erc-timestamp 1680332400 wrap-prefi= x #2# line-prefix #6# erc-command PRIVMSG) 466 473 (erc-timestamp 168033240= 0 field erc-timestamp wrap-prefix #2# line-prefix #6# display #8=3D(#7# #("= [07:00]" 0 7 (display #8# invisible timestamp font-lock-face erc-timestamp-= face)))) 474 476 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9= =3D(space :width (- 27 (6))) erc-ctcp ACTION erc-command PRIVMSG) 476 479 (= erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9# erc-ctcp ACTION er= c-command PRIVMSG) 479 483 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #9# erc-ctcp ACTION erc-command PRIVMSG) 484 485 (erc-timestamp 16803= 32400 wrap-prefix #2# line-prefix #10=3D(space :width (- 27 (6))) erc-comma= nd PRIVMSG) 485 488 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 10# erc-command PRIVMSG) 488 494 (erc-timestamp 1680332400 wrap-prefix #2# = line-prefix #10# erc-command PRIVMSG) 495 497 (erc-timestamp 1680332400 wra= p-prefix #2# line-prefix #11=3D(space :width (- 27 (2))) erc-ctcp ACTION er= c-command PRIVMSG) 497 500 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #11# erc-ctcp ACTION erc-command PRIVMSG) 500 506 (erc-timestamp 1680= 332400 wrap-prefix #2# line-prefix #11# erc-ctcp ACTION erc-command PRIVMSG= ) 507 508 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #12=3D(spac= e :width (- 27 (6))) erc-command PRIVMSG) 508 511 (erc-timestamp 1680332400= wrap-prefix #2# line-prefix #12# erc-command PRIVMSG) 511 518 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #12# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (fi= eld erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space :wi= dth (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-pref= ix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#)= 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6= =3D(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (= erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(spac= e :width (- 27 (8)))) 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wr= ap-prefix #1# line-prefix #3#) 199 202 (wrap-prefix #1# line-prefix #3#) 20= 2 315 (wrap-prefix #1# line-prefix #3#) 316 348 (wrap-prefix #1# line-prefi= x #3#) 349 350 (erc-msg msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-p= refix #4=3D(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# lin= e-prefix #4#) 360 435 (wrap-prefix #1# line-prefix #4#) 436 437 (erc-msg da= testamp erc-ts 1680332400 field erc-timestamp) 437 454 (field erc-timestamp= wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 455 456 (erc-msg m= sg erc-ts 1680332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #5=3D(spac= e :width (- 27 (6)))) 456 459 (wrap-prefix #1# line-prefix #5#) 459 466 (wr= ap-prefix #1# line-prefix #5#) 466 473 (field erc-timestamp wrap-prefix #1#= line-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 474 = 475 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTION wrap-pre= fix #1# line-prefix #7=3D(space :width (- 27 (6)))) 475 476 (wrap-prefix #1= # line-prefix #7#) 476 479 (wrap-prefix #1# line-prefix #7#) 479 483 (wrap-= prefix #1# line-prefix #7#) 484 485 (erc-msg msg erc-ts 1680332400 erc-cmd = PRIVMSG wrap-prefix #1# line-prefix #8=3D(space :width (- 27 0)) display #9= =3D"") 485 488 (wrap-prefix #1# line-prefix #8# display #9#) 488 490 (wrap-= prefix #1# line-prefix #8# display #9#) 490 494 (wrap-prefix #1# line-prefi= x #8#) 495 496 (erc-msg msg erc-ts 1680332400 erc-cmd PRIVMSG erc-ctcp ACTI= ON wrap-prefix #1# line-prefix #10=3D(space :width (- 27 (2)))) 496 497 (wr= ap-prefix #1# line-prefix #10#) 497 500 (wrap-prefix #1# line-prefix #10#) = 500 506 (wrap-prefix #1# line-prefix #10#) 507 508 (erc-msg msg erc-ts 1680= 332400 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #11=3D(space :width (- 2= 7 0)) display #9#) 508 511 (wrap-prefix #1# line-prefix #11# display #9#) 5= 11 513 (wrap-prefix #1# line-prefix #11# display #9#) 513 518 (wrap-prefix = #1# line-prefix #11#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index 80c9e1d80f5..def97738ce6 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (- 27 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 27 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index e675695f660..be3e2b33cfd 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 29 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 29) line-prefix #3=3D(space :width (- 29 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 29 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 29 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 29) line-prefix (space :width (- 29 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 29 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 29 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index a6070c2e3ff..098257d0b49 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 25 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 25) line-prefix #3=3D(space :width (- 25 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 25 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 25 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 25) line-prefix (space :width (- 25 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 25 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 25 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index 80c9e1d80f5..def97738ce6 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18))) field erc-times= tamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (erc-timestamp 0 w= rap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (- 27 (4))= )) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix #2# line-prefix= #3# display #1=3D((margin right-margin) #("[00:00]" 0 7 (display #1# isear= ch-open-invisible timestamp invisible timestamp font-lock-face erc-timestam= p-face)))) 191 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space= :width (- 27 (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-p= refix #2# line-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wra= p-prefix #2# line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 = wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp= 0 erc-command PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefi= x #4# erc-command PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pr= efix #5=3D(space :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-times= tamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-ti= mestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc= -timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (= erc-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20 (field erc-timesta= mp wrap-prefix #1=3D(space :width 27) line-prefix (space :width (- 27 (18))= )) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-prefix #2=3D(space = :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 190 (field= erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margi= n) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (erc-msg msg erc-ts 0 e= rc-cmd PRIVMSG wrap-prefix #1# line-prefix #3=3D(space :width (- 27 (8)))) = 192 197 (wrap-prefix #1# line-prefix #3#) 197 199 (wrap-prefix #1# line-pre= fix #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-ms= g msg erc-ts 0 erc-cmd PRIVMSG wrap-prefix #1# line-prefix #4=3D(space :wid= th (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-pre= fix #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 = (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/t= est/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 2b8766c27f4..360b3dafafd 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18= ))) field erc-timestamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183= (erc-timestamp 0 wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(spac= e :width (- 27 (4)))) 183 190 (erc-timestamp 0 field erc-timestamp wrap-pre= fix #2# line-prefix #3# display #1=3D((margin right-margin) #("[00:00]" 0 7= (display #1# isearch-open-invisible timestamp invisible timestamp font-loc= k-face erc-timestamp-face)))) 190 191 (line-spacing 0.5) 191 192 (erc-times= tamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 27 (8))) erc-comma= nd PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-co= mmand PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc= -command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# = erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #2# line-prefix #= 4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-command PRIVMSG) 316 3= 48 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-command PRIVMSG) 34= 8 349 (line-spacing 0.5) 349 350 (erc-timestamp 0 wrap-prefix #2# line-pref= ix #5=3D(space :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-timesta= mp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-time= stamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-t= imestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (er= c-timestamp 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 435 436 = (line-spacing 0.5) 436 437 (erc-timestamp 0 wrap-prefix #2# line-prefix #6= =3D(space :width (- 27 0)) display #7=3D"" erc-command PRIVMSG) 437 440 (er= c-timestamp 0 wrap-prefix #2# line-prefix #6# display #7# erc-command PRIVM= SG) 440 442 (erc-timestamp 0 wrap-prefix #2# line-prefix #6# display #7# er= c-command PRIVMSG) 442 466 (erc-timestamp 0 wrap-prefix #2# line-prefix #6#= erc-command PRIVMSG) 466 467 (line-spacing 0.5) 467 484 (erc-timestamp 0 w= rap-prefix #2# line-prefix (space :width (- 27 (4)))) 485 502 (erc-timestam= p 0 wrap-prefix #2# line-prefix (space :width (- 27 (4)))) 502 503 (line-sp= acing 0.5) 503 504 (erc-timestamp 0 wrap-prefix #2# line-prefix #8=3D(space= :width (- 27 (6))) erc-command PRIVMSG) 504 507 (erc-timestamp 0 wrap-pref= ix #2# line-prefix #8# erc-command PRIVMSG) 507 525 (erc-timestamp 0 wrap-p= refix #2# line-prefix #8# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n<bo= b> This buffer is for text.\n*** one two three\n*** four five six\n<bob> So= mebody stop me\n" 2 3 (erc-msg datestamp erc-ts 0 field erc-timestamp) 3 20= (field erc-timestamp wrap-prefix #1=3D(space :width 27) line-prefix (space= :width (- 27 (18)))) 21 22 (erc-msg unknown erc-ts 0 wrap-prefix #1# line-= prefix #2=3D(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix = #2#) 183 190 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (= (margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 190 191 (lin= e-spacing 0.5) 191 192 (erc-msg msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1= # line-prefix #3=3D(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 (wr= ap-prefix #1# line-prefix #3#) 348 349 (line-spacing 0.5) 349 350 (erc-msg = msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #4=3D(space :width= (- 27 (6)))) 350 353 (wrap-prefix #1# line-prefix #4#) 353 355 (wrap-prefi= x #1# line-prefix #4#) 355 360 (wrap-prefix #1# line-prefix #4#) 360 435 (w= rap-prefix #1# line-prefix #4#) 435 436 (line-spacing 0.5) 436 437 (erc-msg= msg erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #5=3D(space :widt= h (- 27 0)) display #6=3D"") 437 440 (wrap-prefix #1# line-prefix #5# displ= ay #6#) 440 442 (wrap-prefix #1# line-prefix #5# display #6#) 442 466 (wrap= -prefix #1# line-prefix #5#) 466 467 (line-spacing 0.5) 467 468 (erc-msg un= known erc-ts 0 wrap-prefix #1# line-prefix #7=3D(space :width (- 27 (4)))) = 468 484 (wrap-prefix #1# line-prefix #7#) 485 486 (erc-msg unknown erc-ts 0= wrap-prefix #1# line-prefix #8=3D(space :width (- 27 (4)))) 486 502 (wrap-= prefix #1# line-prefix #8#) 502 503 (line-spacing 0.5) 503 504 (erc-msg msg= erc-cmd PRIVMSG erc-ts 0 wrap-prefix #1# line-prefix #9=3D(space :width (-= 27 (6)))) 504 507 (wrap-prefix #1# line-prefix #9#) 507 525 (wrap-prefix #= 1# line-prefix #9#)) diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld index f62b65cd170..cd3537d3c94 100644 --- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -1 +1 @@ -#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 9 (erc= -timestamp 0 display (#4=3D(margin left-margin) #("[00:00]" 0 7 (invisible = timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-pre= fix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 27 (4)))) 9 17= 1 (erc-timestamp 0 wrap-prefix #1# line-prefix #2#) 172 179 (erc-timestamp = 0 display (#4# #("[00:00]" 0 7 (invisible timestamp font-lock-face erc-time= stamp-face))) field erc-timestamp wrap-prefix #1# line-prefix #3=3D(space := width (- 27 (8)))) 179 180 (erc-timestamp 0 wrap-prefix #1# line-prefix #3#= erc-command PRIVMSG) 180 185 (erc-timestamp 0 wrap-prefix #1# line-prefix = #3# erc-command PRIVMSG) 185 187 (erc-timestamp 0 wrap-prefix #1# line-pref= ix #3# erc-command PRIVMSG) 187 190 (erc-timestamp 0 wrap-prefix #1# line-p= refix #3# erc-command PRIVMSG) 190 303 (erc-timestamp 0 wrap-prefix #1# lin= e-prefix #3# erc-command PRIVMSG) 303 304 (erc-timestamp 0 erc-command PRIV= MSG) 304 336 (erc-timestamp 0 wrap-prefix #1# line-prefix #3# erc-command P= RIVMSG) 337 344 (erc-timestamp 0 display (#4# #("[00:00]" 0 7 (invisible ti= mestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefi= x #1# line-prefix #5=3D(space :width (- 27 (6)))) 344 345 (erc-timestamp 0 = wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 345 348 (erc-timestamp= 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 348 350 (erc-timest= amp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 350 355 (erc-tim= estamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 355 430 (erc-= timestamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc= -msg unknown erc-ts 0 display #3=3D(#5=3D(margin left-margin) #("[00:00]" 0= 7 (invisible timestamp font-lock-face erc-timestamp-face))) field erc-time= stamp wrap-prefix #1=3D(space :width 27) line-prefix #2=3D(space :width (- = 27 (4)))) 3 9 (display #3# field erc-timestamp wrap-prefix #1# line-prefix = #2#) 9 171 (wrap-prefix #1# line-prefix #2#) 172 173 (erc-msg msg erc-ts 0 = erc-cmd PRIVMSG display #6=3D(#5# #("[00:00]" 0 7 (invisible timestamp font= -lock-face erc-timestamp-face))) field erc-timestamp wrap-prefix #1# line-p= refix #4=3D(space :width (- 27 (8)))) 173 179 (display #6# field erc-timest= amp wrap-prefix #1# line-prefix #4#) 179 180 (wrap-prefix #1# line-prefix #= 4#) 180 185 (wrap-prefix #1# line-prefix #4#) 185 187 (wrap-prefix #1# line= -prefix #4#) 187 190 (wrap-prefix #1# line-prefix #4#) 190 303 (wrap-prefix= #1# line-prefix #4#) 304 336 (wrap-prefix #1# line-prefix #4#) 337 338 (er= c-msg msg erc-ts 0 erc-cmd PRIVMSG display #8=3D(#5# #("[00:00]" 0 7 (invis= ible timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wra= p-prefix #1# line-prefix #7=3D(space :width (- 27 (6)))) 338 344 (display #= 8# field erc-timestamp wrap-prefix #1# line-prefix #7#) 344 345 (wrap-prefi= x #1# line-prefix #7#) 345 348 (wrap-prefix #1# line-prefix #7#) 348 350 (w= rap-prefix #1# line-prefix #7#) 350 355 (wrap-prefix #1# line-prefix #7#) 3= 55 430 (wrap-prefix #1# line-prefix #7#)) \ No newline at end of file --=20 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-command-to-refill-buffer-with-erc-fill-wrap-.patch From fcb34a45afd872361b0dbc8e6bd92ba53b910faa Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 21 Sep 2023 06:54:27 -0700 Subject: [PATCH 7/7] [5.6] Add command to refill buffer with erc-fill-wrap-mode * lisp/erc/erc-fill.el (erc-fill--wrap-rejigger-last-message): New internal variable. (erc-fill--wrap-rejigger-region, erc-fill-wrap-refill-buffer): New command and helper function. * test/lisp/erc/erc-fill-tests.el (erc-fill-tests--simulate-refill): New function for approximating `erc-fill-wrap-refill-buffer' without pauses to accept process output. (erc-fill-wrap--merge): Assert refilling is idempotent. (Bug#60936) --- lisp/erc/erc-fill.el | 70 +++++++++++++++++++++++++++++++++ test/lisp/erc/erc-fill-tests.el | 18 ++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 62a9597d481..8b86cf30bf4 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -543,6 +543,76 @@ erc-fill-wrap `((space :width (- erc-fill--wrap-value ,len)) (space :width erc-fill--wrap-value)))))) +(defvar erc-fill--wrap-rejigger-last-message nil + "Temporary working instance of `erc-fill--wrap-last-msg'.") + +(defun erc-fill--wrap-rejigger-region (start finish on-next repairp) + "Recalculate `line-prefix' from START to FINISH. +After refilling each message, call ON-NEXT with no args. But +stash and restore `erc-fill--wrap-last-msg' before doing so, in +case this module's insert hooks run by way of the process filter. +With REPAIRP, destructively fill gaps and re-merge speakers." + (goto-char start) + (cl-assert (null erc-fill--wrap-rejigger-last-message)) + (let (erc-fill--wrap-rejigger-last-message) + (while-let + (((< (point) finish)) + (beg (if (get-text-property (point) 'line-prefix) + (point) + (next-single-property-change (point) 'line-prefix))) + (val (get-text-property beg 'line-prefix)) + (end (text-property-not-all beg finish 'line-prefix val))) + ;; If this is a left-side stamp on its own line. + (remove-text-properties beg (1+ end) '(line-prefix nil wrap-prefix nil)) + (when-let ((repairp) + (dbeg (text-property-not-all beg end 'display nil)) + ((get-text-property (1+ dbeg) 'erc-speaker)) + (dval (get-text-property dbeg 'display)) + ((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) + beg)) + (erc--msg-props (map-into (text-properties-at pos) 'hash-table)) + (erc-stamp--current-time (gethash 'erc-ts erc--msg-props))) + (save-restriction + (narrow-to-region beg (1+ end)) + (let ((erc-fill--wrap-last-msg erc-fill--wrap-rejigger-last-message)) + (erc-fill-wrap) + (setq erc-fill--wrap-rejigger-last-message + erc-fill--wrap-last-msg)))) + (when on-next + (funcall on-next)) + ;; Skip to end of message upon encountering accidental gaps + ;; introduced by third parties (or bugs). + (if-let (((/= ?\n (char-after end))) + (next (erc--get-inserted-msg-bounds 'end beg))) + (progn + (cl-assert (= ?\n (char-after next))) + (when repairp ; eol <= next + (put-text-property end (pos-eol) 'line-prefix val)) + (goto-char next)) + (goto-char end))))) + +(defun erc-fill-wrap-refill-buffer (repair) + "Recalculate all `fill-wrap' prefixes in the current buffer. +With REPAIR, attempt to destructively fix merged properties." + (interactive "P") + (unless erc-fill-wrap-mode + (user-error "Module `fill-wrap' not active in current buffer.")) + (save-excursion + (with-silent-modifications + (let* ((rep (make-progress-reporter + "Rewrap" 0 (line-number-at-pos erc-insert-marker) 1)) + (seen 0) + (callback (lambda () + (progress-reporter-update rep (cl-incf seen)) + (accept-process-output nil 0.000001)))) + (erc-fill--wrap-rejigger-region (point-min) erc-insert-marker + callback repair) + (progress-reporter-done rep))))) + ;; FIXME use own text property to avoid false positives. (defun erc-fill--wrap-merged-button-p (point) (equal "" (get-text-property point 'display))) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index 8f0c8f9ccf4..f6c4c268017 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -234,6 +234,13 @@ erc-fill-wrap--monospace (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> ") (erc-fill-tests--compare "monospace-04-reset"))))) +(defun erc-fill-tests--simulate-refill () + ;; Simulate `erc-fill-wrap-refill-buffer' synchronously and without + ;; a progress reporter. + (save-excursion + (with-silent-modifications + (erc-fill--wrap-rejigger-region (point-min) erc-insert-marker nil nil)))) + (ert-deftest erc-fill-wrap--merge () :tags '(:unstable) (unless (>= emacs-major-version 29) @@ -245,7 +252,9 @@ erc-fill-wrap--merge (erc-update-channel-member "#chan" "Dummy" "Dummy" t nil nil nil nil nil "fake" "~u" nil nil t) - ;; Set this here so that the first few messages are from 1970 + ;; Set this here so that the first few messages are from 1970. + ;; Following the current date stamp, the speaker isn't merged + ;; even though it's continued: "<bob> zero." (let ((erc-fill-tests--time-vals (lambda () 1680332400))) (erc-fill-tests--insert-privmsg "bob" "zero.") (erc-fill-tests--insert-privmsg "alice" "one.") @@ -267,7 +276,12 @@ erc-fill-wrap--merge (erc-fill-tests--wrap-check-prefixes "*** " "<alice> " "<bob> " "<bob> " "<alice> " "<alice> " "<bob> " "<bob> " "<Dummy> " "<Dummy> ") - (erc-fill-tests--compare "merge-02-right"))))) + (erc-fill-tests--compare "merge-02-right") + + (ert-info ("Command `erc-fill-wrap-refill-buffer' is idempotent") + (kill-buffer (pop erc-fill-tests--buffers)) + (erc-fill-tests--simulate-refill) ; idempotent + (erc-fill-tests--compare "merge-02-right")))))) (ert-deftest erc-fill-wrap--merge-action () :tags '(:unstable) -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 27 Sep 2023 14:00:19 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Sep 27 10:00:19 2023 Received: from localhost ([127.0.0.1]:52209 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qlV5L-0005kN-GP for submit <at> debbugs.gnu.org; Wed, 27 Sep 2023 10:00:19 -0400 Received: from mail-108-mta206.mxroute.com ([136.175.108.206]:39845) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qlV5G-0005k9-Qn for 60936 <at> debbugs.gnu.org; Wed, 27 Sep 2023 10:00:14 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta206.mxroute.com (ZoneMTA) with ESMTPSA id 18ad6f0618b000d7b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 27 Sep 2023 13:59:52 +0000 X-Zone-Loop: c9ba540c1fdfe3fa2200b149aad9187224f889b117a4 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=5R0XOOw4hlybvOUgc0lXSkdMs9uSbdz6iJz9nRR6ERg=; b=ZLC7u6nchf4JPzPebhjtWvL+Eq Q90TuDrvihGxAfhRaxEvHtcLxv6QtOd6+aC90rZi78TaU9wzVxzU3vj/TcDygKkyUAafQNt1sLiyp 0rFMoV62AkUEwmvY3udgfCrStCT8rE7oNC6Lo5Dw7qE5XKUiykwjOxhdZnqS1yeq1V7qZWaVOdUKJ XfflCTyMDm3cuyl9B9dal49WQZIQUnpw78gHFoQ+5eyy+HHQqh06EquOC2kCZxsITIykFq5HXU9i7 abwgLXS0+EoDRBWR1ZB6GdRKIole1Fj7f4DXFsApvJtIRJOvz4NXnUAwFYdl44QKC3EbtgfSTrB80 MGbrpNIw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87a5te47sz.fsf@HIDDEN> (J. P.'s message of "Fri, 22 Sep 2023 07:11:08 -0700") References: <87tu0nao77.fsf@HIDDEN> <87a5te47sz.fsf@HIDDEN> Date: Wed, 27 Sep 2023 06:59:48 -0700 Message-ID: <87pm23yawb.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain v2. Move massaging of `invisible' date-stamp intervals from `erc-fill' to `erc-stamp'. Ensure `erc-timestamp-format-left' has a trailing newline. Add helper for easily removing `invisible' prop members. Ensure `erc-fill' extends the `erc-command' text prop to cover prepended whitespace. Don't add inherited `invisible' props to date stamps. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v1-v2.diff From d8870a3dede52045518dc24a53143295df899943 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 27 Sep 2023 06:33:06 -0700 Subject: [PATCH 0/3] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (3): [5.6] Prefer ticks/hz pairs for some ERC timestamps on 29+ [5.6] Fix date-stamp invisibility in erc-fill-wrap [5.6] Add command to refill buffer with erc-fill-wrap-mode etc/ERC-NEWS | 12 +- lisp/erc/erc-compat.el | 15 +++ lisp/erc/erc-fill.el | 96 +++++++++++---- lisp/erc/erc-stamp.el | 119 ++++++++++++++++--- lisp/erc/erc.el | 61 ++++++++-- test/lisp/erc/erc-scenarios-log.el | 1 + test/lisp/erc/erc-scenarios-match.el | 163 ++++++++++++++++++++++++-- test/lisp/erc/erc-tests.el | 169 +++++++++++++++++++++++++++ 8 files changed, 574 insertions(+), 62 deletions(-) Interdiff: diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 05e933930e2..6743e49cfec 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -149,13 +149,17 @@ minor-mode maps, and new third-party modules should do the same. ** Option 'erc-timestamp-format-right' deprecated. Having to account for this option prevented other ERC modules from -easily determining what right-hand stamps would look like before +easily determining what right-sided stamps would look like before insertion, which is knowledge needed for certain UI decisions. The way ERC has chosen to address this is imperfect and boils down to asking users who've customized this option to switch to -'erc-timestamp-format' instead. If you're affected by this and feel -that some other solution, like automatic migration, is justified, -please make that known on the bug list. +'erc-timestamp-format' instead. Somewhat relatedly, the companion +option 'erc-timestamp-format-left', which determines the look of date +stamps, must now end in a newline. Although this has long been the +case in practice, it's now been made official. As always, if you're +affected by these changes and feel that other solutions, like +automatic migration, are justified, please make that known on the bug +list. ** 'erc-button-alist' and 'erc-nick-popup-alist' have evolved slightly. It's no secret that the 'buttons' module treats potential nicknames diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 4dae578de67..4c376cfbc22 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -444,11 +444,20 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) +;; We can't store (TICKS . HZ) style timestamps on 27 and 28 because +;; `time-less-p' and friends do +;; +;; message("obsolete timestamp with cdr ...", ...) +;; decode_lisp_time(_, WARN_OBSOLETE_TIMESTAMPS, ...) +;; lisp_time_struct(...) +;; time_cmp(...) +;; +;; which spams *Messages* (and stderr when running the test suite). (defmacro erc-compat--current-lisp-time () - "Return `current-time' as a frequency pair." + "Return `current-time' as a (TICKS . HZ) pair on 29+." (if (>= emacs-major-version 29) '(let (current-time-list) (current-time)) - '(time-convert nil t))) + '(current-time))) (provide 'erc-compat) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 78b29b51cf7..b419fb57bd4 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -488,20 +488,19 @@ erc-fill--wrap-measure "Return display spec width for inserted region between BEG and END. Ignore any `invisible' props that may be present when figuring." (if (and erc-fill-wrap-use-pixels (fboundp 'buffer-text-pixel-size)) - (save-restriction - (narrow-to-region beg end) - (let (buffer-invisibility-spec) - (list (car (buffer-text-pixel-size))))) + ;; `buffer-text-pixel-size' can move point! + (save-excursion + (save-restriction + (narrow-to-region beg end) + (let (buffer-invisibility-spec) + (list (car (buffer-text-pixel-size)))))) (- end beg))) (defun erc-fill--wrap-stamp-insert-prefixed-date (&rest _) "Apply `line-prefix' property to args. -Expect a multi-line \"date\" stamp, similar to that provided by -the default value of `erc-timestamp-format-left'. Add -`erc-stamp-type' property with the symbol `date-left' as its -value. Possibly adjust invisibility interval to begin at the -previous newline and extend until the end of the last line of the -stamp, not including its line ending." +Expect a multiline \"date\" stamp ending in a newline, similar to +the default value of `erc-timestamp-format-left'. Omit the +`line-prefix' from any trailing newlines." (let* ((beg) ;; Insert " " to simulate gap between <speaker> and msg beg. (end (save-excursion (skip-chars-backward "\n") @@ -510,18 +509,8 @@ erc-fill--wrap-stamp-insert-prefixed-date (point))) (width (erc-fill--wrap-measure beg end))) (delete-region (1- end) end) - ;; Offset existing invisibility bounds by decrementing. See - ;; `erc-legacy-invisible-bounds-p'. - (when-let ((invisible (get-text-property (point) 'invisible)) - (min (point-min))) - (save-restriction - (widen) - (remove-text-properties (max 1 (1- min)) (1+ (point)) '(invisible nil)) - (narrow-to-region min (1+ (point))) - (erc--hide-message invisible))) - (put-text-property (point-min) (point) 'erc-stamp-type 'date-left) ;; Use `point-min' instead of `beg' to cover leading newilnes. - (put-text-property (point-min) (point) 'line-prefix + (put-text-property (point-min) (1- end) 'line-prefix `(space :width (- erc-fill--wrap-value ,width))))) ;; An escape hatch for third-party code expecting speakers of ACTION diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 4e16906c550..68dd1f287cf 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,21 +55,35 @@ erc-timestamp-format :type '(choice (const nil) (string))) -;; FIXME remove surrounding whitespace from default value and have -;; `erc-insert-timestamp-left-and-right' add it before insertion. +(defun erc-stamp--custom-trailing-newline-p (_ value) + "Return non-nil if VALUE ends in a newline." + (string-suffix-p "\n" value)) -(defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" - "If set to a string, messages will be timestamped. -This string is processed using `format-time-string'. -Good examples are \"%T\" and \"%H:%M\". - -This timestamp is used for timestamps on the left side of the -screen when `erc-insert-timestamp-function' is set to -`erc-insert-timestamp-left-and-right'. +(defun erc-stamp--custom-validate-date-stamp (widget) + "Fail unless WIDGET's value ends in a newline." + (unless (string-suffix-p "\n" (widget-value widget)) + (widget-put widget :error "Value lacks a trailing newline") + widget)) -If nil, timestamping is turned off." - :type '(choice (const nil) - (string))) +(defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" + "Format recognized by `format-time-string' for date stamps. +Only considered when `erc-insert-timestamp-function' is set to +`erc-insert-timestamp-left-and-right'. Used for displaying date +stamps on their own line, between messages. As of ERC 5.6, this +module appends a trailing newline on insertion if needed. Any +extra newlines, leading or trailing, become empty lines. For +example, the default value results in an empty line after the +previous message, followed by the timestamp on its own line, +followed immediately by the next message on the next line. ERC +expects to display these stamps less frequently, so the +formatting specifiers should reflect that. To omit these stamps +entirely, use a different `erc-insert-timestamp-function', such +as `erc-timestamp-format-right'." + :type '(string :validate erc-stamp--custom-validate-date-stamp + :match erc-stamp--custom-trailing-newline-p) + :set (lambda (sym val) + (set-default sym + (if (string-suffix-p "\n" val) val (concat val "\n"))))) (defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. @@ -374,7 +388,15 @@ erc-stamp-prefix-log-filter (zerop (forward-line)))) "") -(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) +;; These are currently extended manually, but we could also bind +;; `text-property-default-nonsticky' and call `insert-and-inherit' +;; instead of `insert', but we'd have to pair the props with differing +;; boolean values for left and right stamps. Also, since this hook +;; runs last, we can't expect overriding sticky props to be absent, +;; even though, as of 5.6, `front-sticky' is only added by the +;; `readonly' module after hooks run. +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix) + "Extant properties at the start of a message inherited by the stamp.") (declare-function erc--remove-text-properties "erc" (string)) @@ -604,21 +626,69 @@ erc-stamp--insert-date-function A local module might use this to modify text properties, `insert-before-markers' or renarrow the region after insertion.") +(defun erc-stamp--decrement-date-invisibility-bounds () + "Extend `invisible' prop to previous newline before date stamp. +And apply original prop value from message body to any trailing +newlines after date." + (let ((beg (point-min))) + (save-restriction + (widen) + (when (and (> beg 4) (= (char-before beg) ?\n)) + (when-let ((this (get-text-property (point) 'invisible)) + (prev (get-text-property (1- beg) 'invisible)) + ((not (equal this prev)))) + (put-text-property (1- beg) beg 'invisible + (seq-difference (ensure-list prev) + (ensure-list this)))) + (put-text-property (1- beg) beg 'invisible 'timestamp))) + (cl-assert (= ?\n (char-before (point)))) + ;; Only decrement bounds by one. Additional newlines in the + ;; timestamp must be hidden. + (if-let ((existing (remq 'timestamp + (ensure-list erc-stamp--invisible-property)))) + (put-text-property (1- (point)) (point) 'invisible + (if (cdr existing) existing (car existing))) + (erc--remove-from-prop-value-list + (1- (point)) (point) 'invisible 'timestamp)))) + +(defvar-local erc-stamp--checked-date-string-p nil + "Non-nil if date string has been validated for current buffer.") + (defun erc-insert-timestamp-left-and-right (string) "Insert a stamp on either side when it changes. When the deprecated option `erc-timestamp-format-right' is nil, use STRING, which originates from `erc-timestamp-format', for the right-hand stamp. Use `erc-timestamp-format-left' for the left-hand stamp and expect it to change less frequently. Include -line endings present in `erc-timestamp-format-left' as part of -the `erc-timestamp' field, which extends to the start of the -message proper. Do this so other code knows the stamp is part of -the subsequent IRC message even though it may appear on its own -line. However, allow the stamp's `invisible' property to span a -different interval, in order to satisfy newer folding -requirements related to `erc-legacy-invisible-bounds-p'." +line endings found in `erc-timestamp-format-left' (or affixed by +ERC) as part of the `erc-timestamp' field, which extends to the +start of the message proper. Do this so other code knows the +stamp is part of the subsequent IRC message even though it may +appear on its own line. However, allow the stamp's `invisible' +property to span a different interval, in order to satisfy newer +folding requirements related to `erc-legacy-invisible-bounds-p'. +Additionally, ensure every date stamp formatted with the option +`erc-timestamp-format-left' has the property `erc-stamp-type' set +to the symbol `date-left' so that modules can easily distinguish +between other left-sided stamps and date stamps inserted by this +function." + (unless erc-stamp--checked-date-string-p + (setq erc-stamp--checked-date-string-p t) + (unless (string-suffix-p "\n" erc-timestamp-format-left) + (setq erc-timestamp-format-left + (concat erc-timestamp-format-left "\n")) + (unless erc--target + (erc-button--display-error-notice-with-keys + (current-buffer) + "ERC only supports values of `%s' that end in a ?\\n." + " Changing value for current session to: %s." + " Update your config accordingly to silence this message." + 'erc-timestamp-format-left + (let ((print-escape-newlines t)) + (prin1-to-string erc-timestamp-format-left)))))) (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-left (let ((erc-stamp--invisible-property 'timestamp)) + (erc-format-timestamp ct erc-timestamp-format-left))) (ts-right (with-suppressed-warnings ((obsolete erc-timestamp-format-right)) (if erc-timestamp-format-right @@ -627,8 +697,14 @@ erc-insert-timestamp-left-and-right ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) - (erc-put-text-property 0 (length ts-left) 'field 'erc-timestamp ts-left) + (add-text-properties 0 (length ts-left) + '(field erc-timestamp erc-stamp-type date-left) + ts-left) (funcall erc-stamp--insert-date-function ts-left) + (unless (with-suppressed-warnings + ((obsolete erc-legacy-invisible-bounds-p)) + erc-legacy-invisible-bounds-p) + (erc-stamp--decrement-date-invisibility-bounds)) (setq erc-timestamp-last-inserted-left ts-left)) ;; insert right timestamp (let ((erc-timestamp-only-if-changed-flag t) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index e4b0cd0ddbe..db2e20c800e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1128,9 +1128,13 @@ erc-insert-modify-hook "Insertion hook for functions that will change the text's appearance. This hook is called just after `erc-insert-pre-hook' when the value of `erc-insert-this' is t. -While this hook is run, narrowing is in effect and `current-buffer' is -the buffer where the text got inserted. One possible value to add here -is `erc-fill'." + +ERC runs this hook with the buffer narrowed to the bounds of the +inserted message plus a trailing newline. Built-in modules place +their hook members at depths between 20 and 80, with those from +the stamp module always running last. Use the functions +`erc-find-parsed-property' and `erc-get-parsed-vector' to locate +and extract the `erc-response' object for the inserted message." :group 'erc-hooks :type 'hook) @@ -3037,6 +3041,30 @@ erc--merge-prop old (get-text-property pos prop object) end (next-single-property-change pos prop object to))))) +(defun erc--remove-from-prop-value-list (from to prop val &optional object) + "Remove VAL from text prop value between FROM and TO. +If current value is VAL itself, remove the property entirely. +When VAL is a list, act as if this function were called +repeatedly with VAL set to each of VAL's members." + (let ((old (get-text-property from prop object)) + (pos from) + (end (next-single-property-change from prop object to)) + new) + (while (< pos to) + (when old + (if (setq new (and (consp old) (if (consp val) + (seq-difference old val) + (remq val old)))) + (put-text-property pos end prop + (if (cdr new) new (car new)) object) + (when (pcase val + ((pred consp) (or (consp old) (memq old val))) + (_ (if (consp old) (memq val old) (eq old val)))) + (remove-text-properties pos end (list prop nil) object)))) + (setq pos end + old (get-text-property pos prop object) + end (next-single-property-change pos prop object to))))) + (defvar erc-legacy-invisible-bounds-p nil "Whether to hide trailing rather than preceding newlines. Beginning in ERC 5.6, invisibility extends from a message's @@ -8078,13 +8106,21 @@ erc-find-parsed-property "Find the next occurrence of the `erc-parsed' text property." (text-property-not-all (point-min) (point-max) 'erc-parsed nil)) +(defvar erc--persistent-message-properties '(erc-command)) + (defun erc-restore-text-properties () - "Restore the property `erc-parsed' for the region." - (when-let* ((parsed-posn (erc-find-parsed-property)) - (found (erc-get-parsed-vector parsed-posn))) + "Ensure the `erc-parsed' property covers the narrowed buffer. +Do this for other properties added by `erc-display-message' and +for those named in `erc--persistent-message-properties'." + (when-let ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) (put-text-property (point-min) (point-max) 'erc-parsed found) (when-let ((tags (get-text-property parsed-posn 'tags))) - (put-text-property (point-min) (point-max) 'tags tags)))) + (put-text-property (point-min) (point-max) 'tags tags)) + (let ((to (max (point-min) (1- (point-max))))) + (dolist (prop erc--persistent-message-properties) + (when-let ((val (get-text-property parsed-posn prop))) + (put-text-property (point-min) to prop val)))))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -8109,7 +8145,7 @@ erc--get-eq-comparable-cmd See also `erc-message-type'." ;; IRC numerics are three-digit numbers, possibly with leading 0s. ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) - (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + (if-let ((n (string-to-number command)) ((zerop n))) (intern command) n)) ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenarios-log.el index fd030d90c2f..f7e7d61c92e 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -81,6 +81,7 @@ erc-scenarios-log--kill-hook (ert-deftest erc-scenarios-log--clear-stamp () :tags '(:expensive-test) + (require 'erc-stamp) (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "base/assoc/bouncer-history") (dumb-server (erc-d-run "localhost" t 'foonet)) diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scenarios-match.el index bf74806207d..bc06d58c3e9 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -328,20 +328,25 @@ erc-scenarios-match--stamp-both-invisible-fill-wrap ;; Line ending has the `invisible' property `match-fools'. (should (= (char-after mend) ?\n)) - (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) - (if erc-legacy-invisible-bounds-p - (should (eq (get-text-property mend 'invisible) 'match-fools)) - (should (eq (get-text-property mbeg 'invisible) 'match-fools)) - (should-not (get-text-property mend 'invisible)))))) + (should (eq (get-text-property mbeg 'invisible) 'match-fools)) + (should-not (get-text-property mend 'invisible)))) ;; Only the message right after Alice speaks contains stamps. (when (= 1 bob-utterance-counter) (ert-info ("Date stamp occupying previous line is invisible") + (should (eq 'match-fools (get-text-property (point) 'invisible))) (save-excursion (forward-line -1) (goto-char (pos-bol)) (should (looking-at (rx "[Mon May 4 1992]"))) + (ert-info ("Stamp's NL `invisible' as fool, not timestamp") + (let ((end (match-end 0))) + (should (eq (char-after end) ?\n)) + (should (eq 'timestamp + (get-text-property (1- end) 'invisible))) + (should (eq 'match-fools + (get-text-property end 'invisible))))) (should (erc-scenarios-match--fill-wrap-stamp-dedented-p (point))) ;; Date stamp has a combined `invisible' property value ;; that starts at the previous message's trailing newline @@ -349,7 +354,7 @@ erc-scenarios-match--stamp-both-invisible-fill-wrap (should (equal ?\n (char-before (point)))) (should (equal ?\n (char-before (1- (point))))) (let ((val (get-text-property (- (point) 2) 'invisible))) - (should (equal val '(timestamp match-fools))) + (should (equal val 'timestamp)) (should (= (text-property-not-all (- (point) 2) (point-max) 'invisible val) (pos-eol)))))) @@ -381,7 +386,7 @@ erc-scenarios-match--stamp-both-invisible-fill-wrap (should-not (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp)) (should-not (next-single-property-change (pos-bol) 'invisible)))))) -(defun erc-scenarios-match--stamp-both-invisible-fill-static () +(defun erc-scenarios-match--stamp-both-invisible-fill-static (assert-ds) (should (eq erc-insert-timestamp-function #'erc-insert-timestamp-left-and-right)) @@ -405,7 +410,8 @@ erc-scenarios-match--stamp-both-invisible-fill-static (ert-info ("Line endings in Bob's messages are invisible") ;; 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)) + (let* ((mbeg (and (get-text-property (pos-bol) 'erc-command) + (pos-bol))) (mend (next-single-property-change mbeg 'erc-command))) (if (/= 1 bob-utterance-counter) @@ -437,12 +443,8 @@ erc-scenarios-match--stamp-both-invisible-fill-static (forward-line -1) (goto-char (pos-bol)) (should (looking-at (rx "[Mon May 4 1992]"))) - ;; 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 match-fools))) - (should (= (next-single-property-change (point) 'invisible) - (1+ (pos-eol)))))) + (should (= ?\n (char-after (- (point) 2)))) ; welcome!\n + (funcall assert-ds))) ; "assert date stamp" (ert-info ("Folding preserved despite invisibility") ;; Message has a trailing time stamp, but it's been folded @@ -475,13 +477,42 @@ erc-scenarios-match--stamp-both-invisible-fill-static (ert-deftest erc-scenarios-match--stamp-both-invisible-fill-static () :tags '(:expensive-test) - (erc-scenarios-match--stamp-both-invisible-fill-static)) + (erc-scenarios-match--stamp-both-invisible-fill-static + + (lambda () + ;; Date stamp has an `invisible' property that starts from the + ;; newline delimiting the current and previous messages and + ;; extends until the stamp's final newline. It is not combined + ;; with the old value, `match-fools'. + (let ((delim-pos (- (point) 2))) + (should (equal 'timestamp (get-text-property delim-pos 'invisible))) + ;; Stamp-only invisibility ends before its last newline. + (should (= (text-property-not-all delim-pos (point-max) + 'invisible 'timestamp) + (match-end 0))))))) ; pos-eol (ert-deftest erc-scenarios-match--stamp-both-invisible-fill-static--nooffset () :tags '(:expensive-test) (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) (should-not erc-legacy-invisible-bounds-p) + (let ((erc-legacy-invisible-bounds-p t)) - (erc-scenarios-match--stamp-both-invisible-fill-static)))) + (erc-scenarios-match--stamp-both-invisible-fill-static + + (lambda () + ;; Date stamp has an `invisible' property that covers its + ;; format string exactly. It is not combined with the old + ;; value, `match-fools'. + (let ((delim-prev (- (point) 2))) + (should-not (get-text-property delim-prev 'invisible)) + (should (eq 'erc-timestamp (field-at-pos (point)))) + (should (= (next-single-property-change delim-prev 'invisible) + (field-beginning (point)))) + (should (equal 'timestamp + (get-text-property (1- (point)) 'invisible))) + ;; Stamp-only invisibility includes last newline. + (should (= (text-property-not-all (1- (point)) (point-max) + 'invisible 'timestamp) + (field-end (point)))))))))) ;;; erc-scenarios-match.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 05d45b2d027..3fb96ae64d3 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1385,6 +1385,175 @@ erc--merge-prop (when noninteractive (kill-buffer)))) +(ert-deftest erc--remove-from-prop-value-list () + (with-current-buffer (get-buffer-create "*erc-test*") + ;; Non-list match. + (insert "abc\n") + (put-text-property 1 2 'erc-test 'a) + (put-text-property 2 3 'erc-test 'b) + (put-text-property 3 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 1 2 (erc-test b) + 2 3 (erc-test c)))) + + (erc--remove-from-prop-value-list 1 4 'erc-test 'b) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'a) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "abc")) + + ;; List match. + (goto-char (point-min)) + (insert "def\n") + (put-text-property 1 2 'erc-test '(d x)) + (put-text-property 2 3 'erc-test '(e y)) + (put-text-property 3 4 'erc-test '(f z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x)) + 1 2 (erc-test (e y)) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'y) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x)) + 1 2 (erc-test e) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'd) + (erc--remove-from-prop-value-list 1 4 'erc-test 'f) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test x) + 1 2 (erc-test e) + 2 3 (erc-test z)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'e) + (erc--remove-from-prop-value-list 1 4 'erc-test 'z) + (erc--remove-from-prop-value-list 1 4 'erc-test 'x) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "def")) + + ;; List match. + (goto-char (point-min)) + (insert "ghi\n") + (put-text-property 1 2 'erc-test '(g x)) + (put-text-property 2 3 'erc-test '(h x)) + (put-text-property 3 4 'erc-test '(i y)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test (g x)) + 1 2 (erc-test (h x)) + 2 3 (erc-test (i y))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'x) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test g) + 1 2 (erc-test h) + 2 3 (erc-test (i y))))) + (erc--remove-from-prop-value-list 1 2 'erc-test 'g) ; narrowed + (erc--remove-from-prop-value-list 3 4 'erc-test 'i) ; narrowed + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 1 2 (erc-test h) + 2 3 (erc-test y)))) + + ;; Pathological (,c) case (hopefully not created by ERC) + (goto-char (point-min)) + (insert "jkl\n") + (put-text-property 1 2 'erc-test '(j x)) + (put-text-property 2 3 'erc-test '(k)) + (put-text-property 3 4 'erc-test '(k)) + (erc--remove-from-prop-value-list 1 4 'erc-test 'k) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("jkl" 0 1 (erc-test (j x))))) + + (when noninteractive + (kill-buffer)))) + +(ert-deftest erc--remove-from-prop-value-list/many () + (with-current-buffer (get-buffer-create "*erc-test*") + ;; Non-list match. + (insert "abc\n") + (put-text-property 1 2 'erc-test 'a) + (put-text-property 2 3 'erc-test 'b) + (put-text-property 3 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 1 2 (erc-test b) + 2 3 (erc-test c)))) + + (erc--remove-from-prop-value-list 1 4 'erc-test '(a b)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'a) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(c)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "abc")) + + ;; List match. + (goto-char (point-min)) + (insert "def\n") + (put-text-property 1 2 'erc-test '(d x y)) + (put-text-property 2 3 'erc-test '(e y)) + (put-text-property 3 4 'erc-test '(f z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x y)) + 1 2 (erc-test (e y)) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(d y f)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test x) + 1 2 (erc-test e) + 2 3 (erc-test z)))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(e z x)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "def")) + + ;; Narrowed beg. + (goto-char (point-min)) + (insert "ghi\n") + (put-text-property 1 2 'erc-test '(g x)) + (put-text-property 2 3 'erc-test '(h x)) + (put-text-property 3 4 'erc-test '(i x)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test (g x)) + 1 2 (erc-test (h x)) + 2 3 (erc-test (i x))))) + (erc--remove-from-prop-value-list 1 3 'erc-test '(x g i)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 1 2 (erc-test h) + 2 3 (erc-test (i x))))) + + ;; Narrowed middle. + (goto-char (point-min)) + (insert "jkl\n") + (put-text-property 1 2 'erc-test '(j x)) + (put-text-property 2 3 'erc-test '(k)) + (put-text-property 3 4 'erc-test '(l y z)) + (erc--remove-from-prop-value-list 3 4 'erc-test '(k x y z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("jkl" + 0 1 (erc-test (j x)) + 1 2 (erc-test (k)) + 2 3 (erc-test l)))) + + (when noninteractive + (kill-buffer)))) + (ert-deftest erc--split-string-shell-cmd () ;; Leading and trailing space -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Prefer-ticks-hz-pairs-for-some-ERC-timestamps-on.patch From b56f6410aa1d6bc94b74671cabdcaf17b38b2574 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 18 Sep 2023 22:50:28 -0700 Subject: [PATCH 1/3] [5.6] Prefer ticks/hz pairs for some ERC timestamps on 29+ * lisp/erc/erc-compat.el (erc-compat--current-lisp-time): New macro to prefer ticks/hz pairs on newer Emacs versions without producing a compiler warning on 27 and 28. Stamps of this form are easier to compare at a glance when used as values for text properties. * lisp/erc/erc-stamp.el (erc-stamp--current-time): Use compat macro. (Bug#60936) --- lisp/erc/erc-compat.el | 15 +++++++++++++++ lisp/erc/erc-stamp.el | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 109b5d245ab..4c376cfbc22 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -444,6 +444,21 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) +;; We can't store (TICKS . HZ) style timestamps on 27 and 28 because +;; `time-less-p' and friends do +;; +;; message("obsolete timestamp with cdr ...", ...) +;; decode_lisp_time(_, WARN_OBSOLETE_TIMESTAMPS, ...) +;; lisp_time_struct(...) +;; time_cmp(...) +;; +;; which spams *Messages* (and stderr when running the test suite). +(defmacro erc-compat--current-lisp-time () + "Return `current-time' as a (TICKS . HZ) pair on 29+." + (if (>= emacs-major-version 29) + '(let (current-time-list) (current-time)) + '(current-time))) + (provide 'erc-compat) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index f159b6d226f..0f3163bf68d 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -215,7 +215,7 @@ erc-stamp--current-time (cl-defgeneric erc-stamp--current-time () "Return a lisp time object to associate with an IRC message. This becomes the message's `erc-timestamp' text property." - (let (current-time-list) (current-time))) + (erc-compat--current-lisp-time)) (cl-defmethod erc-stamp--current-time :around () (or erc-stamp--current-time (cl-call-next-method))) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Fix-date-stamp-invisibility-in-erc-fill-wrap.patch From 4b16614f2e3ec9f9a376de54efa8f9ffe8dea7af Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 21 Sep 2023 23:54:31 -0700 Subject: [PATCH 2/3] [5.6] Fix date-stamp invisibility in erc-fill-wrap * etc/ERC-NEWS: Mention that `erc-timestamp-format-left' now officially requires a trailing newline to work correctly. * lisp/erc/erc-fill.el (erc-fill--wrap-measure): New helper function, factored out from common code shared by `erc-fill-wrap' and `erc-fill--wrap-stamp-insert-prefixed-date'. (erc-fill--wrap-stamp-insert-prefixed-date): Refactor for more general use and decrement `invisible' bounds, when applicable. (erc-fill-wrap): Use helper `erc-fill--wrap-measure'. * lisp/erc/erc-stamp.el (erc-stamp--custom-trailing-newline-p, erc-stamp--custom-validate-date-stamp): New Custom type validation functions to avoid difficult-to-read closures appearing in `setopt' warnings. (erc-timestamp-format-left): Mention that value should contain a trailing newline, and drop `nil' from Custom :type spec because users who don't want date stamps should use `erc-timestamp-format-right' instead. (erc-stamp--inherited-props): Add doc string. (erc-stamp--decrement-date-invisibility-bounds): New function to implement expected `invisible' interval adjustments needed by the flag `erc-legacy-invisible-bounds-p' when nil. (erc-stamp--checked-date-string-p): New internal flag variable to track whether users whose `erc-timestamp-format-left' value lacks a trailing newline have been warned in the current session. (erc-insert-timestamp-left-and-right): Mention intervals of relevant text props in doc string. Add text property `erc-stamp-type' to inserted date stamps to help folks distinguish between them and other left-sided stamps. Shadow `erc-stamp--invisible-property' when calling `erc-format-timestamp' in order to prevent date stamps from inheriting other `invisible' props. These stamps are special in that they have no business being hidden along with the current message. Also, appeal to `erc-stamp--decrement-date-invisibility-bounds' in offset the invisibility interval when `erc-legacy-invisible-bounds-p' is nil. * lisp/erc/erc.el (erc-insert-modify-hook): Mention reserved depth ranges for built-in members in doc string. (erc--remove-from-prop-value-list): New function for removing `invisible' and `face' prop members cleanly. (erc--hide-message): Don't bother offsetting start of first message in a buffer. (erc--own-property-names): Add `erc-stamp-type'. (erc--persistent-message-properties): New variable. (erc-restore-text-properties): Extend role to cover persistent as well as ephemeral props that only exist during message insertion for the benefit of hooks. (erc--get-eq-comparable-cmd): Use `if-let' instead of `if-let*'. * test/lisp/erc/erc-scenarios-log.el (erc-scenarios-log--clear-stamp): Ensure `erc-stamp' is loaded. * test/lisp/erc/erc-scenarios-match.el (erc-scenarios-match--stamp-right-fools-invisible): Remove misplaced ERT tag from function. (erc-scenarios-match--fill-wrap-stamp-dedented-p): New assertion utility function. (erc-scenarios-match--stamp-both-invisible-fill-wrap) New test. (erc-scenarios-match--stamp-both-invisible-fill-static): Expect `erc-command' at beginning of inserted message's filled line, even if it starts with whitespace. This is a consequence of the change above to `erc-restore-text-properties'. Also, add new function parameter `assert-ds', a callback to run when visiting the second date stamp, which is followed by a hidden message. In the test of the same name, expect the date stamp's invisibility interval to begin at the newline after the previous message and to not contain any existing invisibility props, namely, those belonging to the subsequent hidden "fools" message. (erc-scenarios-match--stamp-both-invisible-fill-static--nooffset): Expect the date stamp's invisibility interval to match its field's instead of starting and ending sooner. * test/lisp/erc/erc-tests.el (erc--remove-from-prop-value-list, erc--remove-from-prop-value-list/many): New tests. (Bug#60936) --- etc/ERC-NEWS | 12 +- lisp/erc/erc-fill.el | 45 +++---- lisp/erc/erc-stamp.el | 117 ++++++++++++++++--- lisp/erc/erc.el | 61 ++++++++-- test/lisp/erc/erc-scenarios-log.el | 1 + test/lisp/erc/erc-scenarios-match.el | 163 ++++++++++++++++++++++++-- test/lisp/erc/erc-tests.el | 169 +++++++++++++++++++++++++++ 7 files changed, 507 insertions(+), 61 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 05e933930e2..6743e49cfec 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -149,13 +149,17 @@ minor-mode maps, and new third-party modules should do the same. ** Option 'erc-timestamp-format-right' deprecated. Having to account for this option prevented other ERC modules from -easily determining what right-hand stamps would look like before +easily determining what right-sided stamps would look like before insertion, which is knowledge needed for certain UI decisions. The way ERC has chosen to address this is imperfect and boils down to asking users who've customized this option to switch to -'erc-timestamp-format' instead. If you're affected by this and feel -that some other solution, like automatic migration, is justified, -please make that known on the bug list. +'erc-timestamp-format' instead. Somewhat relatedly, the companion +option 'erc-timestamp-format-left', which determines the look of date +stamps, must now end in a newline. Although this has long been the +case in practice, it's now been made official. As always, if you're +affected by these changes and feel that other solutions, like +automatic migration, are justified, please make that known on the bug +list. ** 'erc-button-alist' and 'erc-nick-popup-alist' have evolved slightly. It's no secret that the 'buttons' module treats potential nicknames diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index f4835f71278..d323682476d 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -484,25 +484,34 @@ erc-fill--wrap-continued-message-p ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) -(defun erc-fill--wrap-stamp-insert-prefixed-date (&rest args) - "Apply `line-prefix' property to args." - (let* ((ts-left (car args)) - (start) +(defun erc-fill--wrap-measure (beg end) + "Return display spec width for inserted region between BEG and END. +Ignore any `invisible' props that may be present when figuring." + (if (and erc-fill-wrap-use-pixels (fboundp 'buffer-text-pixel-size)) + ;; `buffer-text-pixel-size' can move point! + (save-excursion + (save-restriction + (narrow-to-region beg end) + (let (buffer-invisibility-spec) + (list (car (buffer-text-pixel-size)))))) + (- end beg))) + +(defun erc-fill--wrap-stamp-insert-prefixed-date (&rest _) + "Apply `line-prefix' property to args. +Expect a multiline \"date\" stamp ending in a newline, similar to +the default value of `erc-timestamp-format-left'. Omit the +`line-prefix' from any trailing newlines." + (let* ((beg) ;; Insert " " to simulate gap between <speaker> and msg beg. (end (save-excursion (skip-chars-backward "\n") - (setq start (pos-bol)) + (setq beg (pos-bol)) (insert " ") (point))) - (width (if (and erc-fill-wrap-use-pixels - (fboundp 'buffer-text-pixel-size)) - (save-restriction (narrow-to-region start end) - (list (car (buffer-text-pixel-size)))) - (length (string-trim-left ts-left))))) + (width (erc-fill--wrap-measure beg end))) (delete-region (1- end) end) - ;; Use `point-min' instead of `start' to cover leading newilnes. - (put-text-property (point-min) (point) 'line-prefix - `(space :width (- erc-fill--wrap-value ,width)))) - args) + ;; Use `point-min' instead of `beg' to cover leading newilnes. + (put-text-property (point-min) (1- end) 'line-prefix + `(space :width (- erc-fill--wrap-value ,width))))) ;; An escape hatch for third-party code expecting speakers of ACTION ;; messages to be exempt from `line-prefix'. This could be converted @@ -536,12 +545,8 @@ erc-fill-wrap (put-text-property (point-min) (point) 'display "") 0) - ((and erc-fill-wrap-use-pixels - (fboundp 'buffer-text-pixel-size)) - (save-restriction - (narrow-to-region (point-min) (point)) - (list (car (buffer-text-pixel-size))))) - (t (- (point) (point-min)))))))) + (t + (erc-fill--wrap-measure (point-min) (point)))))))) (erc-put-text-properties (point-min) (1- (point-max)) ; exclude "\n" '(line-prefix wrap-prefix) nil `((space :width (- erc-fill--wrap-value ,len)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0f3163bf68d..68dd1f287cf 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,21 +55,35 @@ erc-timestamp-format :type '(choice (const nil) (string))) -;; FIXME remove surrounding whitespace from default value and have -;; `erc-insert-timestamp-left-and-right' add it before insertion. +(defun erc-stamp--custom-trailing-newline-p (_ value) + "Return non-nil if VALUE ends in a newline." + (string-suffix-p "\n" value)) -(defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" - "If set to a string, messages will be timestamped. -This string is processed using `format-time-string'. -Good examples are \"%T\" and \"%H:%M\". - -This timestamp is used for timestamps on the left side of the -screen when `erc-insert-timestamp-function' is set to -`erc-insert-timestamp-left-and-right'. +(defun erc-stamp--custom-validate-date-stamp (widget) + "Fail unless WIDGET's value ends in a newline." + (unless (string-suffix-p "\n" (widget-value widget)) + (widget-put widget :error "Value lacks a trailing newline") + widget)) -If nil, timestamping is turned off." - :type '(choice (const nil) - (string))) +(defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" + "Format recognized by `format-time-string' for date stamps. +Only considered when `erc-insert-timestamp-function' is set to +`erc-insert-timestamp-left-and-right'. Used for displaying date +stamps on their own line, between messages. As of ERC 5.6, this +module appends a trailing newline on insertion if needed. Any +extra newlines, leading or trailing, become empty lines. For +example, the default value results in an empty line after the +previous message, followed by the timestamp on its own line, +followed immediately by the next message on the next line. ERC +expects to display these stamps less frequently, so the +formatting specifiers should reflect that. To omit these stamps +entirely, use a different `erc-insert-timestamp-function', such +as `erc-timestamp-format-right'." + :type '(string :validate erc-stamp--custom-validate-date-stamp + :match erc-stamp--custom-trailing-newline-p) + :set (lambda (sym val) + (set-default sym + (if (string-suffix-p "\n" val) val (concat val "\n"))))) (defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. @@ -374,7 +388,15 @@ erc-stamp-prefix-log-filter (zerop (forward-line)))) "") -(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) +;; These are currently extended manually, but we could also bind +;; `text-property-default-nonsticky' and call `insert-and-inherit' +;; instead of `insert', but we'd have to pair the props with differing +;; boolean values for left and right stamps. Also, since this hook +;; runs last, we can't expect overriding sticky props to be absent, +;; even though, as of 5.6, `front-sticky' is only added by the +;; `readonly' module after hooks run. +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix) + "Extant properties at the start of a message inherited by the stamp.") (declare-function erc--remove-text-properties "erc" (string)) @@ -604,14 +626,69 @@ erc-stamp--insert-date-function A local module might use this to modify text properties, `insert-before-markers' or renarrow the region after insertion.") +(defun erc-stamp--decrement-date-invisibility-bounds () + "Extend `invisible' prop to previous newline before date stamp. +And apply original prop value from message body to any trailing +newlines after date." + (let ((beg (point-min))) + (save-restriction + (widen) + (when (and (> beg 4) (= (char-before beg) ?\n)) + (when-let ((this (get-text-property (point) 'invisible)) + (prev (get-text-property (1- beg) 'invisible)) + ((not (equal this prev)))) + (put-text-property (1- beg) beg 'invisible + (seq-difference (ensure-list prev) + (ensure-list this)))) + (put-text-property (1- beg) beg 'invisible 'timestamp))) + (cl-assert (= ?\n (char-before (point)))) + ;; Only decrement bounds by one. Additional newlines in the + ;; timestamp must be hidden. + (if-let ((existing (remq 'timestamp + (ensure-list erc-stamp--invisible-property)))) + (put-text-property (1- (point)) (point) 'invisible + (if (cdr existing) existing (car existing))) + (erc--remove-from-prop-value-list + (1- (point)) (point) 'invisible 'timestamp)))) + +(defvar-local erc-stamp--checked-date-string-p nil + "Non-nil if date string has been validated for current buffer.") + (defun erc-insert-timestamp-left-and-right (string) "Insert a stamp on either side when it changes. When the deprecated option `erc-timestamp-format-right' is nil, use STRING, which originates from `erc-timestamp-format', for the right-hand stamp. Use `erc-timestamp-format-left' for the -left-hand stamp and expect it to change less frequently." +left-hand stamp and expect it to change less frequently. Include +line endings found in `erc-timestamp-format-left' (or affixed by +ERC) as part of the `erc-timestamp' field, which extends to the +start of the message proper. Do this so other code knows the +stamp is part of the subsequent IRC message even though it may +appear on its own line. However, allow the stamp's `invisible' +property to span a different interval, in order to satisfy newer +folding requirements related to `erc-legacy-invisible-bounds-p'. +Additionally, ensure every date stamp formatted with the option +`erc-timestamp-format-left' has the property `erc-stamp-type' set +to the symbol `date-left' so that modules can easily distinguish +between other left-sided stamps and date stamps inserted by this +function." + (unless erc-stamp--checked-date-string-p + (setq erc-stamp--checked-date-string-p t) + (unless (string-suffix-p "\n" erc-timestamp-format-left) + (setq erc-timestamp-format-left + (concat erc-timestamp-format-left "\n")) + (unless erc--target + (erc-button--display-error-notice-with-keys + (current-buffer) + "ERC only supports values of `%s' that end in a ?\\n." + " Changing value for current session to: %s." + " Update your config accordingly to silence this message." + 'erc-timestamp-format-left + (let ((print-escape-newlines t)) + (prin1-to-string erc-timestamp-format-left)))))) (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-left (let ((erc-stamp--invisible-property 'timestamp)) + (erc-format-timestamp ct erc-timestamp-format-left))) (ts-right (with-suppressed-warnings ((obsolete erc-timestamp-format-right)) (if erc-timestamp-format-right @@ -620,8 +697,14 @@ erc-insert-timestamp-left-and-right ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) - (erc-put-text-property 0 (length ts-left) 'field 'erc-timestamp ts-left) + (add-text-properties 0 (length ts-left) + '(field erc-timestamp erc-stamp-type date-left) + ts-left) (funcall erc-stamp--insert-date-function ts-left) + (unless (with-suppressed-warnings + ((obsolete erc-legacy-invisible-bounds-p)) + erc-legacy-invisible-bounds-p) + (erc-stamp--decrement-date-invisibility-bounds)) (setq erc-timestamp-last-inserted-left ts-left)) ;; insert right timestamp (let ((erc-timestamp-only-if-changed-flag t) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ec4fae548c7..db2e20c800e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1128,9 +1128,13 @@ erc-insert-modify-hook "Insertion hook for functions that will change the text's appearance. This hook is called just after `erc-insert-pre-hook' when the value of `erc-insert-this' is t. -While this hook is run, narrowing is in effect and `current-buffer' is -the buffer where the text got inserted. One possible value to add here -is `erc-fill'." + +ERC runs this hook with the buffer narrowed to the bounds of the +inserted message plus a trailing newline. Built-in modules place +their hook members at depths between 20 and 80, with those from +the stamp module always running last. Use the functions +`erc-find-parsed-property' and `erc-get-parsed-vector' to locate +and extract the `erc-response' object for the inserted message." :group 'erc-hooks :type 'hook) @@ -3037,6 +3041,30 @@ erc--merge-prop old (get-text-property pos prop object) end (next-single-property-change pos prop object to))))) +(defun erc--remove-from-prop-value-list (from to prop val &optional object) + "Remove VAL from text prop value between FROM and TO. +If current value is VAL itself, remove the property entirely. +When VAL is a list, act as if this function were called +repeatedly with VAL set to each of VAL's members." + (let ((old (get-text-property from prop object)) + (pos from) + (end (next-single-property-change from prop object to)) + new) + (while (< pos to) + (when old + (if (setq new (and (consp old) (if (consp val) + (seq-difference old val) + (remq val old)))) + (put-text-property pos end prop + (if (cdr new) new (car new)) object) + (when (pcase val + ((pred consp) (or (consp old) (memq old val))) + (_ (if (consp old) (memq val old) (eq old val)))) + (remove-text-properties pos end (list prop nil) object)))) + (setq pos end + old (get-text-property pos prop object) + end (next-single-property-change pos prop object to))))) + (defvar erc-legacy-invisible-bounds-p nil "Whether to hide trailing rather than preceding newlines. Beginning in ERC 5.6, invisibility extends from a message's @@ -3046,7 +3074,11 @@ erc-legacy-invisible-bounds-p (defun erc--hide-message (value) "Apply `invisible' text-property with VALUE to current message. -Expect to run in a narrowed buffer during message insertion." +Expect to run in a narrowed buffer during message insertion. +Begin the invisible interval at the previous message's trailing +newline and end before the current message's. If the preceding +message ends in a double newline or there is no previous message, +don't bother including the preceding newline." (if erc-legacy-invisible-bounds-p ;; Before ERC 5.6, this also used to add an `intangible' ;; property, but the docs say it's now obsolete. @@ -3055,6 +3087,8 @@ erc--hide-message (end (point-max))) (save-restriction (widen) + (when (or (<= beg 4) (= ?\n (char-before (- beg 2)))) + (cl-incf beg)) (erc--merge-prop (1- beg) (1- end) 'invisible value))))) (defun erc-display-message-highlight (type string) @@ -4770,6 +4804,7 @@ 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 @@ -8071,13 +8106,21 @@ erc-find-parsed-property "Find the next occurrence of the `erc-parsed' text property." (text-property-not-all (point-min) (point-max) 'erc-parsed nil)) +(defvar erc--persistent-message-properties '(erc-command)) + (defun erc-restore-text-properties () - "Restore the property `erc-parsed' for the region." - (when-let* ((parsed-posn (erc-find-parsed-property)) - (found (erc-get-parsed-vector parsed-posn))) + "Ensure the `erc-parsed' property covers the narrowed buffer. +Do this for other properties added by `erc-display-message' and +for those named in `erc--persistent-message-properties'." + (when-let ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) (put-text-property (point-min) (point-max) 'erc-parsed found) (when-let ((tags (get-text-property parsed-posn 'tags))) - (put-text-property (point-min) (point-max) 'tags tags)))) + (put-text-property (point-min) (point-max) 'tags tags)) + (let ((to (max (point-min) (1- (point-max))))) + (dolist (prop erc--persistent-message-properties) + (when-let ((val (get-text-property parsed-posn prop))) + (put-text-property (point-min) to prop val)))))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -8102,7 +8145,7 @@ erc--get-eq-comparable-cmd See also `erc-message-type'." ;; IRC numerics are three-digit numbers, possibly with leading 0s. ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) - (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + (if-let ((n (string-to-number command)) ((zerop n))) (intern command) n)) ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenarios-log.el index fd030d90c2f..f7e7d61c92e 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -81,6 +81,7 @@ erc-scenarios-log--kill-hook (ert-deftest erc-scenarios-log--clear-stamp () :tags '(:expensive-test) + (require 'erc-stamp) (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "base/assoc/bouncer-history") (dumb-server (erc-d-run "localhost" t 'foonet)) diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scenarios-match.el index cd899fddb98..bc06d58c3e9 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -167,7 +167,6 @@ erc-scenarios-match--find-eol ;; In most cases, `erc-hide-fools' makes line endings invisible. (defun erc-scenarios-match--stamp-right-fools-invisible () - :tags '(:expensive-test) (let ((erc-insert-timestamp-function #'erc-insert-timestamp-right)) (erc-scenarios-match--invisible-stamp @@ -271,7 +270,123 @@ erc-scenarios-match--stamp-right-invisible-fill-wrap (let ((inv-beg (next-single-property-change (1- (pos-bol)) 'invisible))) (should (eq (get-text-property inv-beg 'invisible) 'timestamp))))))) -(defun erc-scenarios-match--stamp-both-invisible-fill-static () +(defun erc-scenarios-match--fill-wrap-stamp-dedented-p (point) + (pcase (get-text-property point 'line-prefix) + (`(space :width (- erc-fill--wrap-value (,n))) + (if (display-graphic-p) (< 100 n 200) (< 10 n 30))) + (`(space :width (- erc-fill--wrap-value ,n)) + (< 10 n 30)))) + +(ert-deftest erc-scenarios-match--stamp-both-invisible-fill-wrap () + + ;; Rewind the clock to known date artificially. + (let ((erc-stamp--current-time 704591940) + (erc-stamp--tz t) + (erc-fill-function #'erc-fill-wrap) + (bob-utterance-counter 0)) + + (erc-scenarios-match--invisible-stamp + + (lambda () + (ert-info ("Baseline check") + ;; False date printed initially before anyone speaks. + (when (zerop bob-utterance-counter) + (save-excursion + (goto-char (point-min)) + (search-forward "[Wed Apr 29 1992]") + ;; First stamp in a buffer is not invisible from previous + ;; newline (before stamp's own leading newline). + (should (= 4 (match-beginning 0))) + (should (get-text-property 3 'invisible)) + (should-not (get-text-property 2 'invisible)) + (should (erc-scenarios-match--fill-wrap-stamp-dedented-p 4)) + (search-forward "[23:59]")))) + + (ert-info ("Line endings in Bob's messages are invisible") + ;; The message proper has the `invisible' property `match-fools'. + (should (eq (get-text-property (pos-bol) 'invisible) 'match-fools)) + (let* ((mbeg (or (and (get-text-property (pos-bol) 'erc-command) + (pos-bol)) + (next-single-property-change (pos-bol) + 'erc-command))) + (mend (text-property-not-all + mbeg (point-max) 'erc-command + (get-text-property mbeg 'erc-command)))) + + (if (/= 1 bob-utterance-counter) + (should-not (field-at-pos mend)) + ;; For Bob's stamped message, check newline after stamp. + (should (eq (field-at-pos mend) 'erc-timestamp)) + (setq mend (field-end mend))) + + ;; The `erc-timestamp' property spans entire messages, + ;; including stamps and filled text, which makes for + ;; convenient traversal when `erc-stamp-mode' is enabled. + (should (get-text-property (pos-bol) 'erc-timestamp)) + (should (= (next-single-property-change (pos-bol) 'erc-timestamp) + mend)) + + ;; Line ending has the `invisible' property `match-fools'. + (should (= (char-after mend) ?\n)) + (should (eq (get-text-property mbeg 'invisible) 'match-fools)) + (should-not (get-text-property mend 'invisible)))) + + ;; Only the message right after Alice speaks contains stamps. + (when (= 1 bob-utterance-counter) + + (ert-info ("Date stamp occupying previous line is invisible") + (should (eq 'match-fools (get-text-property (point) 'invisible))) + (save-excursion + (forward-line -1) + (goto-char (pos-bol)) + (should (looking-at (rx "[Mon May 4 1992]"))) + (ert-info ("Stamp's NL `invisible' as fool, not timestamp") + (let ((end (match-end 0))) + (should (eq (char-after end) ?\n)) + (should (eq 'timestamp + (get-text-property (1- end) 'invisible))) + (should (eq 'match-fools + (get-text-property end 'invisible))))) + (should (erc-scenarios-match--fill-wrap-stamp-dedented-p (point))) + ;; Date stamp has a combined `invisible' property value + ;; that starts at the previous message's trailing newline + ;; and extends until the start of the message proper. + (should (equal ?\n (char-before (point)))) + (should (equal ?\n (char-before (1- (point))))) + (let ((val (get-text-property (- (point) 2) 'invisible))) + (should (equal val 'timestamp)) + (should (= (text-property-not-all (- (point) 2) (point-max) + 'invisible val) + (pos-eol)))))) + + (ert-info ("Current message's RHS stamp is hidden") + ;; Right stamp has `match-fools' property. + (save-excursion + (should-not (field-at-pos (point))) + (should (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp))) + + ;; Stamp invisibility starts where message's ends. + (let ((msgend (next-single-property-change (pos-bol) 'invisible))) + ;; Stamp has a combined `invisible' property value. + (should (equal (get-text-property msgend 'invisible) + '(timestamp match-fools))) + + ;; Combined `invisible' property spans entire timestamp. + (should (= (next-single-property-change msgend 'invisible) + (pos-eol)))))) + + (cl-incf bob-utterance-counter)) + + ;; Alice. + (lambda () + ;; Set clock ahead a week or so. + (setq erc-stamp--current-time 704962800) + + ;; This message has no time stamp and is completely visible. + (should-not (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp)) + (should-not (next-single-property-change (pos-bol) 'invisible)))))) + +(defun erc-scenarios-match--stamp-both-invisible-fill-static (assert-ds) (should (eq erc-insert-timestamp-function #'erc-insert-timestamp-left-and-right)) @@ -295,7 +410,8 @@ erc-scenarios-match--stamp-both-invisible-fill-static (ert-info ("Line endings in Bob's messages are invisible") ;; 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)) + (let* ((mbeg (and (get-text-property (pos-bol) 'erc-command) + (pos-bol))) (mend (next-single-property-change mbeg 'erc-command))) (if (/= 1 bob-utterance-counter) @@ -327,12 +443,8 @@ erc-scenarios-match--stamp-both-invisible-fill-static (forward-line -1) (goto-char (pos-bol)) (should (looking-at (rx "[Mon May 4 1992]"))) - ;; 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 match-fools))) - (should (= (next-single-property-change (point) 'invisible) - (1+ (pos-eol)))))) + (should (= ?\n (char-after (- (point) 2)))) ; welcome!\n + (funcall assert-ds))) ; "assert date stamp" (ert-info ("Folding preserved despite invisibility") ;; Message has a trailing time stamp, but it's been folded @@ -365,13 +477,42 @@ erc-scenarios-match--stamp-both-invisible-fill-static (ert-deftest erc-scenarios-match--stamp-both-invisible-fill-static () :tags '(:expensive-test) - (erc-scenarios-match--stamp-both-invisible-fill-static)) + (erc-scenarios-match--stamp-both-invisible-fill-static + + (lambda () + ;; Date stamp has an `invisible' property that starts from the + ;; newline delimiting the current and previous messages and + ;; extends until the stamp's final newline. It is not combined + ;; with the old value, `match-fools'. + (let ((delim-pos (- (point) 2))) + (should (equal 'timestamp (get-text-property delim-pos 'invisible))) + ;; Stamp-only invisibility ends before its last newline. + (should (= (text-property-not-all delim-pos (point-max) + 'invisible 'timestamp) + (match-end 0))))))) ; pos-eol (ert-deftest erc-scenarios-match--stamp-both-invisible-fill-static--nooffset () :tags '(:expensive-test) (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) (should-not erc-legacy-invisible-bounds-p) + (let ((erc-legacy-invisible-bounds-p t)) - (erc-scenarios-match--stamp-both-invisible-fill-static)))) + (erc-scenarios-match--stamp-both-invisible-fill-static + + (lambda () + ;; Date stamp has an `invisible' property that covers its + ;; format string exactly. It is not combined with the old + ;; value, `match-fools'. + (let ((delim-prev (- (point) 2))) + (should-not (get-text-property delim-prev 'invisible)) + (should (eq 'erc-timestamp (field-at-pos (point)))) + (should (= (next-single-property-change delim-prev 'invisible) + (field-beginning (point)))) + (should (equal 'timestamp + (get-text-property (1- (point)) 'invisible))) + ;; Stamp-only invisibility includes last newline. + (should (= (text-property-not-all (1- (point)) (point-max) + 'invisible 'timestamp) + (field-end (point)))))))))) ;;; erc-scenarios-match.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 05d45b2d027..3fb96ae64d3 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1385,6 +1385,175 @@ erc--merge-prop (when noninteractive (kill-buffer)))) +(ert-deftest erc--remove-from-prop-value-list () + (with-current-buffer (get-buffer-create "*erc-test*") + ;; Non-list match. + (insert "abc\n") + (put-text-property 1 2 'erc-test 'a) + (put-text-property 2 3 'erc-test 'b) + (put-text-property 3 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 1 2 (erc-test b) + 2 3 (erc-test c)))) + + (erc--remove-from-prop-value-list 1 4 'erc-test 'b) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'a) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "abc")) + + ;; List match. + (goto-char (point-min)) + (insert "def\n") + (put-text-property 1 2 'erc-test '(d x)) + (put-text-property 2 3 'erc-test '(e y)) + (put-text-property 3 4 'erc-test '(f z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x)) + 1 2 (erc-test (e y)) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'y) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x)) + 1 2 (erc-test e) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'd) + (erc--remove-from-prop-value-list 1 4 'erc-test 'f) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test x) + 1 2 (erc-test e) + 2 3 (erc-test z)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'e) + (erc--remove-from-prop-value-list 1 4 'erc-test 'z) + (erc--remove-from-prop-value-list 1 4 'erc-test 'x) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "def")) + + ;; List match. + (goto-char (point-min)) + (insert "ghi\n") + (put-text-property 1 2 'erc-test '(g x)) + (put-text-property 2 3 'erc-test '(h x)) + (put-text-property 3 4 'erc-test '(i y)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test (g x)) + 1 2 (erc-test (h x)) + 2 3 (erc-test (i y))))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'x) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test g) + 1 2 (erc-test h) + 2 3 (erc-test (i y))))) + (erc--remove-from-prop-value-list 1 2 'erc-test 'g) ; narrowed + (erc--remove-from-prop-value-list 3 4 'erc-test 'i) ; narrowed + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 1 2 (erc-test h) + 2 3 (erc-test y)))) + + ;; Pathological (,c) case (hopefully not created by ERC) + (goto-char (point-min)) + (insert "jkl\n") + (put-text-property 1 2 'erc-test '(j x)) + (put-text-property 2 3 'erc-test '(k)) + (put-text-property 3 4 'erc-test '(k)) + (erc--remove-from-prop-value-list 1 4 'erc-test 'k) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("jkl" 0 1 (erc-test (j x))))) + + (when noninteractive + (kill-buffer)))) + +(ert-deftest erc--remove-from-prop-value-list/many () + (with-current-buffer (get-buffer-create "*erc-test*") + ;; Non-list match. + (insert "abc\n") + (put-text-property 1 2 'erc-test 'a) + (put-text-property 2 3 'erc-test 'b) + (put-text-property 3 4 'erc-test 'c) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" + 0 1 (erc-test a) + 1 2 (erc-test b) + 2 3 (erc-test c)))) + + (erc--remove-from-prop-value-list 1 4 'erc-test '(a b)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test 'a) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("abc" 2 3 (erc-test c)))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(c)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "abc")) + + ;; List match. + (goto-char (point-min)) + (insert "def\n") + (put-text-property 1 2 'erc-test '(d x y)) + (put-text-property 2 3 'erc-test '(e y)) + (put-text-property 3 4 'erc-test '(f z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test (d x y)) + 1 2 (erc-test (e y)) + 2 3 (erc-test (f z))))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(d y f)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("def" + 0 1 (erc-test x) + 1 2 (erc-test e) + 2 3 (erc-test z)))) + (erc--remove-from-prop-value-list 1 4 'erc-test '(e z x)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) "def")) + + ;; Narrowed beg. + (goto-char (point-min)) + (insert "ghi\n") + (put-text-property 1 2 'erc-test '(g x)) + (put-text-property 2 3 'erc-test '(h x)) + (put-text-property 3 4 'erc-test '(i x)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 0 1 (erc-test (g x)) + 1 2 (erc-test (h x)) + 2 3 (erc-test (i x))))) + (erc--remove-from-prop-value-list 1 3 'erc-test '(x g i)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("ghi" + 1 2 (erc-test h) + 2 3 (erc-test (i x))))) + + ;; Narrowed middle. + (goto-char (point-min)) + (insert "jkl\n") + (put-text-property 1 2 'erc-test '(j x)) + (put-text-property 2 3 'erc-test '(k)) + (put-text-property 3 4 'erc-test '(l y z)) + (erc--remove-from-prop-value-list 3 4 'erc-test '(k x y z)) + (should (erc-tests--equal-including-properties + (buffer-substring 1 4) #("jkl" + 0 1 (erc-test (j x)) + 1 2 (erc-test (k)) + 2 3 (erc-test l)))) + + (when noninteractive + (kill-buffer)))) + (ert-deftest erc--split-string-shell-cmd () ;; Leading and trailing space -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Add-command-to-refill-buffer-with-erc-fill-wrap-.patch From d8870a3dede52045518dc24a53143295df899943 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 21 Sep 2023 06:54:27 -0700 Subject: [PATCH 3/3] [5.6] Add command to refill buffer with erc-fill-wrap-mode * lisp/erc/erc-fill.el (erc-fill--wrap-rejigger-last-message): New internal variable. (erc-fill--wrap-rejigger-region, erc-fill-wrap-refill-buffer): New command and helper function. (Bug#60936) --- lisp/erc/erc-fill.el | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index d323682476d..b419fb57bd4 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -552,6 +552,57 @@ erc-fill-wrap `((space :width (- erc-fill--wrap-value ,len)) (space :width erc-fill--wrap-value)))))) +(defvar erc-fill--wrap-rejigger-last-message nil + "Temporary working instance of `erc-fill--wrap-last-msg'.") + +(defun erc-fill--wrap-rejigger-region (start finish on-next) + "Recalculate `line-prefix' from START to FINISH. +After refilling each message, call ON-NEXT with no args. But +stash and restore `erc-fill--wrap-last-msg' before doing so, in +case this module's insert hooks run by way of the process filter." + (goto-char start) + (cl-assert (null erc-fill--wrap-rejigger-last-message)) + (let (erc-fill--wrap-rejigger-last-message) + (while-let + (((< (point) finish)) + (beg (if (get-text-property (point) 'line-prefix) + (point) + (next-single-property-change (point) 'line-prefix))) + (val (get-text-property beg 'line-prefix)) + (end (text-property-not-all beg finish 'line-prefix val))) + ;; If this is a left-side stamp on its own line. + (remove-text-properties beg (1+ end) '(line-prefix nil wrap-prefix nil)) + (save-restriction + (narrow-to-region beg (1+ end)) + (if-let (((eq 'erc-timestamp (field-at-pos beg))) + ((eq 'date-left (get-text-property beg 'erc-stamp-type)))) + (progn + (goto-char (field-end beg)) + (erc-fill--wrap-stamp-insert-prefixed-date)) + (let ((erc-fill--wrap-last-msg erc-fill--wrap-rejigger-last-message)) + (erc-fill-wrap) + (setq erc-fill--wrap-rejigger-last-message + erc-fill--wrap-last-msg)))) + (when on-next + (funcall on-next)) + (goto-char end)))) + +(defun erc-fill-wrap-refill-buffer () + "Recalculate all `fill-wrap' prefixes in the current buffer." + (interactive) + (unless erc-fill-wrap-mode + (user-error "Module `fill-wrap' not active in current buffer.")) + (save-excursion + (with-silent-modifications + (let* ((rep (make-progress-reporter + "Rewrap" 0 (line-number-at-pos erc-insert-marker) 1)) + (seen 0) + (callback (lambda () + (progress-reporter-update rep (cl-incf seen)) + (accept-process-output nil 0.000001)))) + (erc-fill--wrap-rejigger-region (point-min) erc-insert-marker callback) + (progress-reporter-done rep))))) + ;; FIXME use own text property to avoid false positives. (defun erc-fill--wrap-merged-button-p (point) (equal "" (get-text-property point 'display))) -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 22 Sep 2023 14:11:32 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Fri Sep 22 10:11:32 2023 Received: from localhost ([127.0.0.1]:37034 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qjgsU-0002BM-T9 for submit <at> debbugs.gnu.org; Fri, 22 Sep 2023 10:11:32 -0400 Received: from mail-108-mta116.mxroute.com ([136.175.108.116]:42783) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qjgsP-0002BA-Qe for 60936 <at> debbugs.gnu.org; Fri, 22 Sep 2023 10:11:29 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta116.mxroute.com (ZoneMTA) with ESMTPSA id 18abd3af79b000d7b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 22 Sep 2023 14:11:12 +0000 X-Zone-Loop: ed607968ac776a6656a2ec97229e2079fa8d030b1261 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=kwX36DY8VV/Fycd1jSackMfWEQQ5tP3AqXXJvOIclKs=; b=lwAs59VLhC0FWdkv4sSyaCP358 XndQNt4NW/GhCWOoqutXlOowx3KwJ4sE06fiA42z/4lngOQ72DeQN1zF9CZkTYw8sYQ7Wu7TXIOzu 7139SkdDtW8hxOIMKQukmwCfqxDG7lF2inMjYxu0NgaiwjDD372O2KuP3T7RscNQWooNYlSUuKqKW wtJpl2TV7nKgp8vMc3MbFNjyL+odZtOvW8JiGotbvjkFRcKbiN5yreuXzMGzUCBVmq3ilXU5ZHy1I OnIInu3I7Pbqfaa2yZnHCojh4NzIZ2okoVKDtNzTv+N1cudVK/XQUBQnszGn76vFCyGCN5tNu1lcc yQ1pPwCA==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Fri, 22 Sep 2023 07:11:08 -0700 Message-ID: <87a5te47sz.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain A couple more bugs stemming from this feature's introduction have surfaced. The first involves stamp hiding when `erc-fill-wrap-mode' is enabled. To reproduce from emacs -Q: - Connect and join a channel - In the channel buffer, set `erc-timestamp-last-inserted-left' to nil - Say something and notice a new date stamp inserted - Run M-x erc-toggle-timestamps RET - Notice that the message after the stamp is dedented incorrectly This problem occurs because date stamps are not well defined and straddle roles occupied by normal stamps and standalone messages. The remedy I've chosen retains compatibility at the cost of kicking the can down the road WRT defining the precise role and expected behavior of date stamps. (If still unclear, I say "date stamp" to mean a left-sided stamp inserted by the function `erc-insert-timestamp-left-and-right' and formatted using the string `erc-timestamp-format-left'.) This issue is closely related to the interplay between normal right-hand stamps and non-`fill-wrap' fill functions because the latter hard-wrap (i.e., "fill") messages, which results in a stamp often residing on its own line. The second issue comes down to the lack of an integration with `text-scale-mode'. To reproduce from emacs -Q: - Connect from a graphical Emacs - In the server buffer, hit C-x C-=, and notice misaligned speaker tags among the upscaled text - Run a command, like "/msg NickServ help", and notice the leading `erc-notice-prefix' portion of new messages correctly dedented - Hit C-x C-0 and observe the just-inserted messages now looking mangled and the preexisting ones seemingly restored The problem is that our `line-prefix' values use display specs with pixel widths, which is needed for speakers with variable-width faces and non-ascii chars. (Based on a cursory glance at relevant sections of the manual, it doesn't look like there's an easy way to adjust these automatically.) For now, I'm proposing we include a command to manually traverse and refill target buffers. Luckily, this is much faster than it'd be with some other `erc-fill-function' because no actual "filling" takes place. We're just remeasuring speaker tags and replacing existing display-spec values. If you're affected by these bugs, please try these patches. Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Prefer-ticks-hz-pairs-for-erc-timestamp-values-o.patch From c4d98ab82a9edac04abdde59df4055685f17b6cb Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 18 Sep 2023 22:50:28 -0700 Subject: [PATCH 1/3] [5.6] Prefer ticks/hz pairs for erc-timestamp values on <29 * lisp/erc/erc-compat.el (erc-compat--current-lisp-time): New macro to prefer ticks/hz pairs on older Emacs versions. They're easier to compare at a glance when used as values for text properties. * lisp/erc/erc-stamp.el (erc-stamp--current-time): Use compat macro. (Bug#60936) --- lisp/erc/erc-compat.el | 6 ++++++ lisp/erc/erc-stamp.el | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 109b5d245ab..4dae578de67 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -444,6 +444,12 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) +(defmacro erc-compat--current-lisp-time () + "Return `current-time' as a frequency pair." + (if (>= emacs-major-version 29) + '(let (current-time-list) (current-time)) + '(time-convert nil t))) + (provide 'erc-compat) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index f159b6d226f..0f3163bf68d 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -215,7 +215,7 @@ erc-stamp--current-time (cl-defgeneric erc-stamp--current-time () "Return a lisp time object to associate with an IRC message. This becomes the message's `erc-timestamp' text property." - (let (current-time-list) (current-time))) + (erc-compat--current-lisp-time)) (cl-defmethod erc-stamp--current-time :around () (or erc-stamp--current-time (cl-call-next-method))) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Fix-date-stamp-invisibility-in-erc-fill-wrap.patch From 0c2b76532490d85a5b622e57af5aa1320278a20c Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 21 Sep 2023 23:54:31 -0700 Subject: [PATCH 2/3] [5.6] Fix date-stamp invisibility in erc-fill-wrap * lisp/erc/erc-fill.el (erc-fill--wrap-measure): New helper function, factored out from common code shared by `erc-fill-wrap' and `erc-fill--wrap-stamp-insert-prefixed-date'. (erc-fill--wrap-stamp-insert-prefixed-date): Refactor for more general use and decrement `invisible' bounds, when applicable. (erc-fill-wrap): Use helper `erc-fill--wrap-measure'. * lisp/erc/erc-stamp.el (erc-insert-timestamp-left-and-right): Mention intervals of relevant text props in doc string. * lisp/erc/erc.el (erc--hide-message): Don't bother offsetting start of first message in a buffer. (erc--own-property-names): Add `erc-stamp-type'. * test/lisp/erc/erc-scenarios-match.el (erc-scenarios-match--fill-wrap-stamp-dedented-p): New function. (erc-scenarios-match--stamp-both-invisible-fill-wrap) New test. (Bug#60936) --- lisp/erc/erc-fill.el | 54 ++++++++----- lisp/erc/erc-stamp.el | 9 ++- lisp/erc/erc.el | 9 ++- test/lisp/erc/erc-scenarios-match.el | 112 ++++++++++++++++++++++++++- 4 files changed, 162 insertions(+), 22 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index f4835f71278..6d39bcb19b9 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -484,25 +484,45 @@ erc-fill--wrap-continued-message-p ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) -(defun erc-fill--wrap-stamp-insert-prefixed-date (&rest args) - "Apply `line-prefix' property to args." - (let* ((ts-left (car args)) - (start) +(defun erc-fill--wrap-measure (beg end) + "Return display spec width for inserted region between BEG and END. +Ignore any `invisible' props that may be present when figuring." + (if (and erc-fill-wrap-use-pixels (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region beg end) + (let (buffer-invisibility-spec) + (list (car (buffer-text-pixel-size))))) + (- end beg))) + +(defun erc-fill--wrap-stamp-insert-prefixed-date (&rest _) + "Apply `line-prefix' property to args. +Expect a multi-line \"date\" stamp, similar to that provided by +the default value of `erc-timestamp-format-left'. Add +`erc-stamp-type' property with the symbol `date-left' as its +value. Possibly adjust invisibility interval to begin at the +previous newline and extend until the end of the last line of the +stamp, not including its line ending." + (let* ((beg) ;; Insert " " to simulate gap between <speaker> and msg beg. (end (save-excursion (skip-chars-backward "\n") - (setq start (pos-bol)) + (setq beg (pos-bol)) (insert " ") (point))) - (width (if (and erc-fill-wrap-use-pixels - (fboundp 'buffer-text-pixel-size)) - (save-restriction (narrow-to-region start end) - (list (car (buffer-text-pixel-size)))) - (length (string-trim-left ts-left))))) + (width (erc-fill--wrap-measure beg end))) (delete-region (1- end) end) - ;; Use `point-min' instead of `start' to cover leading newilnes. + ;; Offset existing invisibility bounds by decrementing. See + ;; `erc-legacy-invisible-bounds-p'. + (when-let ((invisible (get-text-property (point) 'invisible)) + (min (point-min))) + (save-restriction + (widen) + (remove-text-properties (max 1 (1- min)) (1+ (point)) '(invisible nil)) + (narrow-to-region min (1+ (point))) + (erc--hide-message invisible))) + (put-text-property (point-min) (point) 'erc-stamp-type 'date-left) + ;; Use `point-min' instead of `beg' to cover leading newilnes. (put-text-property (point-min) (point) 'line-prefix - `(space :width (- erc-fill--wrap-value ,width)))) - args) + `(space :width (- erc-fill--wrap-value ,width))))) ;; An escape hatch for third-party code expecting speakers of ACTION ;; messages to be exempt from `line-prefix'. This could be converted @@ -536,12 +556,8 @@ erc-fill-wrap (put-text-property (point-min) (point) 'display "") 0) - ((and erc-fill-wrap-use-pixels - (fboundp 'buffer-text-pixel-size)) - (save-restriction - (narrow-to-region (point-min) (point)) - (list (car (buffer-text-pixel-size))))) - (t (- (point) (point-min)))))))) + (t + (erc-fill--wrap-measure (point-min) (point)))))))) (erc-put-text-properties (point-min) (1- (point-max)) ; exclude "\n" '(line-prefix wrap-prefix) nil `((space :width (- erc-fill--wrap-value ,len)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0f3163bf68d..4e16906c550 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -609,7 +609,14 @@ erc-insert-timestamp-left-and-right When the deprecated option `erc-timestamp-format-right' is nil, use STRING, which originates from `erc-timestamp-format', for the right-hand stamp. Use `erc-timestamp-format-left' for the -left-hand stamp and expect it to change less frequently." +left-hand stamp and expect it to change less frequently. Include +line endings present in `erc-timestamp-format-left' as part of +the `erc-timestamp' field, which extends to the start of the +message proper. Do this so other code knows the stamp is part of +the subsequent IRC message even though it may appear on its own +line. However, allow the stamp's `invisible' property to span a +different interval, in order to satisfy newer folding +requirements related to `erc-legacy-invisible-bounds-p'." (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) (ts-right (with-suppressed-warnings diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ec4fae548c7..e4b0cd0ddbe 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3046,7 +3046,11 @@ erc-legacy-invisible-bounds-p (defun erc--hide-message (value) "Apply `invisible' text-property with VALUE to current message. -Expect to run in a narrowed buffer during message insertion." +Expect to run in a narrowed buffer during message insertion. +Begin the invisible interval at the previous message's trailing +newline and end before the current message's. If the preceding +message ends in a double newline or there is no previous message, +don't bother including the preceding newline." (if erc-legacy-invisible-bounds-p ;; Before ERC 5.6, this also used to add an `intangible' ;; property, but the docs say it's now obsolete. @@ -3055,6 +3059,8 @@ erc--hide-message (end (point-max))) (save-restriction (widen) + (when (or (<= beg 4) (= ?\n (char-before (- beg 2)))) + (cl-incf beg)) (erc--merge-prop (1- beg) (1- end) 'invisible value))))) (defun erc-display-message-highlight (type string) @@ -4770,6 +4776,7 @@ 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 diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scenarios-match.el index cd899fddb98..bf74806207d 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -167,7 +167,6 @@ erc-scenarios-match--find-eol ;; In most cases, `erc-hide-fools' makes line endings invisible. (defun erc-scenarios-match--stamp-right-fools-invisible () - :tags '(:expensive-test) (let ((erc-insert-timestamp-function #'erc-insert-timestamp-right)) (erc-scenarios-match--invisible-stamp @@ -271,6 +270,117 @@ erc-scenarios-match--stamp-right-invisible-fill-wrap (let ((inv-beg (next-single-property-change (1- (pos-bol)) 'invisible))) (should (eq (get-text-property inv-beg 'invisible) 'timestamp))))))) +(defun erc-scenarios-match--fill-wrap-stamp-dedented-p (point) + (pcase (get-text-property point 'line-prefix) + (`(space :width (- erc-fill--wrap-value (,n))) + (if (display-graphic-p) (< 100 n 200) (< 10 n 30))) + (`(space :width (- erc-fill--wrap-value ,n)) + (< 10 n 30)))) + +(ert-deftest erc-scenarios-match--stamp-both-invisible-fill-wrap () + + ;; Rewind the clock to known date artificially. + (let ((erc-stamp--current-time 704591940) + (erc-stamp--tz t) + (erc-fill-function #'erc-fill-wrap) + (bob-utterance-counter 0)) + + (erc-scenarios-match--invisible-stamp + + (lambda () + (ert-info ("Baseline check") + ;; False date printed initially before anyone speaks. + (when (zerop bob-utterance-counter) + (save-excursion + (goto-char (point-min)) + (search-forward "[Wed Apr 29 1992]") + ;; First stamp in a buffer is not invisible from previous + ;; newline (before stamp's own leading newline). + (should (= 4 (match-beginning 0))) + (should (get-text-property 3 'invisible)) + (should-not (get-text-property 2 'invisible)) + (should (erc-scenarios-match--fill-wrap-stamp-dedented-p 4)) + (search-forward "[23:59]")))) + + (ert-info ("Line endings in Bob's messages are invisible") + ;; The message proper has the `invisible' property `match-fools'. + (should (eq (get-text-property (pos-bol) 'invisible) 'match-fools)) + (let* ((mbeg (or (and (get-text-property (pos-bol) 'erc-command) + (pos-bol)) + (next-single-property-change (pos-bol) + 'erc-command))) + (mend (text-property-not-all + mbeg (point-max) 'erc-command + (get-text-property mbeg 'erc-command)))) + + (if (/= 1 bob-utterance-counter) + (should-not (field-at-pos mend)) + ;; For Bob's stamped message, check newline after stamp. + (should (eq (field-at-pos mend) 'erc-timestamp)) + (setq mend (field-end mend))) + + ;; The `erc-timestamp' property spans entire messages, + ;; including stamps and filled text, which makes for + ;; convenient traversal when `erc-stamp-mode' is enabled. + (should (get-text-property (pos-bol) 'erc-timestamp)) + (should (= (next-single-property-change (pos-bol) 'erc-timestamp) + mend)) + + ;; Line ending has the `invisible' property `match-fools'. + (should (= (char-after mend) ?\n)) + (with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p)) + (if erc-legacy-invisible-bounds-p + (should (eq (get-text-property mend 'invisible) 'match-fools)) + (should (eq (get-text-property mbeg 'invisible) 'match-fools)) + (should-not (get-text-property mend 'invisible)))))) + + ;; Only the message right after Alice speaks contains stamps. + (when (= 1 bob-utterance-counter) + + (ert-info ("Date stamp occupying previous line is invisible") + (save-excursion + (forward-line -1) + (goto-char (pos-bol)) + (should (looking-at (rx "[Mon May 4 1992]"))) + (should (erc-scenarios-match--fill-wrap-stamp-dedented-p (point))) + ;; Date stamp has a combined `invisible' property value + ;; that starts at the previous message's trailing newline + ;; and extends until the start of the message proper. + (should (equal ?\n (char-before (point)))) + (should (equal ?\n (char-before (1- (point))))) + (let ((val (get-text-property (- (point) 2) 'invisible))) + (should (equal val '(timestamp match-fools))) + (should (= (text-property-not-all (- (point) 2) (point-max) + 'invisible val) + (pos-eol)))))) + + (ert-info ("Current message's RHS stamp is hidden") + ;; Right stamp has `match-fools' property. + (save-excursion + (should-not (field-at-pos (point))) + (should (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp))) + + ;; Stamp invisibility starts where message's ends. + (let ((msgend (next-single-property-change (pos-bol) 'invisible))) + ;; Stamp has a combined `invisible' property value. + (should (equal (get-text-property msgend 'invisible) + '(timestamp match-fools))) + + ;; Combined `invisible' property spans entire timestamp. + (should (= (next-single-property-change msgend 'invisible) + (pos-eol)))))) + + (cl-incf bob-utterance-counter)) + + ;; Alice. + (lambda () + ;; Set clock ahead a week or so. + (setq erc-stamp--current-time 704962800) + + ;; This message has no time stamp and is completely visible. + (should-not (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp)) + (should-not (next-single-property-change (pos-bol) 'invisible)))))) + (defun erc-scenarios-match--stamp-both-invisible-fill-static () (should (eq erc-insert-timestamp-function #'erc-insert-timestamp-left-and-right)) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Add-command-to-refill-buffer-with-erc-fill-wrap-.patch From 2dd2c5c00e5a405f74ee0c7d61b35ba2f1e633e1 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 21 Sep 2023 06:54:27 -0700 Subject: [PATCH 3/3] [5.6] Add command to refill buffer with erc-fill-wrap-mode * lisp/erc/erc-fill.el (erc-fill--wrap-rejigger-last-message): New internal variable. (erc-fill--wrap-rejigger-region, erc-fill-wrap-refill-buffer): New command and helper function. (Bug#60936) --- lisp/erc/erc-fill.el | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 6d39bcb19b9..78b29b51cf7 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -563,6 +563,57 @@ erc-fill-wrap `((space :width (- erc-fill--wrap-value ,len)) (space :width erc-fill--wrap-value)))))) +(defvar erc-fill--wrap-rejigger-last-message nil + "Temporary working instance of `erc-fill--wrap-last-msg'.") + +(defun erc-fill--wrap-rejigger-region (start finish on-next) + "Recalculate `line-prefix' from START to FINISH. +After refilling each message, call ON-NEXT with no args. But +stash and restore `erc-fill--wrap-last-msg' before doing so, in +case this module's insert hooks run by way of the process filter." + (goto-char start) + (cl-assert (null erc-fill--wrap-rejigger-last-message)) + (let (erc-fill--wrap-rejigger-last-message) + (while-let + (((< (point) finish)) + (beg (if (get-text-property (point) 'line-prefix) + (point) + (next-single-property-change (point) 'line-prefix))) + (val (get-text-property beg 'line-prefix)) + (end (text-property-not-all beg finish 'line-prefix val))) + ;; If this is a left-side stamp on its own line. + (remove-text-properties beg (1+ end) '(line-prefix nil wrap-prefix nil)) + (save-restriction + (narrow-to-region beg (1+ end)) + (if-let (((eq 'erc-timestamp (field-at-pos beg))) + ((eq 'date-left (get-text-property beg 'erc-stamp-type)))) + (progn + (goto-char (field-end beg)) + (erc-fill--wrap-stamp-insert-prefixed-date)) + (let ((erc-fill--wrap-last-msg erc-fill--wrap-rejigger-last-message)) + (erc-fill-wrap) + (setq erc-fill--wrap-rejigger-last-message + erc-fill--wrap-last-msg)))) + (when on-next + (funcall on-next)) + (goto-char end)))) + +(defun erc-fill-wrap-refill-buffer () + "Recalculate all `fill-wrap' prefixes in the current buffer." + (interactive) + (unless erc-fill-wrap-mode + (user-error "Module `fill-wrap' not active in current buffer.")) + (save-excursion + (with-silent-modifications + (let* ((rep (make-progress-reporter + "Rewrap" 0 (line-number-at-pos erc-insert-marker) 1)) + (seen 0) + (callback (lambda () + (progress-reporter-update rep (cl-incf seen)) + (accept-process-output nil 0.000001)))) + (erc-fill--wrap-rejigger-region (point-min) erc-insert-marker callback) + (progress-reporter-done rep))))) + ;; FIXME use own text property to avoid false positives. (defun erc-fill--wrap-merged-button-p (point) (equal "" (get-text-property point 'display))) -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 23:40:15 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Sep 13 19:40:15 2023 Received: from localhost ([127.0.0.1]:36327 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qgZSx-0000hT-5P for submit <at> debbugs.gnu.org; Wed, 13 Sep 2023 19:40:15 -0400 Received: from mail-lf1-x132.google.com ([2a00:1450:4864:20::132]:52400) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <stefankangas@HIDDEN>) id 1qgZSu-0000hD-Cy for 60936 <at> debbugs.gnu.org; Wed, 13 Sep 2023 19:40:13 -0400 Received: by mail-lf1-x132.google.com with SMTP id 2adb3069b0e04-502e385e33bso570052e87.0 for <60936 <at> debbugs.gnu.org>; Wed, 13 Sep 2023 16:40:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1694648401; x=1695253201; darn=debbugs.gnu.org; h=cc:to:subject:message-id:date:mime-version:references:in-reply-to :from:from:to:cc:subject:date:message-id:reply-to; bh=tikWxD3I1Hq8qXH8/CYBmkUAn8nM9nxK2b0aGhY6SK4=; b=cWd7Zd63IupfTUzf2BCrJVytc4Fsdim23KW7TL3x8NSFH0DhmhrpLpTE/Cw9kBThBV nzU4wNH7AuOuJufh9Ri/jR8fgOwfClBimNpH1n1vDuvijKEFyUC8KwijWvsUvgjdODoO Nv+1xNhB8bSixw78zEP2kM10jOKL0mPyH8wK7Klv7W32iIYXujaYHBOjhPidTnj7D2Cu Mhi7h6kzrbPF3YGRwaca/mEcgDGqcq6WZEhEZVH4LDJemp/xpIEI+r1ZpXva0poiY1gE I5hRNEbP428W2hASQE/PElNv6sna1kCx3uLmKdORy5cT06HsNhO83OYdwUh8Uj0ahdDx KfJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1694648401; x=1695253201; h=cc:to:subject:message-id:date:mime-version:references:in-reply-to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tikWxD3I1Hq8qXH8/CYBmkUAn8nM9nxK2b0aGhY6SK4=; b=n4DnAGq+hoXJhv8XprS2TIN/WOk3sDNpA18nu9qGAstfHMrxzCilLcC701SOnF3z0k KjdfyVdXUG9vBPCd8jfVEvesAERPiJrqTi0vF5YwGOjmimqoVtQV0+0LtKGOwfvxPmQU XiYlIDCincPzE+rijW+ZykA2zbSFdp78FXU+M2dJRnr34Ohbt1FL6/CkRrIcgQ5q6dVM jttTGZUiOcMcNAvR5y5nOk+KFzGZCpNBya1r+1QGG1JfJfkgxbkHYyyrq9AA5qqMUI8b jMSJI6wrJFo3d2qM0Nb1WWlUrEjGYKJ7gisDyKj4UWOWHue/95j3/4yo0x9vFjzt+8nz 8ulA== X-Gm-Message-State: AOJu0YxWOYY7Wmv2uKYS95t3XoqPkY4SIBt4fZiP4RXQOq0azZXXmvvU QSVeH1NaISiuhPaVvDFI8dRPjuKB//UGLEWbiB7nY19WH0M= X-Google-Smtp-Source: AGHT+IG5OiTiL0etQfyutp4WSKfjBXrhQ6piyJ9t66eR4UeqMQ0/bSudjJwzyEc5icKLJW3mzskl3bN3IAGJZKkFRNo= X-Received: by 2002:ac2:4248:0:b0:500:95f7:c416 with SMTP id m8-20020ac24248000000b0050095f7c416mr3357692lfl.7.1694648400571; Wed, 13 Sep 2023 16:40:00 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Wed, 13 Sep 2023 16:40:00 -0700 From: Stefan Kangas <stefankangas@HIDDEN> In-Reply-To: <87pm2lzn1i.fsf@HIDDEN> References: <87tu0nao77.fsf@HIDDEN> <87il8vxrr1.fsf@HIDDEN> <CADwFkmm3bfkXaOvDYXwKr+RsXird-X47rK=QW6M_cuD6YEm=zA@HIDDEN> <87pm2lzn1i.fsf@HIDDEN> MIME-Version: 1.0 Date: Wed, 13 Sep 2023 16:40:00 -0700 Message-ID: <CADwFkmnmk9mQPy=+Pt=9x4G9zCEGwz4Od6mxcOePoxNFKXNing@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode To: "J.P." <jp@HIDDEN> Content-Type: text/plain; charset="UTF-8" X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > Should be fixed now (hopefully). I can confirm that it is fixed. Thanks.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 23:11:38 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Sep 13 19:11:38 2023 Received: from localhost ([127.0.0.1]:36320 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qgZ1G-0008T0-Hy for submit <at> debbugs.gnu.org; Wed, 13 Sep 2023 19:11:38 -0400 Received: from mail-108-mta17.mxroute.com ([136.175.108.17]:41099) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qgZ1C-0008Sn-NL for 60936 <at> debbugs.gnu.org; Wed, 13 Sep 2023 19:11:36 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta17.mxroute.com (ZoneMTA) with ESMTPSA id 18a90d04eae000d7b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 13 Sep 2023 23:11:25 +0000 X-Zone-Loop: b0e8a729418627983f6941c349f9a7ef700caff2d815 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=owsjduwKtt88zRwPxt6Cp+rxtEEz9UlEui8OqMRFj/c=; b=EfPIn4ucd5/FO111S4lgG6+Zyc 4YTKcOhUyXiG4177SQG1v8dIFhKVX0a1FTlNxAWvLlNiiVWBAyQ45m/e4a90WmkDyjFe2laOTBJ7A QDbIZFecXZ6KLo4skIuhEqujoHgeT7KBSevVCi0wd6ayybEwL7oPUN63rMyIICU7ATFkx4NVSLyVa B510+nqbXTZUlBa7m8dGS+MleX0gOGuQJQ/q9ZtHjYJCVdsd/oGryxxoNYgcXK2FmPzThNVSIVJQK hnAthUqJPbe/APp30RHgHbcka1gJv/wUaJXpkGqJsfgGRUIUI2Mv74Qw/y3WybAGcd9pCabz6/lC0 ioyjQBnQ==; From: "J.P." <jp@HIDDEN> To: Stefan Kangas <stefankangas@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <CADwFkmm3bfkXaOvDYXwKr+RsXird-X47rK=QW6M_cuD6YEm=zA@HIDDEN> (Stefan Kangas's message of "Wed, 13 Sep 2023 08:56:12 -0700") References: <87tu0nao77.fsf@HIDDEN> <87il8vxrr1.fsf@HIDDEN> <CADwFkmm3bfkXaOvDYXwKr+RsXird-X47rK=QW6M_cuD6YEm=zA@HIDDEN> Date: Wed, 13 Sep 2023 16:11:21 -0700 Message-ID: <87pm2lzn1i.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) Stefan Kangas <stefankangas@HIDDEN> writes: > I'm seeing new test failures with this file on master: > > [...] > normal-top-level() > Test erc-echo-timestamp condition: > (ert-test-failed > ((should (equal (call-interactively ...) "1983-09-27 04:00:00 GMT")) > :form (equal "1983-09-27 04:00:00 UTC" "1983-09-27 04:00:00 GMT") > :value nil :explanation > (array-elt 20 (different-atoms (85 "#x55" "?U") (71 "#x47" "?G"))))) > FAILED 1/6 erc-echo-timestamp (0.002433 sec) at Oof. Sorry about that. Should be fixed now (hopefully).
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 15:56:28 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Sep 13 11:56:28 2023 Received: from localhost ([127.0.0.1]:35731 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qgSE7-0006ZE-JL for submit <at> debbugs.gnu.org; Wed, 13 Sep 2023 11:56:27 -0400 Received: from mail-lj1-x232.google.com ([2a00:1450:4864:20::232]:52504) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <stefankangas@HIDDEN>) id 1qgSE4-0006Yz-PI for 60936 <at> debbugs.gnu.org; Wed, 13 Sep 2023 11:56:25 -0400 Received: by mail-lj1-x232.google.com with SMTP id 38308e7fff4ca-2bfbbd55158so12803181fa.1 for <60936 <at> debbugs.gnu.org>; Wed, 13 Sep 2023 08:56:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1694620573; x=1695225373; darn=debbugs.gnu.org; h=content-transfer-encoding:cc:to:subject:message-id:date :mime-version:references:in-reply-to:from:from:to:cc:subject:date :message-id:reply-to; bh=VqiYl0BW3zfX9+Wg7d8i0IoNi3/osTwFSVDBJWponq4=; b=E/mYr5xKQinaoBmw4C+Ou6HrveJjC5Erkwc2bUhObc5i/JfrjAqI/r+aWMU4jIVubf 7sKNQTWZumnlCjkfcWU/zVCBOVGCnpPzng82w1ci0VK6RX1PDIFcOtSMKkjkFBeQuYYc EFlrZ/8DAacD7wD5Z9mXhUhcw43o1NjXQQiC2TdvF+pJu20cQX5YqoEVoS5Q0WQegzhB 59S9qC8iaJH5NqidlsxHjMlaxlDGqWwWvG2PMP6gXqPG4nwbZABPS46XVcILrFhoUgT+ glJRHVF17dDePFS8u8wRJUypc2172aEvunGxr9d4E7u1PUz81hYXhV4eZiBpB+jUDhCk g+eQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1694620573; x=1695225373; h=content-transfer-encoding:cc:to:subject:message-id:date :mime-version:references:in-reply-to:from:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=VqiYl0BW3zfX9+Wg7d8i0IoNi3/osTwFSVDBJWponq4=; b=K12SMFRQVwtnGJl+yL/VopSGUZTT6vLOhxxbnXUj7TvEk4Pec6m10YskCUfYAOb8uk 0z4YVh5IVtvpDY4P5gghbMj5sHNA2jnfEzMgKEsjG6cSe7SYAAUkcvaJO/RXHLBTM0VS xwJrhiB9YfHp5hkxQLgu4NWEcpuuOerKCFVZKkDGSr+RUj16eHuWfCS+x5rg+K6waNuf Qv08AjgFv5gvwin5byNnhjx7yZb8nTa3p82Z/cs6KkJjjKp/rdc4wdZUcadTMybrwgBQ +FW10gytuTVooXW+8FStE2gSPIGVZzuNCKsC85ZKP79lrQVPYQVGcBtADNV6q1Y9t1LO Vdow== X-Gm-Message-State: AOJu0YyRW9b82p+XbEyTEMk5B8cjGqKp7NwrZf3sAqZoABZW0X7oG/It XosbbcMFdVZSFAwlSkZtK49xAWrjTSpJ6ETj4Ic= X-Google-Smtp-Source: AGHT+IGXjTixofjfFem6qcypiwryypUs1kmk8bt/sSR1m1Blxz9eDN1tZUyhefg9ksXUodVdb+sZ9d/6zbNVVLsgntU= X-Received: by 2002:a2e:9849:0:b0:2b9:55c9:c228 with SMTP id e9-20020a2e9849000000b002b955c9c228mr2677727ljj.27.1694620573306; Wed, 13 Sep 2023 08:56:13 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Wed, 13 Sep 2023 08:56:12 -0700 From: Stefan Kangas <stefankangas@HIDDEN> In-Reply-To: <87il8vxrr1.fsf@HIDDEN> References: <87tu0nao77.fsf@HIDDEN> <87il8vxrr1.fsf@HIDDEN> MIME-Version: 1.0 Date: Wed, 13 Sep 2023 08:56:12 -0700 Message-ID: <CADwFkmm3bfkXaOvDYXwKr+RsXird-X47rK=QW6M_cuD6YEm=zA@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode To: "J.P." <jp@HIDDEN>, 60936 <at> debbugs.gnu.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > One of my patches for this feature introduced a corner-case regression > involving the option `erc-echo-timestamps'. If `cursor-sensor-mode' is > somehow enabled outside of this module, then timestamps will still be > echoed even when `erc-echo-timestamps' is nil. > > commit ad3dc74e074719a58226e23a45c4556cd54c0a48 > Author: F. Jason Park <jp@HIDDEN> > Date: Wed Nov 24 03:10:20 2021 -0800 > > Expose insertion time as text prop in erc-stamp > > * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property > [...] > (erc-echo-timestamp): Make interactive and show timestamps even whe= n > the variable `erc-echo-timestamps' is nil. > (erc--echo-ts-csf): Add new function to serve as value of > cursor-sensor function text properties. > * test/lisp/erc/erc-stamp-tests.el: New file. (Bug#60936.) I'm seeing new test failures with this file on master: Running 6 tests (2023-09-13 16:45:56+0200, selector =E2=80=98(not (or (tag :expensive-test) (tag :unstable) (tag :nativecomp)))=E2=80=99) Test erc-echo-timestamp backtrace: signal(ert-test-failed (((should (equal (call-interactively #'erc-ec ert-fail(((should (equal (call-interactively #'erc-echo-timestamp) " #f(compiled-function () #<bytecode -0x766a19e4460e6be>)() ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test ert-run-test(#s(ert-test :name erc-echo-timestamp :documentation nil ert-run-or-rerun-test(#s(ert--stats :selector (not (or ... ... ...)) ert-run-tests((not (or (tag :expensive-test) (tag :unstable) (tag :n ert-run-tests-batch((not (or (tag :expensive-test) (tag :unstable) ( ert-run-tests-batch-and-exit((not (or (tag :expensive-test) (tag :un eval((ert-run-tests-batch-and-exit '(not (or (tag :expensive-test) ( command-line-1(("-L" ":." "-l" "ert" "-l" "lisp/erc/erc-stamp-tests" command-line() normal-top-level() Test erc-echo-timestamp condition: (ert-test-failed ((should (equal (call-interactively ...) "1983-09-27 04:00:00 GMT")) :form (equal "1983-09-27 04:00:00 UTC" "1983-09-27 04:00:00 GMT") :value nil :explanation (array-elt 20 (different-atoms (85 "#x55" "?U") (71 "#x47" "?G"))))) FAILED 1/6 erc-echo-timestamp (0.002433 sec) at lisp/erc/erc-stamp-tests.el:277 passed 2/6 erc-stamp--display-margin-mode--right (0.009260 sec) passed 3/6 erc-timestamp-intangible--left (0.012494 sec) passed 4/6 erc-timestamp-use-align-to--integer (0.007917 sec) passed 5/6 erc-timestamp-use-align-to--nil (0.015289 sec) passed 6/6 erc-timestamp-use-align-to--t (0.024845 sec) Ran 6 tests, 5 results as expected, 1 unexpected (2023-09-13 16:45:56+0200, 0.484120 sec) 1 unexpected results: FAILED erc-echo-timestamp GEN lisp/eshell/em-dirs-tests.log make[3]: *** [lisp/erc/erc-stamp-tests.log] Error 1 In GNU Emacs 30.0.50 (build 3, x86_64-apple-darwin21.6.0, NS appkit-2113.60 Version 12.6.9 (Build 21G726)) of 2023-09-13 built on MY-MacBook-Pro Repository revision: 1f7113e68988fa0bcbdeca5ae364cba8d6db3637 Repository branch: master Windowing system distributor 'Apple', version 10.3.2113 System Description: macOS 12.6.9 Configured features: ACL GIF GMP GNUTLS JPEG JSON LCMS2 LIBXML2 MODULES NOTIFY KQUEUE NS PDUMPER PNG SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER WEBP XIM ZLIB
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 14:06:46 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Sep 13 10:06:46 2023 Received: from localhost ([127.0.0.1]:35484 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qgQVx-0000rI-UM for submit <at> debbugs.gnu.org; Wed, 13 Sep 2023 10:06:46 -0400 Received: from mail-108-mta228.mxroute.com ([136.175.108.228]:41091) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qgQVt-0000r7-WF for 60936 <at> debbugs.gnu.org; Wed, 13 Sep 2023 10:06:45 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta228.mxroute.com (ZoneMTA) with ESMTPSA id 18a8edd731b000d7b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 13 Sep 2023 14:06:32 +0000 X-Zone-Loop: 92822eef4a5a3e4994cd5277b1d8a2adcd504703b450 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=4bHWSfOWvF2KPxQR4pfxZ1BvAMevjoXOb4MwmOfVYGo=; b=i5PteEEEkse2A3T6D5vCX+N+Hr juqNGRLEXuJhIhcxPoK9DkbJxaJzd7lHa5spEpsYT2amrywCfekrse+7vLKwKIQO7VzmS1fmN2TFm i0WbtkI6/FL/8HZg93bY5IC7VYLWPi/uflCa/2hdgxOj1CG74feaPnGpE1xufXeq3HLypV6FeCndA HZ7GH9MWBg1/ZfasSP9K/aYjsOUcuK7v89o5z986uTGfBF+RfZjYkZ3OBvLrFKYtbJbPBfPDXJ86x R/r/zyCJp03v28nIUkGlcGlFVf/BMJFtGl90a3/ycTqWE4c2kWwEyZ/t6jsHJr848IqF1iLFkedxA yHrBamtw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87il8vxrr1.fsf@HIDDEN> (J. P.'s message of "Thu, 31 Aug 2023 06:31:46 -0700") References: <87tu0nao77.fsf@HIDDEN> <87il8vxrr1.fsf@HIDDEN> Date: Wed, 13 Sep 2023 07:06:28 -0700 Message-ID: <87zg1qyxp7.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > In addition to addressing the above, the attached patch includes a new > optional parameter for the command `erc-echo-timestamp'. It allows for > specifying a timezone for the echoed stamp via prefix argument or a new > option, `erc-echo-timestamp-zone'. > > These changes are intended for ERC 5.6. Added as commit 7c932fa307851ccef1cf17a1d7eec689af82a0ef Add optional timezone param to erc-echo-timestamp This bug is already closed.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 31 Aug 2023 13:32:07 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Thu Aug 31 09:32:06 2023 Received: from localhost ([127.0.0.1]:55192 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qbhmG-0005wS-Pm for submit <at> debbugs.gnu.org; Thu, 31 Aug 2023 09:32:06 -0400 Received: from mail-108-mta59.mxroute.com ([136.175.108.59]:45787) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qbhmD-0005w3-2Y for 60936 <at> debbugs.gnu.org; Thu, 31 Aug 2023 09:32:03 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta59.mxroute.com (ZoneMTA) with ESMTPSA id 18a4bcb0604000d7b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Thu, 31 Aug 2023 13:31:51 +0000 X-Zone-Loop: f68bddc17320c579a6d8ef0dad95342a82db99146893 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=bJP1F7523Ditipigv5KYS0hTIe6C9xJG/Whuo+21Waw=; b=evPdLSwTPDiBdD2FoAPq0L/pO/ YCCBm1Vqr+7c3UEZ1/Ieq21Fh01iN8yzMeG82RnDSxGEeUYFmICk8grpJ1EsDDRr3PI611HAslh6/ 88Eggr+hI+27PTyZ9VYAx+9r6tptIDEhHvDC+oTBP1WGaquin2CLQ181b/YHEW2+/nCc/ogbcaG0v rdVIFukqEpT9GqbZUmQ2ZC7cFluDLy7qQv2rnzR+r8e4jzIvITfQ+MEs6HTtbWxKE/9YNyqHkCc/5 4O8IXTkUjhhojaJ+OETFKWoRniLWjXyMzAuT30K8X/c3geB8/YL4iyGbEHSviDdx46MMvC7G9t+sw JAr4X04A==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Thu, 31 Aug 2023 06:31:46 -0700 Message-ID: <87il8vxrr1.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain One of my patches for this feature introduced a corner-case regression involving the option `erc-echo-timestamps'. If `cursor-sensor-mode' is somehow enabled outside of this module, then timestamps will still be echoed even when `erc-echo-timestamps' is nil. commit ad3dc74e074719a58226e23a45c4556cd54c0a48 Author: F. Jason Park <jp@HIDDEN> Date: Wed Nov 24 03:10:20 2021 -0800 Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property [...] (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. (Bug#60936.) lisp/erc/erc-stamp.el | 15 ++- test/lisp/erc/erc-stamp-tests.el | 207 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 5 deletions(-) In addition to addressing the above, the attached patch includes a new optional parameter for the command `erc-echo-timestamp'. It allows for specifying a timezone for the echoed stamp via prefix argument or a new option, `erc-echo-timestamp-zone'. These changes are intended for ERC 5.6. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Allow-alternate-ert-info-text-in-ERC-test-utilit.patch From 1ca0862854ff5f926ed45b06cc494aa7f7f2b1b7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 25 Aug 2023 19:03:26 -0700 Subject: [PATCH 1/2] [5.6] ; Allow alternate ert-info text in ERC test utility * test/lisp/erc/erc-tests.el (erc-tests--assert-printed-in-subprocess): Don't insist that arguments to the Emacs "-load" invocation option be actual disk files. * test/lisp/erc/resources/base/assoc/bumped/again.eld: Adjust timeouts. * test/lisp/erc/resources/base/assoc/bumped/foisted.eld: Adjust timeouts. * test/lisp/erc/resources/base/assoc/bumped/refoisted.eld: Adjust timeouts. * test/lisp/erc/resources/base/netid/bouncer/barnet.eld: Adjust timeouts. * test/lisp/erc/resources/base/netid/bouncer/foonet.eld: Adjust timeouts. * test/lisp/erc/resources/base/renick/self/qual-chester.eld: Adjust timeouts. * test/lisp/erc/resources/base/renick/self/qual-tester.eld: Adjust timeouts. * test/lisp/erc/resources/erc-d/erc-d-t.el (erc-d-t--wait-message-prefix, erc-d-t-wait-for, erc-d-t-ensure-for): Add and use new variable to make `ert-info' message prefix adjustable. The immediate use for this is to make it easier to distinguish between consecutive assertions in which the first waits for a condition and the second ensures it holds for some duration. * test/lisp/erc/resources/erc-d/erc-d-u.el (erc-d-u--read-exchange-default): Skip killed buffers. * test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld: Adjust timeout. * test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld: Adjust timeouts. * test/lisp/erc/resources/erc-d/resources/linger.eld: Adjust timeouts. --- test/lisp/erc/erc-tests.el | 3 +-- test/lisp/erc/resources/base/assoc/bumped/again.eld | 10 +++++----- test/lisp/erc/resources/base/assoc/bumped/foisted.eld | 10 +++++----- .../lisp/erc/resources/base/assoc/bumped/refoisted.eld | 8 ++++---- test/lisp/erc/resources/base/netid/bouncer/barnet.eld | 2 +- test/lisp/erc/resources/base/netid/bouncer/foonet.eld | 2 +- .../erc/resources/base/renick/self/qual-chester.eld | 2 +- .../erc/resources/base/renick/self/qual-tester.eld | 2 +- test/lisp/erc/resources/erc-d/erc-d-t.el | 7 +++++-- test/lisp/erc/resources/erc-d/erc-d-u.el | 1 + .../erc/resources/erc-d/resources/dynamic-barnet.eld | 4 ++-- .../erc/resources/erc-d/resources/dynamic-foonet.eld | 2 +- test/lisp/erc/resources/erc-d/resources/linger.eld | 4 ++-- 13 files changed, 30 insertions(+), 27 deletions(-) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 9fdad823059..7e01efe95cf 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -2038,8 +2038,7 @@ erc-tests--assert-printed-in-subprocess ;; This is for integrations testing with managed configs ;; ("starter kits") that use a different package manager. (init (and-let* ((found (getenv "ERC_TESTS_INIT")) - (files (split-string found ",")) - ((seq-every-p #'file-exists-p files))) + (files (split-string found ","))) (mapcan (lambda (f) (list "-l" f)) files))) (prog `(progn diff --git a/test/lisp/erc/resources/base/assoc/bumped/again.eld b/test/lisp/erc/resources/base/assoc/bumped/again.eld index ab3c7b06214..aef164b6237 100644 --- a/test/lisp/erc/resources/base/assoc/bumped/again.eld +++ b/test/lisp/erc/resources/base/assoc/bumped/again.eld @@ -1,10 +1,10 @@ ;; -*- mode: lisp-data; -*- -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0.0 ":irc.foonet.org 433 * tester :Nickname is reserved by a different account") (0.0 ":irc.foonet.org FAIL NICK NICKNAME_RESERVED tester :Nickname is reserved by a different account")) -((nick 3 "NICK tester`") +((nick 10 "NICK tester`") (0.1 ":irc.foonet.org 001 tester` :Welcome to the foonet IRC Network tester`") (0.0 ":irc.foonet.org 002 tester` :Your host is irc.foonet.org, running version oragono-2.6.1-937b9b02368748e5") (0.0 ":irc.foonet.org 003 tester` :This server was created Fri, 24 Sep 2021 01:38:36 UTC") @@ -21,10 +21,10 @@ (0.2 ":irc.foonet.org 266 tester` 3 3 :Current global users 3, max 3") (0.0 ":irc.foonet.org 422 tester` :MOTD File is missing")) -((mode-user 3.2 "MODE tester` +i") +((mode-user 10 "MODE tester` +i") (0.0 ":irc.foonet.org 221 tester` +i") (0.0 ":irc.foonet.org NOTICE tester` :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.")) -((privmsg 42.6 "PRIVMSG NickServ :IDENTIFY tester changeme") +((privmsg 10 "PRIVMSG NickServ :IDENTIFY tester changeme") (0.01 ":tester`!~u@HIDDEN NICK tester") (0.0 ":NickServ!NickServ@localhost NOTICE tester :You're now logged in as tester")) diff --git a/test/lisp/erc/resources/base/assoc/bumped/foisted.eld b/test/lisp/erc/resources/base/assoc/bumped/foisted.eld index 5c36e58d9d3..0f7aadac564 100644 --- a/test/lisp/erc/resources/base/assoc/bumped/foisted.eld +++ b/test/lisp/erc/resources/base/assoc/bumped/foisted.eld @@ -1,6 +1,6 @@ ;; -*- mode: lisp-data; -*- -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.1-937b9b02368748e5") (0.0 ":irc.foonet.org 003 tester :This server was created Fri, 24 Sep 2021 01:38:36 UTC") @@ -17,14 +17,14 @@ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0.0 ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 1.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0.0 ":irc.foonet.org 221 tester +i") (0.0 ":irc.foonet.org NOTICE tester :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.")) -((privmsg 17.21 "PRIVMSG bob :hi") +((privmsg 10 "PRIVMSG bob :hi") (0.02 ":bob!~u@HIDDEN PRIVMSG tester :hola") (0.01 ":bob!~u@HIDDEN PRIVMSG tester :how r u?")) -((quit 18.19 "QUIT :" quit) +((quit 10 "QUIT :" quit) (0.01 ":tester!~u@HIDDEN QUIT :Quit: " quit)) ((drop 1 DROP)) diff --git a/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld b/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld index 33e4168ac46..63366d3f576 100644 --- a/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld +++ b/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld @@ -1,6 +1,6 @@ ;; -*- mode: lisp-data; -*- -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0.1 ":irc.foonet.org 001 dummy :Welcome to the foonet IRC Network dummy") (0.0 ":irc.foonet.org 002 dummy :Your host is irc.foonet.org, running version oragono-2.6.1-937b9b02368748e5") (0.0 ":irc.foonet.org 003 dummy :This server was created Fri, 24 Sep 2021 01:38:36 UTC") @@ -22,10 +22,10 @@ (0.01 ":bob!~u@HIDDEN PRIVMSG dummy :back?") ) -((mode-user 1.2 "MODE dummy +i") +((mode-user 10 "MODE dummy +i") (0.0 ":irc.foonet.org 221 dummy +i") (0.0 ":irc.foonet.org NOTICE dummy :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.")) -((renick 42.6 "NICK tester") +((renick 10 "NICK tester") (0.01 ":dummy!~u@HIDDEN NICK tester") (0.0 ":NickServ!NickServ@localhost NOTICE dummy :You're now logged in as tester")) diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet.eld b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld index 204d01fef77..596383c2699 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/barnet.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld @@ -38,4 +38,4 @@ (0.05 ":joe!~u@HIDDEN PRIVMSG #chan :mike: As he regards his aged father's life.") (0.05 ":mike!~u@HIDDEN PRIVMSG #chan :joe: It is a rupture that you may easily heal; and the cure of it not only saves your brother, but keeps you from dishonor in doing it.")) -((linger 1 LINGER)) +((linger 2 LINGER)) diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet.eld b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld index 4445350ca0c..2e1a3ac27da 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/foonet.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld @@ -43,4 +43,4 @@ (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :bob: Orlando, my liege; the youngest son of Sir Rowland de Boys.") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: The ape is dead, and I must conjure him.")) -((linger 1 LINGER)) +((linger 2 LINGER)) diff --git a/test/lisp/erc/resources/base/renick/self/qual-chester.eld b/test/lisp/erc/resources/base/renick/self/qual-chester.eld index 75b50fe68bd..a224e0451d7 100644 --- a/test/lisp/erc/resources/base/renick/self/qual-chester.eld +++ b/test/lisp/erc/resources/base/renick/self/qual-chester.eld @@ -18,7 +18,7 @@ (0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4") (0 ":irc.foonet.org 422 chester :MOTD File is missing")) -((mode-user 1.2 "MODE chester +i") +((mode-user 10 "MODE chester +i") (0 ":irc.foonet.org 221 chester +i") (0 ":irc.foonet.org NOTICE chester :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.")) diff --git a/test/lisp/erc/resources/base/renick/self/qual-tester.eld b/test/lisp/erc/resources/base/renick/self/qual-tester.eld index 25199226658..27061c65223 100644 --- a/test/lisp/erc/resources/base/renick/self/qual-tester.eld +++ b/test/lisp/erc/resources/base/renick/self/qual-tester.eld @@ -18,7 +18,7 @@ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 1.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0 ":irc.foonet.org 221 tester +i") (0 ":irc.foonet.org NOTICE tester :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.")) diff --git a/test/lisp/erc/resources/erc-d/erc-d-t.el b/test/lisp/erc/resources/erc-d/erc-d-t.el index 7b2adf4f07b..cf869fb3c70 100644 --- a/test/lisp/erc/resources/erc-d/erc-d-t.el +++ b/test/lisp/erc/resources/erc-d/erc-d-t.el @@ -83,6 +83,8 @@ erc-d-t-with-cleanup (ignore-errors (kill-buffer buf))))) (sleep-for erc-d-t-cleanup-sleep-secs))))) +(defvar erc-d-t--wait-message-prefix "Awaiting: ") + (defmacro erc-d-t-wait-for (max-secs msg &rest body) "Wait for BODY to become non-nil. Or signal error with MSG after MAX-SECS. When MAX-SECS is negative, @@ -99,7 +101,7 @@ erc-d-t-wait-for (let ((inverted (make-symbol "inverted")) (time-out (make-symbol "time-out")) (result (make-symbol "result"))) - `(ert-info ((concat "Awaiting: " ,msg)) + `(ert-info ((concat erc-d-t--wait-message-prefix ,msg)) (let ((,time-out (abs ,max-secs)) (,inverted (< ,max-secs 0)) (,result ',result)) @@ -120,7 +122,8 @@ erc-d-t-ensure-for (unless (or (stringp msg) (memq (car-safe msg) '(format concat))) (push msg body) (setq msg (prin1-to-string body))) - `(erc-d-t-wait-for (- (abs ,max-secs)) ,msg (not (progn ,@body)))) + `(let ((erc-d-t--wait-message-prefix "Sustaining: ")) + (erc-d-t-wait-for (- (abs ,max-secs)) ,msg (not (progn ,@body))))) (defun erc-d-t-search-for (timeout text &optional from on-success) "Wait for TEXT to appear in current buffer before TIMEOUT secs. diff --git a/test/lisp/erc/resources/erc-d/erc-d-u.el b/test/lisp/erc/resources/erc-d/erc-d-u.el index e26fa8b47dd..c7d6859e3e1 100644 --- a/test/lisp/erc/resources/erc-d/erc-d-u.el +++ b/test/lisp/erc/resources/erc-d/erc-d-u.el @@ -74,6 +74,7 @@ erc-d-u--read-exchange-default (let ((hunks (erc-d-u-scan-e-sd info)) (pos (erc-d-u-scan-e-pos info))) (or (and (erc-d-u-scan-d-hunks hunks) + (buffer-live-p (erc-d-u-scan-d-buf hunks)) (with-current-buffer (erc-d-u-scan-d-buf hunks) (goto-char pos) (condition-case _err diff --git a/test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld b/test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld index 4994e9c5503..e8feb2e6fd8 100644 --- a/test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld +++ b/test/lisp/erc/resources/erc-d/resources/dynamic-barnet.eld @@ -18,14 +18,14 @@ (0. ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3") (0. ":irc.barnet.org 422 tester :MOTD File is missing")) -((mode-user 1.2 "MODE tester +i") +((mode-user 2 "MODE tester +i") (0. ":irc.barnet.org 221 tester +Zi") (0. ":irc.barnet.org 306 tester :You have been marked as being away") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.barnet.org 353 joe = #chan :+joe!~joe@HIDDEN @%+mike!~mike@HIDDEN") (0 ":irc.barnet.org 366 joe #chan :End of NAMES list")) -((mode 1 "MODE #chan") +((mode 3 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620805269") (0.1 ":joe!~u@HIDDEN PRIVMSG #chan :mike: Yes, a dozen; and as many to the vantage, as would store the world they played for.") diff --git a/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld b/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld index a47998e7d32..4855c178861 100644 --- a/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld +++ b/test/lisp/erc/resources/erc-d/resources/dynamic-foonet.eld @@ -17,7 +17,7 @@ (0. ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0. ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 1.2 "MODE tester +i") +((mode-user 2 "MODE tester +i") (0. ":irc.foonet.org 221 tester +Zi") (0. ":irc.foonet.org 306 tester :You have been marked as being away") (0 ":tester!~u@HIDDEN JOIN #chan") diff --git a/test/lisp/erc/resources/erc-d/resources/linger.eld b/test/lisp/erc/resources/erc-d/resources/linger.eld index 36c81a3af4b..e456370a800 100644 --- a/test/lisp/erc/resources/erc-d/resources/linger.eld +++ b/test/lisp/erc/resources/erc-d/resources/linger.eld @@ -20,14 +20,14 @@ (0 ":irc.example.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.example.org 422 tester :MOTD File is missing")) -((mode-user 1.2 "MODE tester +i") +((mode-user 2 "MODE tester +i") (0 ":irc.example.org 221 tester +Zi") (0 ":irc.example.org 306 tester :You have been marked as being away") (0 ":tester!~tester@localhost JOIN #chan") (0 ":irc.example.org 353 alice = #chan :+alice!~alice@HIDDEN @%+bob!~bob@HIDDEN") (0 ":irc.example.org 366 alice #chan :End of NAMES list")) -((mode-chan 1.2 "MODE #chan") +((mode-chan 2 "MODE #chan") (0 ":bob!~bob@HIDDEN PRIVMSG #chan :hey")) ((linger 1.0 LINGER)) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Add-optional-timezone-param-to-erc-echo-timestam.patch From 9a5b2bd7e9ce32bafbb3f204cc1b4a7d5069e9e5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 30 Aug 2023 23:15:22 -0700 Subject: [PATCH 2/2] [5.6] Add optional timezone param to erc-echo-timestamp * etc/ERC-NEWS: Mention option `erc-echo-timestamp-zone'. * lisp/erc/erc-stamp.el (erc-echo-timestamps): Mention that some finagling is required if enabling this option after activating the module. (erc-echo-timestamp-format): Add additional Custom choice constants. (erc-echo-timestamp-zone): New option to specify timezone for option `erc-echo-timestamps' and function `erc-echo-timestamp'. (erc-stamp-mode, erc-stamp-enable, erc-stamp-disable): Call `erc-stamp--setup' instead of `erc-munge-invisibility-spec'. (erc-munge-invisibility-spec): Perform teardown when boolean flag options, like `erc-timestamp-intangible' and `erc-echo-timestamps' are nil. (erc-stamp--setup): Call `erc-munge-invisibility-spec). (erc-stamp--last-stamp, erc-stamp--on-clear-message): New function and helper state variable to tell Emacs not to clear the current timestamp message when navigating within the same IRC message. (erc-echo-timestamp): Add optional `zone' parameter, to be passed directly to `format-time-string', when non-interactive, and massaged sensibly otherwise. Set the local variable `erc-stamp--last-stamp'. * test/lisp/erc/erc-stamp-tests.el (erc-echo-timestamp): New test. (Bug#60936) --- etc/ERC-NEWS | 13 +++-- lisp/erc/erc-stamp.el | 83 ++++++++++++++++++++++++++------ test/lisp/erc/erc-stamp-tests.el | 30 ++++++++++++ 3 files changed, 107 insertions(+), 19 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 7ee55982b17..69088732c0d 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -203,11 +203,18 @@ continued integration. With the existing design, merely loading the library 'erc-log' caused 'truncate' to start writing logs, possibly against a user's wishes. +** The function 'erc-echo-timestamp' is now a command. +The option 'erc-echo-timestamps' (plural) enables the contextual +echoing of timestamps to the echo area when moving between messages in +an ERC buffer. This functionality is now available on demand by +invoking the newly interactive function 'erc-echo-timestamp' atop any +message. And the new companion option 'erc-echo-timestamp-zone' +determines the default timezone when not specified with a prefix +argument. + ** Miscellaneous UX changes. Some minor quality-of-life niceties have finally made their way to -ERC. For example, the function 'erc-echo-timestamp' is now -interactive and can be invoked on any message to view its timestamp in -the echo area. Fool visibility has become togglable with the new +ERC. For example, fool visibility has become togglable with the new command 'erc-match-toggle-hidden-fools'. The 'button' module's 'erc-button-previous' now moves to the beginning instead of the end of buttons. A new command, 'erc-news', can be invoked to visit this very diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index a021cd26607..be12d6080d2 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -136,14 +136,27 @@ erc-echo-timestamps "If non-nil, print timestamp in the minibuffer when point is moved. Using this variable, you can turn off normal timestamping, and simply move point to an irc message to see its timestamp -printed in the minibuffer." +printed in the minibuffer. When attempting to enable this option +after `erc-stamp-mode' is already active, you may need to run the +command `erc-show-timestamps', `erc-hide-timestamps', or similar +in the appropriate ERC buffer." :type 'boolean) (defcustom erc-echo-timestamp-format "Timestamped %A, %H:%M:%S" "Format string to be used when `erc-echo-timestamps' is non-nil. This string specifies the format of the timestamp being echoed in the minibuffer." - :type 'string) + :type '(choice (const "Timestamped %A, %H:%M:%S") + (const "%Y-%m-%d %H:%M:%S %Z") + string)) + +(defcustom erc-echo-timestamp-zone nil + "Default timezone for the option `erc-echo-timestamps'. +Also affects the command `erc-echo-timestamp' (singular). See +the ZONE parameter of `format-time-string' for a description of +acceptable value types." + :type '(choice boolean number (const wall) (list number string)) + :package-version '(ERC . "5.6")) ; FIXME sync on release (defcustom erc-timestamp-intangible nil "Whether the timestamps should be intangible, i.e. prevent the point @@ -167,14 +180,16 @@ stamp (add-hook 'erc-send-modify-hook #'erc-add-timestamp 60) (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) (add-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear) - (unless erc--updating-modules-p - (erc-buffer-do #'erc-munge-invisibility-spec))) + (unless erc--updating-modules-p (erc-buffer-do #'erc-stamp--setup))) ((remove-hook 'erc-mode-hook #'erc-munge-invisibility-spec) (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp) (remove-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) (remove-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear) (erc-with-all-buffers-of-server nil nil + (let (erc-echo-timestamps erc-hide-timestamps erc-timestamp-intangible) + (erc-stamp--setup)) + (kill-local-variable 'erc-stamp--last-stamp) (kill-local-variable 'erc-timestamp-last-inserted) (kill-local-variable 'erc-timestamp-last-inserted-left) (kill-local-variable 'erc-timestamp-last-inserted-right)))) @@ -640,14 +655,31 @@ erc-format-timestamp ;; please modify this function and move it to a more appropriate ;; location. (defun erc-munge-invisibility-spec () - (and erc-timestamp-intangible (not (bound-and-true-p cursor-intangible-mode)) - (cursor-intangible-mode 1)) - (and erc-echo-timestamps (not (bound-and-true-p cursor-sensor-mode)) - (cursor-sensor-mode 1)) + (if erc-timestamp-intangible + (cursor-intangible-mode +1) ; idempotent + (when (bound-and-true-p cursor-intangible-mode) + (cursor-intangible-mode -1))) + (if erc-echo-timestamps + (progn + (cursor-sensor-mode +1) ; idempotent + (when (<= 29 emacs-major-version) + (add-function :before-until (local 'clear-message-function) + #'erc-stamp--on-clear-message))) + (when (bound-and-true-p cursor-sensor-mode) + (cursor-sensor-mode -1)) + (remove-function (local 'clear-message-function) + #'erc-stamp--on-clear-message)) (if erc-hide-timestamps (add-to-invisibility-spec 'timestamp) (remove-from-invisibility-spec 'timestamp))) +(defun erc-stamp--setup () + "Enable or disable buffer-local `erc-stamp-mode' modifications." + (if erc-stamp-mode + (erc-munge-invisibility-spec) + (let (erc-echo-timestamps erc-hide-timestamps erc-timestamp-intangible) + (erc-munge-invisibility-spec)))) + (defun erc-hide-timestamps () "Hide timestamp information from display." (interactive) @@ -677,14 +709,33 @@ erc-toggle-timestamps (erc-munge-invisibility-spec))) (erc-buffer-list))) -(defun erc-echo-timestamp (dir stamp) - "Print timestamp text-property of an IRC message." - ;; Could also pass an &optional `zone' arg to `format-time-string'. - (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) - (when (eq 'entered dir) - (when stamp - (message "%s" (format-time-string erc-echo-timestamp-format - stamp))))) +(defvar-local erc-stamp--last-stamp nil) + +(defun erc-stamp--on-clear-message (&rest _) + "Return `dont-clear-message' when operating inside the same stamp." + (and erc-stamp--last-stamp erc-echo-timestamps + (eq (get-text-property (point) 'erc-timestamp) erc-stamp--last-stamp) + 'dont-clear-message)) + +(defun erc-echo-timestamp (dir stamp &optional zone) + "Display timestamp of message at point in echo area. +Interactively, interpret a numeric prefix as a ZONE offset in +hours (or seconds, if its abs value is larger than 14), and +interpret a \"raw\" prefix as UTC. To specify a zone for use +with the option `erc-echo-timestamps', see the companion option +`erc-echo-timestamp-zone'." + (interactive (list nil (get-text-property (point) 'erc-timestamp) + (pcase current-prefix-arg + ((and (pred numberp) v) + (if (<= (abs v) 14) (* v 3600) v)) + (`(,_) t)))) + (if (and stamp (or (null dir) (and erc-echo-timestamps (eq 'entered dir)))) + (progn + (setq erc-stamp--last-stamp stamp) + (message (format-time-string erc-echo-timestamp-format + stamp (or zone erc-echo-timestamp-zone)))) + (when (and erc-echo-timestamps (eq 'left dir)) + (setq erc-stamp--last-stamp nil)))) (defun erc--echo-ts-csf (_window _before dir) (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index c448416cd69..b00aa6dcabf 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -274,4 +274,34 @@ erc-timestamp-intangible--left (when noninteractive (kill-buffer))))) +(ert-deftest erc-echo-timestamp () + (should-not erc-echo-timestamps) + (should-not erc-stamp--last-stamp) + (insert (propertize "abc" 'erc-timestamp 433483200)) + (goto-char (point-min)) + (let ((inhibit-message t) + (erc-echo-timestamp-format "%Y-%m-%d %H:%M:%S %Z") + (erc-echo-timestamp-zone (list (* 60 60 -4) "EDT"))) + + ;; No-op when non-interactive and option is nil + (should-not (erc--echo-ts-csf nil nil 'entered)) + (should-not erc-stamp--last-stamp) + + ;; Non-interactive (cursor sensor function) + (let ((erc-echo-timestamps t)) + (should (equal (erc--echo-ts-csf nil nil 'entered) + "1983-09-27 00:00:00 EDT"))) + (should (= 433483200 erc-stamp--last-stamp)) + + ;; Interactive + (should (equal (call-interactively #'erc-echo-timestamp) + "1983-09-27 00:00:00 EDT")) + ;; Interactive with zone + (let ((current-prefix-arg '(4))) + (should (equal (call-interactively #'erc-echo-timestamp) + "1983-09-27 04:00:00 GMT"))) + (let ((current-prefix-arg -7)) + (should (equal (call-interactively #'erc-echo-timestamp) + "1983-09-26 21:00:00 -07"))))) + ;;; erc-stamp-tests.el ends here -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 16 Aug 2023 17:39:08 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Aug 16 13:39:08 2023 Received: from localhost ([127.0.0.1]:42024 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qWKU7-0000Ly-Qu for submit <at> debbugs.gnu.org; Wed, 16 Aug 2023 13:39:08 -0400 Received: from mout.gmx.net ([212.227.17.21]:35165) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <michael.albinus@HIDDEN>) id 1qWKU5-0000LS-Tr for 60936 <at> debbugs.gnu.org; Wed, 16 Aug 2023 13:39:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.de; s=s31663417; t=1692207531; x=1692812331; i=michael.albinus@HIDDEN; bh=qhF54qAewlLEiLqgrafrtZFHV1tLdg+Qz7QcoukVeIA=; h=X-UI-Sender-Class:From:To:Cc:Subject:In-Reply-To:References:Date; b=PSxfl/i0ZPEO2h/hc0dJbhFLLQ2D1rDL1NVmvr9FMZ+XXL8yY2V1vMlvSBDawPVRWbfNTK/ MIYlrHigyUZa7wKRkz9sidsDITBV6AsepWnRJYrVbKS+UHlXwGVe3ioHbGqLQfpxmk/V0C+GJ 4JMDbNRjJFAsPZUk43d7QP6n6Ys6om8j9AwZv/wK05bF/Y40ewbFjAvlaozR64DvPlH1lhRuq PiFfUoXnsj43sdKCKnHwruFI7cl8kkEXebJGRM82W1uEH0vSLXtxTimbxR+fkr5/fAt42Dtzk AYIDqd2iK1EMFGezPwVuz4KLA3k27Auvebbf+lyXnnnqrV17GoWg== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from gandalf.gmx.de ([185.89.39.27]) by mail.gmx.net (mrgmx104 [212.227.17.168]) with ESMTPSA (Nemesis) id 1Mg6Zq-1pq8NJ2Qww-00hbba; Wed, 16 Aug 2023 19:38:51 +0200 From: Michael Albinus <michael.albinus@HIDDEN> To: "J.P." <jp@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87msyrcb91.fsf@HIDDEN> (J. P.'s message of "Wed, 16 Aug 2023 07:28:26 -0700") References: <87tu0nao77.fsf@HIDDEN> <87edkcmflq.fsf__21602.8587006562$1691592938$gmane$org@HIDDEN> <87jzu4upl9.fsf@HIDDEN> <87v8dgh0af.fsf@HIDDEN> <87sf8kuvxr.fsf@HIDDEN> <87leecuuqu.fsf@HIDDEN> <87msyrcb91.fsf@HIDDEN> Date: Wed, 16 Aug 2023 19:38:51 +0200 Message-ID: <87r0o251lg.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Provags-ID: V03:K1:SDnR/Td/arCud0F5QWW+dfjh2443aB0BfXtmZ9fKALurSnoR4lz gtvmgD5pMlFfKSscz5V1VbJnSjI4hIGfMjsarm//7WeM/XM24TPL6mvzuqU0EHvXCmZH2RE cjipQrfV3JFQ6Zy+k2V9PFTpoaHPnOTJuJ2FgH1C0areH/nUixQxB7xfYhiAie9HI9Zm3xy o5Tn/mbJraPm07z3ao/fA== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:tsZjAe25/rA=;xJFlGH2e9yF1r85YhZZY0hAe4Fo 8y9NZkVX+l05uG2NlNdtZR36YNs5q82dkd546gvjpJGDxvtRQJoZY9Qd8OShl6wuWJQ/uPgCt uQNV+Y4LDKQljQtAtQTHUcHXJAS+eGMN8e+McGaAf+7Lo3IlnwYZpZrHf7rFcsmtSK3/TB8Z/ bPdQ5IPp8aCiJAotxXeRGSJluB4QjN5V6522qT+5NVCTYVwBnPlCLDcBJG2dzBVTNMfjht2wt H1hidsM18j+sm8lWrb12EzJjnPqliKmWFrAtBUOk4K4erbbj+lvV8+zoUcsJbb+2TwFEozoWB 7HylQ770l1xe2rFdikSnaCnP+DTI6cDYdxVDyDcVoUXxl4+zPcKnoYSZS3VPHZfxqZUeHiGcG YY0VwQqWu2hzTASeBPQ4wjlnKmSbZbT2SmUIj+Xu+WDNleU73tVN64ju1Ac7q1W3tnnoYqmlp rmVftcUhm+eocSpedQyfxalAjohNLpe2pEEBgAwU3ObGCdWlukoWC3jIOf0ISSg7RPxtG6Ktl hfuBpB+yoAe+QEaMZkdCbmLO2ByjVMvAWHNa6/0ctB45hCa+t5fbM61qJFg6g9qW5C/SaGp56 gXpkI94ch1u9sQd7elRBand3FAG3ggW9qvWTjjYUT7zf9c1fJ30LWAKIGS9ix3WApQ8wwqvxZ zt7fcDfpGaEKPFPKJS5OymRZbXoMrmi8oSpZ+/QlMyrJ7n0MsraukhhWVJarAxCip/fPcS/g1 dOkLfItAcOohRMG3qB/FZyR1IGuAVQQ56f059e/rmnp2K+ZG/0yfweRQG+yyBB32T2cv2UFJR wBq8y5vfm83cSoptr5YOHXaBJcO+eDsgdF5misHSEKoWWRL2PpD4maWf+MvlLnHFaVkhL6MQz 4a4mESRyVXV2uSi4z+VyHk1n4a69WkwvYG+i7MNNpVCChnzKrGgUEgSgQ08s/j9SLLZ+WgNHN KLtzxTRh5wqXN1lQDYWNu5U+rls= X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.7 (-) "J.P." <jp@HIDDEN> writes: Hi, > It's the second bullet I was referring to initially, which allows > external Prometheus instances to poll the /-/metrics endpoint if > exposed. But to be of any use, those instances would need their IP > addresses whitelisted. Additionally, we'd need a "node exporter" [3] > process running on the same host to provide intel on system-resource > consumption. In the end, this is probably too involved to be worth > anyone's while. So, I guess you can probably just revert whatever change > you made to the configuration. Thanks anyway and please pardon the > distraction. No problem. I've disabled it on emba. Best regards, Michael.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 16 Aug 2023 14:28:39 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Aug 16 10:28:39 2023 Received: from localhost ([127.0.0.1]:41790 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qWHVm-0004JT-Lv for submit <at> debbugs.gnu.org; Wed, 16 Aug 2023 10:28:39 -0400 Received: from mail-108-mta86.mxroute.com ([136.175.108.86]:34383) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qWHVj-0004JH-7U for 60936 <at> debbugs.gnu.org; Wed, 16 Aug 2023 10:28:36 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta86.mxroute.com (ZoneMTA) with ESMTPSA id 189febf7cf5000d7b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 16 Aug 2023 14:28:29 +0000 X-Zone-Loop: a8ea7983d49d7a49c4db9972e68483e404d334ab02d8 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=38dGZHBHSag3G3UmMI99vN/mzyzBvINNk5o5DKN59L0=; b=FKjGoGQNthb3wARwn8fEZTZO4E cVJbW2tdTVV137xXIrz0lNPCJQa5wROPPjdVNtTrJc0pOUZrAN8fPMinmE/5NEoyRgU2cp6rE8+Pn +9e176QpfSPx4Blr1nA6d+fgUZHdrhXClCXh315Qdf8KvADsPrDd2gmaABMTk1xsiNabJc/vMPMlB SeBBdUJluh/cyvex6pRvk6F0DXMvBeaMMENDIGi4RX7zXAk7edGHsBrFUbmzD5g51oSrP46SMqYLV mtKFlSezQ9KpFis6zlqG/I8hyx2+nMzOPm/K1rJOTjVVIklYsl3Vpero0j/OYztL6D8ceE/C/YD/q IJchsoJQ==; From: "J.P." <jp@HIDDEN> To: Michael Albinus <michael.albinus@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87leecuuqu.fsf@HIDDEN> (Michael Albinus's message of "Tue, 15 Aug 2023 18:37:45 +0200") References: <87tu0nao77.fsf@HIDDEN> <87edkcmflq.fsf__21602.8587006562$1691592938$gmane$org@HIDDEN> <87jzu4upl9.fsf@HIDDEN> <87v8dgh0af.fsf@HIDDEN> <87sf8kuvxr.fsf@HIDDEN> <87leecuuqu.fsf@HIDDEN> Date: Wed, 16 Aug 2023 07:28:26 -0700 Message-ID: <87msyrcb91.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) Michael Albinus <michael.albinus@HIDDEN> writes: > Michael Albinus <michael.albinus@HIDDEN> writes: > >> I've enabled the /metrics endpoint on emba. This requires a restart of >> gitlab, which I haven't done. Should happen next time, when gitlab >> patches are installed (which is not my responsibility). > > Hmm. I've just read <https://docs.gitlab.com/ee/operations/>. It tells us > > Measure reliability and stability with metrics (removed) > > This feature was deprecated in GitLab 14.7 and removed in 16.0. > > So it might work ATM (we're using GitLab CE 13.12.15), but it might > disappear in the future. Hi Michael. This deprecation notice appears to be about GitLab's metrics feature, which they describe as a managed Prometheus instance and integrated dashboard solution for their enterprise product. Apparently, they're replacing that with a full observability offering. In case you're curious, they also say [1]: This deprecation does not include: - Deprecating alerts for Prometheus - Capabilities that GitLab comes with that allow operators of GitLab to retrieve metrics from those instances [2] It's the second bullet I was referring to initially, which allows external Prometheus instances to poll the /-/metrics endpoint if exposed. But to be of any use, those instances would need their IP addresses whitelisted. Additionally, we'd need a "node exporter" [3] process running on the same host to provide intel on system-resource consumption. In the end, this is probably too involved to be worth anyone's while. So, I guess you can probably just revert whatever change you made to the configuration. Thanks anyway and please pardon the distraction. [1] https://gitlab.com/gitlab-org/gitlab/-/issues/346541 [2] https://docs.gitlab.com/ee/administration/monitoring/prometheus/gitlab_metrics.html [3] https://prometheus.io/docs/guides/node-exporter/
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 15 Aug 2023 16:38:05 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Aug 15 12:38:05 2023 Received: from localhost ([127.0.0.1]:36569 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qVx3V-0002WN-CO for submit <at> debbugs.gnu.org; Tue, 15 Aug 2023 12:38:05 -0400 Received: from mout.gmx.net ([212.227.15.18]:42393) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <michael.albinus@HIDDEN>) id 1qVx3T-0002Vq-7b for 60936 <at> debbugs.gnu.org; Tue, 15 Aug 2023 12:38:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.de; s=s31663417; t=1692117467; x=1692722267; i=michael.albinus@HIDDEN; bh=beZvADyfFzApnbfa2CxNhJmJfxnpbF2i45Q9rkvVz44=; h=X-UI-Sender-Class:From:To:Cc:Subject:In-Reply-To:References:Date; b=DQKrtg/3tmhjsLrquFe2WxOYd6USfPWDMi84/pBd8XSSMNZ7tmh1QXbRU4VpDYtTccYnlOQ ID38QHIP18eGqxdzRFiN4gm3fOUjKaOwfEfwzkXOeUf+bIhinOUBmsoLwYfwx3xLNBAjCfn+v T+Jc1YdLTrC08cEba+nbdXdgutyoTRgOTmJqDutdGLeqoQ+3G2KBhRyDJa64JIygv6uQF8LSz sWxPmmMlSO3HD7pI07mt5OO9gpHnBbJGl4uZnu0wVVD/2qfuyFJ86p63OEhx2RW0WAdz4/3Lv CQqCvl0m1Zegzb2x/adejcbszWECeJVwRcPCOG2MEwy2vZdZ2dWQ== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from gandalf.gmx.de ([185.89.39.27]) by mail.gmx.net (mrgmx005 [212.227.17.190]) with ESMTPSA (Nemesis) id 1N8GQs-1pjT4M308O-014DHo; Tue, 15 Aug 2023 18:37:46 +0200 From: Michael Albinus <michael.albinus@HIDDEN> To: "J.P." <jp@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87sf8kuvxr.fsf@HIDDEN> (Michael Albinus's message of "Tue, 15 Aug 2023 18:12:00 +0200") References: <87tu0nao77.fsf@HIDDEN> <87edkcmflq.fsf__21602.8587006562$1691592938$gmane$org@HIDDEN> <87jzu4upl9.fsf@HIDDEN> <87v8dgh0af.fsf@HIDDEN> <87sf8kuvxr.fsf@HIDDEN> Date: Tue, 15 Aug 2023 18:37:45 +0200 Message-ID: <87leecuuqu.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Provags-ID: V03:K1:vhdsJ9oP/FTxaHxuGyUSgrKZo1GD7UJr549nMrg/0vJDclVrMH2 UGGe7RV57q8CVVBEcnNz4O/+aryiUXKmapllBkrLE1+bFeYmlrBvIZIz7kr/+ECVbtshMuf usb50X6TP4SORardqj2OVeJhW73P9YRjPBUClJTyAxB3ZzchpPASY5A8XJnj3bN1U/YtT4M EI6KXwKSp/ImriD5b8JgQ== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:clST6d5p5Ck=;wTDEQUY9Y5Tllyoj8GAn2Qy5Kp9 /rFEv8ipX350q7JEhlzPqXu8CCM8fitmROe0hllquaVfBKT+bIO4aUsinRfm5l7xLiHSDqGNy yDBbkNY/DWkNQOv/k2aJ6JqU7TiK5XagAaoTLZxc4cQy2JsSb40z10KvDs2Wq3mHCMu4LmDPE oCa4K4Ap0GZuk+knfhAvqzKq9QBKSbn64Pt0d3IUGxiqkTA7eifdffvUk3vq/4xHf3q72qhKU 9dFz3PFfH17OXkZwK8GZDAwVqdkl+GfA+OnBmej+O8GaAnb1lDjyfyQiKKy/e5sx2gJODbMH2 a8hZOS6UgM0JYgEN34PwGBE6xu0Zq6V0ltDb65R05xEEs7L4FKjX91x879zKaNCc7oR2PFBXM +khfKmv6iRmL9XeVuBFxTjLN0FIEjYrEdMbM8+iBFwyJOPJgasir64/Ql+b82jP+hUQFTCpjK nmvRP+NFR8PgdHM+Pyu0Bs2w6lLrmUzG5L2JkeyO2GvbbE7kwaYy+M5MvqEPiLnLo//A/6z1Z aXm6XqeY46tZIV8359K7Wcrz5BKdctA5wBlJ10qC0HZ83KpYKWQ57XKuICmnfdXmg1v3Gcl1y CwTqD1NiWjfKmTI/V3u+1lFwrcxCZDAkcHGljLKbSBBQYbXx1keKNtJdvAaVyJQVj5+bTtuPp kCJuUkp80puR1efQw/m+r4wVSoqfWW+7sT7JczfqR3rjHKNGYqdAgKUh8B08eV58TjH6XR1oB EsSC0wf59pMt3cRHxsujZrWWZfMi/Sm1lL1ruhCjSPr5Myw+2ZYut+GRC0Vnic7QGf/cxQu6N kI/KVk11mxyRlI4jLU+NYC9sCuEmbtu6uBPzOKR8LzAgp+YdffJXnOBmNkCdWNqvX1e/DQWAP qyEbGFhr3z5hbCpJH8DnoqL0oPXNhgw4TwaUg/AaZClFT416AT1cTPJphXyb79ogAcOY6I0ND ciaKt1bBKnMNorXcyYHSEjRXXuo= X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.7 (-) Michael Albinus <michael.albinus@HIDDEN> writes: Hi, >> BTW, does EMBA expose any public /metrics endpoints? I ask because >> perhaps investigating possible relationships between intermittent >> EMBA-only job failures and something like node-exporter signals [1] >> might prove fruitful. Just a thought. >> >> [1] https://docs.gitlab.com/ee/administration/monitoring/prometheus/index.html#prometheus-as-a-grafana-data-source > > I've enabled the /metrics endpoint on emba. This requires a restart of > gitlab, which I haven't done. Should happen next time, when gitlab > patches are installed (which is not my responsibility). Hmm. I've just read <https://docs.gitlab.com/ee/operations/>. It tells us --8<---------------cut here---------------start------------->8--- Measure reliability and stability with metrics (removed) This feature was deprecated in GitLab 14.7 and removed in 16.0. --8<---------------cut here---------------end--------------->8--- So it might work ATM (we're using GitLab CE 13.12.15), but it might disappear in the future. Best regards, Michael.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 15 Aug 2023 16:12:31 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Aug 15 12:12:31 2023 Received: from localhost ([127.0.0.1]:36544 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qVwek-0001uN-Bl for submit <at> debbugs.gnu.org; Tue, 15 Aug 2023 12:12:31 -0400 Received: from mout.gmx.net ([212.227.17.21]:45343) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <michael.albinus@HIDDEN>) id 1qVwed-0001u4-Pb for 60936 <at> debbugs.gnu.org; Tue, 15 Aug 2023 12:12:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.de; s=s31663417; t=1692115921; x=1692720721; i=michael.albinus@HIDDEN; bh=07zakHqpUMh48DdY6knJgkHVOCie198EMA9CFrk1myQ=; h=X-UI-Sender-Class:From:To:Cc:Subject:In-Reply-To:References:Date; b=mJlylt6cFFmZEbbY2n9arvuE/96T0dHR3IIM8GYHRNtDpXi+5pNc6rx7oP0ziD2VhmAuz8T tmmpXfxAN2FqK0p0XodurP411TMYhPEHNuUuj/HtwP/doVIB3ag7GIFGpQbiaJqGss9tlQ33r EZHIJtNSWdayC4D2jXrVgxBcY0xRgk2qVbTwUaaBfKcaZ8oJsVTZccln4wB0Xi7/Duh7OdjyO fqA94dgtLefz9+aado79ocZ3rp8E0DvodxwBd7iljx1+VqgWGpgnQEfu/KltE2CKXLhTTcWa8 y1pIluTF5iilIil2ajWWRSw0xUGihMQbRqr4o/X/9nOkNjcFhbMw== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from gandalf.gmx.de ([185.89.39.27]) by mail.gmx.net (mrgmx104 [212.227.17.168]) with ESMTPSA (Nemesis) id 1M2wGi-1qUrFt1Qdw-003Iib; Tue, 15 Aug 2023 18:12:01 +0200 From: Michael Albinus <michael.albinus@HIDDEN> To: "J.P." <jp@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87v8dgh0af.fsf@HIDDEN> (J. P.'s message of "Tue, 15 Aug 2023 07:01:44 -0700") References: <87tu0nao77.fsf@HIDDEN> <87edkcmflq.fsf__21602.8587006562$1691592938$gmane$org@HIDDEN> <87jzu4upl9.fsf@HIDDEN> <87v8dgh0af.fsf@HIDDEN> Date: Tue, 15 Aug 2023 18:12:00 +0200 Message-ID: <87sf8kuvxr.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Provags-ID: V03:K1:M7FJuDfrnSZSeA8X77B2H0O35NxMNpYFrB5D+AYoS+g0NNW8NsL N64EhhOExD6mymUYUxl6NtbnSCs+bugDTvPJxCvIeTtRW1U2/9KkS7wQpTANBsBfAMiZLh2 WG12Kywy85X/KLuuY84bCFIavBf1DsGzqmJhcwj2JRtKghm1td1eIUjuDVfbQWluxQa2hcz dUyZI7J2oUveCzQaB3I5A== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:i3IcT8ovel0=;WaxfDvhwRvW7Gaq86F4msUqIvtj J+cyeoYrMuOWEmzTPsu07GSS2brzE2D4d0ehZFiF3Z85mf8VXLCzXs4tIG2zy67Z1ErKZOrjO kbgmKRZHXoVIXT1RG0fSGnHZKy9O0VFmdc4ehv1562teEABXj5Qm4k8C8lHjNctGcUghSnfNI iWlfCV2kugUOIDzUzUNlFsMKNhZl1zLvn01VsXlM+Zo9U7AUlld/ICLV5e1zDo1pAtg9L8R7K TubKe3bG8duBDn82aYjYHdS5DWn+q5jukjhVw1sQt1AnKiPH1XBWvUggcxdY8m3neYNcgrNKK nzn4HP9k0Hk4dfPj6Hd9Yp4YSjc+sW0bKn1vRSh4zduDG15b+4xe1G/1Y8Nfr1URTlm5P6oVc ogNSyzFB4OYKFZvgYcChWY/DF0R2YC+qAcqWAxUx3/dR0Kw6KMJ5RgPTih3LgivlJl254fm0N Q0Fl4m7TjpeJdJ3qDFnhTRe995EvM2kT1eYBWTOxC8gFYvDj0fshevMJX/qejZpoppmcfZi6u iEr/H3dxG9YaN+DLWeVw9p/YCwemmgMK6WAPCwNvC4vFaeIOF+g63sZaAKMnh2fk7FN7rrg5V dkq/aLxV2o2zCia7+AQyi7EcPMmGx38vr8X7f51nxuH9UvVamnff+wQYJ/JZEx74N/oLOCnlM 4VrcofRMeNmrnmq8NY5Dqb+wa24Fh1X6O0Rldsq2xwWjyzsfZ6YjhRhaROBNjGqwZ4ZH6GILT Q8d1FKS9wHkxnRs0fZAY9++FIMRae0qnWTHhFKSz31TrGaal0hwCURMXAfEhcBxYTboA+XGbh YYZPCWJkwqeOt4qzQ0KJt1zAKA3oZwGViPZlhZWzsATeCg3h0cfu6ER5dzsjYuO9rJxdGLqdS f61BS09Be2UeixNQANkig3dwoI7v4OadkgDQnb2IRWwyZxUerTvNYTP2dyfpfCAOgTJeFNZas NktA5P546II10b1PYvZDeT0Ufjc= X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.7 (-) "J.P." <jp@HIDDEN> writes: Hi, > Thanks Michael. I guess checking for > > (equal (get-env "CI_JOB_STAGE") "native-comp") > > might also help unless that's inadvisable for some reason (though I'm > still hoping it doesn't come to this). Should be OK. If you use `getenv'. > And not that you should care, but I've been waiting for > > bug#65176: ~25 test failures from make check in the latest master > > to wrap up before installing this or similar. This bug has been closed yesterday. > BTW, does EMBA expose any public /metrics endpoints? I ask because > perhaps investigating possible relationships between intermittent > EMBA-only job failures and something like node-exporter signals [1] > might prove fruitful. Just a thought. > > [1] https://docs.gitlab.com/ee/administration/monitoring/prometheus/index.html#prometheus-as-a-grafana-data-source I've enabled the /metrics endpoint on emba. This requires a restart of gitlab, which I haven't done. Should happen next time, when gitlab patches are installed (which is not my responsibility). Best regards, Michael.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 15 Aug 2023 14:01:58 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Aug 15 10:01:57 2023 Received: from localhost ([127.0.0.1]:36387 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qVucP-0006r9-Ix for submit <at> debbugs.gnu.org; Tue, 15 Aug 2023 10:01:57 -0400 Received: from mail-108-mta220.mxroute.com ([136.175.108.220]:46159) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qVucL-0006qy-Ce for 60936 <at> debbugs.gnu.org; Tue, 15 Aug 2023 10:01:57 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta220.mxroute.com (ZoneMTA) with ESMTPSA id 189f980b0df00023b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Tue, 15 Aug 2023 14:01:47 +0000 X-Zone-Loop: b2ed370aadfa99263c9c979e98bd6efeb6ad397acce1 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=jV3DymtLK0Opf6oodR+2HrUcsuWmOPhzmU2JeCuEMqQ=; b=lSe7vyOISa0oobGq5YQ7lxLMwN OXfrmdILdD6kYL7XY32TOlsPEfbun/YP/lyGbLPF+fOtNYlMRMULUP+Co2xAH3gNS1rzEfXmyP86a SwPKA3Bb8uXmVjqUk1WvtnRCHriTWkJZ8rl4iwGR6STiK2TiT/rGeEG4wIxQE04GS7QZk2JAE5oc4 BXwcF/3/pUW9S2b7AqrhsIssrNHHwsmidfOUZ8N2pv4qwcetNayXmfCVLTJRNxOKZmHV0qFwIk0q+ ourhxJilAMt0ihAkEP69b+1cBP/2sPVrUavM9uFU3HlXHpH2I3GWoVRwP7cKqT4nB1IGst8QrDZ53 aNCKhsrQ==; From: "J.P." <jp@HIDDEN> To: Michael Albinus <michael.albinus@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87jzu4upl9.fsf@HIDDEN> (Michael Albinus's message of "Wed, 09 Aug 2023 18:50:58 +0200") References: <87tu0nao77.fsf@HIDDEN> <87edkcmflq.fsf__21602.8587006562$1691592938$gmane$org@HIDDEN> <87jzu4upl9.fsf@HIDDEN> Date: Tue, 15 Aug 2023 07:01:44 -0700 Message-ID: <87v8dgh0af.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) Michael Albinus <michael.albinus@HIDDEN> writes: > "J.P." <jp@HIDDEN> writes: > > Hi, > >> There have been three failures (all on native-comp-speed2-master) over >> the last three weeks pointing to these tests, which haven't changed in >> the year-plus they've existed in tree. No test appears in multiple >> failures, and all continue to pass daily on commercial GitLab (GCP) >> runners using the same EMBA container image. They also pass locally >> with "make check" and "make -j -C test SELECTOR=t check-lisp-erc". If >> these tweaks don't fix the problem, they can be branded :unstable. > > If the problem happens only on emba, you can skip the tests with > > :tags (if (getenv "EMACS_EMBA_CI") > '(:expensive-test :unstable) > '(:expensive-test)) > > Best regards, Michael. Thanks Michael. I guess checking for (equal (get-env "CI_JOB_STAGE") "native-comp") might also help unless that's inadvisable for some reason (though I'm still hoping it doesn't come to this). And not that you should care, but I've been waiting for bug#65176: ~25 test failures from make check in the latest master to wrap up before installing this or similar. BTW, does EMBA expose any public /metrics endpoints? I ask because perhaps investigating possible relationships between intermittent EMBA-only job failures and something like node-exporter signals [1] might prove fruitful. Just a thought. [1] https://docs.gitlab.com/ee/administration/monitoring/prometheus/index.html#prometheus-as-a-grafana-data-source
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 9 Aug 2023 16:51:20 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Aug 09 12:51:20 2023 Received: from localhost ([127.0.0.1]:40431 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qTmP2-0005Vu-9O for submit <at> debbugs.gnu.org; Wed, 09 Aug 2023 12:51:20 -0400 Received: from mout.gmx.net ([212.227.15.18]:39017) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <michael.albinus@HIDDEN>) id 1qTmP0-0005Vf-4a for 60936 <at> debbugs.gnu.org; Wed, 09 Aug 2023 12:51:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.de; s=s31663417; t=1691599859; x=1692204659; i=michael.albinus@HIDDEN; bh=rUcgkklABTCVyG9U25YwKxiE9TqTGzI+7F29Tbvpa+o=; h=X-UI-Sender-Class:From:To:Cc:Subject:In-Reply-To:References:Date; b=Uy8oETKtdVxDh/BSey4AOeu3c4PjhQjCJMp8blXN7DPu4KnIZDDtrzyuyenMKseyJUSjwt7 +UBuEf457SmwZlFZ2At4LGZLyPqGz+PvwW7lJQO0jofAi+9mkG5w7M+4RERFNpl6ndpKJqmrh 4MdlbnE03PsJ/OZrS7E7avmjactBgUSqANxHhvd7nAhI5WYvEm6h7SvQtDhjizJorBab2YBj7 qVazWwpkpWcjUrlHEZS/PDAxTAriZLhcpjOYIYYc2lp8hQFDLsgkC+a204nMjwTQTgfLoOq/L vvp5Roh7PqDf/12ClWmPoBOrqT6LbISxlK5ofW+5pyvxkwA2RmlQ== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from gandalf.gmx.de ([185.89.39.27]) by mail.gmx.net (mrgmx004 [212.227.17.190]) with ESMTPSA (Nemesis) id 1MMXUD-1qCO6W1ttX-00JdNz; Wed, 09 Aug 2023 18:50:59 +0200 From: Michael Albinus <michael.albinus@HIDDEN> To: "J.P." <jp@HIDDEN> Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87edkcmflq.fsf__21602.8587006562$1691592938$gmane$org@HIDDEN> (J. P.'s message of "Wed, 09 Aug 2023 07:53:53 -0700") References: <87tu0nao77.fsf@HIDDEN> <87edkcmflq.fsf__21602.8587006562$1691592938$gmane$org@HIDDEN> Date: Wed, 09 Aug 2023 18:50:58 +0200 Message-ID: <87jzu4upl9.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Provags-ID: V03:K1:/NgzfGObZVeaG2eDA+92oNr7Ekz95i7GtCvHXrqSWmeK8EeQ58O scBAxBNwMSm2IKVfOc6JhOAYRSegCEgEQp53xOIyo+srcZK6j0IJQDs90fkNEC9IO9VlhAm 6t/JTq065lVMsKWxwhzgpyfXL/y5UejE0J7TxlojP0RNVBkqHKpFGQcB4lATYFwdaaJ9xL4 dYULw1IWh3bWAptO1Chjg== X-Spam-Flag: NO UI-OutboundReport: notjunk:1;M01:P0:8Ll8dpNbEcg=;USMdHY69gIVxcCv5W13TAXifbYY pW97uuBFvGtMOespanlwBnQHASeJNBeIMzar4Kew3etl4RiylRz0d471U3HXhd0UD9gqS4HgW I/gAz0BrAhxJbg5rY0HQjzRqUKFbuUTKhur9tM6zyIKRMU/IZFuqVmmP118ba0L/TrzxkWzYK uv1f5SukCJKPmUVzXPzo+FHghUqEYo8LyQ014/BncVsjCwvCeYwnVAyhv24zUp8Ihe4ECwEjD C/MVkAeh/QD4J0kNmZ1pcVtHNHuEGaMggteFWKnoI+A/CGeranCXyxiFgzj7bGF8L39BmuhE9 KVXkOUaqVCVRZmefCGK1D3ySr+Qu4tm5glEaTspT/SajUP7cd0D85vd6qq4AXYmny4vwp18LG CmJOa+VR+e5wJjc9FRs58VguSbE+3Xj1ITkJKIuCs15eBlTfvI2E6xJV63X9maDXE77ztv8sO P5E8tQeh4Wgf97Y+iw/TtZWqXdWoTjLpODGesPc3Zt8sZ/iY4mkLxl86uMf+Vvne9UXAgDoam 2jf8rm4TQ29lLekXsql24/Qxft/TnwTljPPtxRGf54bwSHq5yjO4J2h7g//u50YJejbjDcGLT CdpEYvNtzDmxfHDaKgk5dlBFUTYerY5mLqkZxLgVL1lJxOhBTdnWp+6NvZ2x1a5ALIyCCZIgM ZWpAm50SSw5NXWYA/kXSYC8BsIfsqucja98w6P8aptdkeSmUFmj77sX9Ube7QrG3QrAgkfdnI DzABzQyVjvqtv/rZoIrH47/nEYc2LBuNXOgsBMPsS3FQJ0PxGi4eSo4/W10xJkRxBIUp8bN2Q gQPc3mxx8XRWIVU+FnqUxwGTtMxXKYQSh+OngX7H0vEeGue+ShzGtLQWgMOEJbD7hpRbz1GVt nYVsKP7DXkBhp6UHludt5lyf4IUvKhvC1faqzVnePnxjNEZzfP1a7r/dSCI2YXqU61UkIrFZJ ZVurRMXSv1ruCWCdP6bo9nHhbRU= X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 60936 Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.7 (-) "J.P." <jp@HIDDEN> writes: Hi, > There have been three failures (all on native-comp-speed2-master) over > the last three weeks pointing to these tests, which haven't changed in > the year-plus they've existed in tree. No test appears in multiple > failures, and all continue to pass daily on commercial GitLab (GCP) > runners using the same EMBA container image. They also pass locally > with "make check" and "make -j -C test SELECTOR=t check-lisp-erc". If > these tweaks don't fix the problem, they can be branded :unstable. If the problem happens only on emba, you can skip the tests with --8<---------------cut here---------------start------------->8--- :tags (if (getenv "EMACS_EMBA_CI") '(:expensive-test :unstable) '(:expensive-test)) --8<---------------cut here---------------end--------------->8--- Best regards, Michael.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 9 Aug 2023 14:54:05 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Aug 09 10:54:05 2023 Received: from localhost ([127.0.0.1]:40319 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qTkZX-0002FB-IN for submit <at> debbugs.gnu.org; Wed, 09 Aug 2023 10:54:05 -0400 Received: from mail-108-mta81.mxroute.com ([136.175.108.81]:41397) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qTkZT-0002Ei-Cm for 60936 <at> debbugs.gnu.org; Wed, 09 Aug 2023 10:54:01 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta81.mxroute.com (ZoneMTA) with ESMTPSA id 189daca481500023b6.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 09 Aug 2023 14:53:57 +0000 X-Zone-Loop: 21b2bd0b616a68af2eb2c149ed38739563225a3ab21e 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=P/1mpDiezr6hMkgxY+OiP6uRUmrgMZem4EDHoyXO09Q=; b=bI8lxyyKYo4d31fUb6mzQJh6f1 0Cx+ppXPRiOnyLRxiI55OkXGNKMb6fO5WwZK0YCNYQ148a4uuArxlXBjzB8PbvNPE81JuPj9CzNga jej3+HiEzzRZNLwHGU5EoNeClggUnj0YvXc1zKX1ZOPHwwUfJwB4q/MhQVwnRbc6hvM/3aDJfjgD/ 235GPIL1hFKqdXx5hrSZo4DwHfFy3BvJ40C3DQv3Y/A82otyt22rMe5Yhk9RQV1A8xUg4VxQd5rxW pfbaU6L2AfBQ/Qhz6N7IIDeHDyHb1J5lap8CqR1v7onmgXv8UnYvUbCWlZY9RQgnRcyL3/YnsT1y3 a0PS3cwg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Wed, 09 Aug 2023 07:53:53 -0700 Message-ID: <87edkcmflq.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain I'd like to add a minor improvement and some small bug fixes to this feature (new in ERC 5.6). The improvement concerns the command `erc-fill-wrap-cycle-visual-movement', which cycles through three flavors of interactive movement: "logcial-line", "screen-line", and "DWIM". In an unfortunate omission (by me), basic line-wise movement commands weren't initially included. But now I'm thinking users would at least appreciate being able to navigate by whole IRC message when the logical-line variant (nil state) is active. That's what the third patch does. The second patch introduces a minor change involving the mostly unrelated bug#60933, which did away with the oddball "nickname" entry in `erc-button-alist' and introduced an escape hatch (in the function-valued variable `erc-button-nickname-callback-function') for those needing access to the excised entry's "on-click" callback. The interface was initially defined to accommodate the nick-button's "erc-data" object, in this case a list containing a lone arg, the nickname, to pass to the callback. However, in this instance, we're not really obliged to preserve compatibility because this is a new variable, and the old hard-wired callback, `erc-nick-popup', remains untouched. Therefore, I think we should take this opportunity to redefine this interface to accept any number of TBD trailing args after the nickname. This will make it easier to retain more informative data for rich UI features without resorting to hacks, like hiding data in text-properties of public strings, which can leak memory. I also think we ought to deprecate this variable even though it's new in ERC 5.6 to stress the fact that the default value is basically required when using ERC as an interactive client. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Relax-timeouts-on-some-ERC-tests.patch From 7056f29d1f604c1a52f905578f0a75e8b157bfb4 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 31 Jul 2023 22:20:01 -0700 Subject: [PATCH 1/3] ; Relax timeouts on some ERC tests There have been three failures (all on native-comp-speed2-master) over the last three weeks pointing to these tests, which haven't changed in the year-plus they've existed in tree. No test appears in multiple failures, and all continue to pass daily on commercial GitLab (GCP) runners using the same EMBA container image. They also pass locally with "make check" and "make -j -C test SELECTOR=t check-lisp-erc". If these tweaks don't fix the problem, they can be branded :unstable. * test/lisp/erc/erc-scenarios-base-renick.el: Extend timeouts. * test/lisp/erc/resources/base/netid/bouncer/barnet.eld: Extend timeouts. * test/lisp/erc/resources/base/netid/bouncer/foonet.eld: Extend timeouts. * test/lisp/erc/resources/base/reconnect/options.eld: Extend timeouts. * test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld: Extend timeouts. * test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld: Extend timeouts. * test/lisp/erc/resources/erc-scenarios-common.el: Extend timeout. * test/lisp/erc/resources/services/auth-source/libera.eld: Extend timeouts. --- test/lisp/erc/erc-scenarios-base-renick.el | 4 ++-- .../erc/resources/base/netid/bouncer/barnet.eld | 12 ++++++------ .../erc/resources/base/netid/bouncer/foonet.eld | 12 ++++++------ test/lisp/erc/resources/base/reconnect/options.eld | 10 +++++----- .../base/renick/queries/bouncer-barnet.eld | 14 +++++++------- .../base/renick/queries/bouncer-foonet.eld | 12 ++++++------ test/lisp/erc/resources/erc-scenarios-common.el | 2 +- .../erc/resources/services/auth-source/libera.eld | 10 +++++----- 8 files changed, 38 insertions(+), 38 deletions(-) diff --git a/test/lisp/erc/erc-scenarios-base-renick.el b/test/lisp/erc/erc-scenarios-base-renick.el index f1723200533..2bf3ef46257 100644 --- a/test/lisp/erc/erc-scenarios-base-renick.el +++ b/test/lisp/erc/erc-scenarios-base-renick.el @@ -275,8 +275,8 @@ erc-scenarios-base-renick-queries-bouncer (funcall expect 3 "I never saw her before") (erc-scenarios-common-say "You aren't with Wage?"))) - (erc-d-t-wait-for 3 (get-buffer "frenemy@foonet")) - (erc-d-t-wait-for 3 (get-buffer "frenemy@barnet")) + (erc-d-t-wait-for 10 (get-buffer "frenemy@foonet")) + (erc-d-t-wait-for 10 (get-buffer "frenemy@barnet")) (should-not (get-buffer "rando@foonet")) (should-not (get-buffer "rando@barnet")) diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet.eld b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld index d0fe3af8ea4..204d01fef77 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/barnet.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 3 "PASS :barnet:changeme")) -((nick 3 "NICK tester")) -((user 3 "USER user 0 * :tester") +((pass 10 "PASS :barnet:changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester") (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version oragono-2.6.0-7481bf0385b95b16") (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 07:41:08 UTC") @@ -17,19 +17,19 @@ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.barnet.org 422 tester :MOTD File is missing")) -((mode-user 10.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") ;; No mode answer ^ (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":irc.barnet.org 305 tester :You are no longer marked as being away")) -((join 1 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester") (0 ":irc.barnet.org 366 tester #chan :End of NAMES list") (0.1 ":joe!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":mike!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 3 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1620805269") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: But you have outfaced them all.") diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet.eld b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld index b0964fb9537..4445350ca0c 100644 --- a/test/lisp/erc/resources/base/netid/bouncer/foonet.eld +++ b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 3 "PASS :foonet:changeme")) -((nick 3 "NICK tester")) -((user 3 "USER user 0 * :tester") +((pass 10 "PASS :foonet:changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16") (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 07:41:09 UTC") @@ -17,19 +17,19 @@ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 4.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") ;; No mode answer ^ (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":irc.foonet.org 305 tester :You are no longer marked as being away")) -((join 1 "JOIN #chan") +((join 10 "JOIN #chan") (0 ":tester!~u@HIDDEN JOIN #chan") (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester") (0 ":irc.foonet.org 366 tester #chan :End of NAMES list") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :tester, welcome!") (0 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!")) -((mode 3 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620805271") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :bob: He cannot be heard of. Out of doubt he is transported.") diff --git a/test/lisp/erc/resources/base/reconnect/options.eld b/test/lisp/erc/resources/base/reconnect/options.eld index 3b305d85594..e0952a2aece 100644 --- a/test/lisp/erc/resources/base/reconnect/options.eld +++ b/test/lisp/erc/resources/base/reconnect/options.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 1 "PASS :changeme")) -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((pass 10 "PASS :changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16") (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 05:06:18 UTC") @@ -18,7 +18,7 @@ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 3.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0 ":irc.foonet.org 221 tester +i") (0 ":irc.foonet.org NOTICE tester :This server is in debug mode.") @@ -26,7 +26,7 @@ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob") (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")) -((mode-chan 4 "MODE #chan") +((mode-chan 10 "MODE #chan") (0 ":irc.foonet.org 324 tester #chan +nt") (0 ":irc.foonet.org 329 tester #chan 1620104779") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :tester, welcome!") diff --git a/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld b/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld index 0c8cdac0379..c9080cf39e9 100644 --- a/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld +++ b/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 3 "PASS :barnet:changeme")) -((nick 3 "NICK tester")) -((user 3 "USER user 0 * :tester") +((pass 10 "PASS :barnet:changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester") (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version oragono-2.6.0-7481bf0385b95b16") (0 ":irc.barnet.org 003 tester :This server was created Tue, 01 Jun 2021 07:49:23 UTC") @@ -17,7 +17,7 @@ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.barnet.org 422 tester :MOTD File is missing")) -((mode-user 3.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") ;; No mode answer (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":tester!~u@HIDDEN JOIN #chan") @@ -32,18 +32,18 @@ (0 ":irc.barnet.org NOTICE tester :[09:13:24] 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.") (0 ":irc.barnet.org 305 tester :You are no longer marked as being away")) -((mode 5 "MODE #chan") +((mode 10 "MODE #chan") (0 ":irc.barnet.org 324 tester #chan +nt") (0 ":irc.barnet.org 329 tester #chan 1622538742") (0.1 ":joe!~u@HIDDEN PRIVMSG #chan :mike: By favors several which they did bestow.") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: You, Roderigo! come, sir, I am for you.")) -((privmsg-a 5 "PRIVMSG rando :Linda said you were gonna kill me.") +((privmsg-a 10 "PRIVMSG rando :Linda said you were gonna kill me.") (0.1 ":joe!~u@HIDDEN PRIVMSG #chan :mike: Play, music, then! Nay, you must do it soon.") (0.1 ":rando!~u@HIDDEN PRIVMSG tester :Linda said? I never saw her before I came up here.") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: Of arts inhibited and out of warrant.")) -((privmsg-b 3 "PRIVMSG rando :You aren't with Wage?") +((privmsg-b 10 "PRIVMSG rando :You aren't with Wage?") (0.1 ":joe!~u@HIDDEN PRIVMSG #chan :mike: But most of all, agreeing with the proclamation.") (0.1 ":rando!~u@HIDDEN PRIVMSG tester :I think you screwed up, Case.") (0.1 ":mike!~u@HIDDEN PRIVMSG #chan :joe: Good gentleman, go your gait, and let poor volk pass. An chud ha' bin zwaggered out of my life, 'twould not ha' bin zo long as 'tis by a vortnight. Nay, come not near th' old man; keep out, che vor ye, or ise try whether your costard or my ballow be the harder. Chill be plain with you.") diff --git a/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld b/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld index 162e8bf9655..2421651ebe8 100644 --- a/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld +++ b/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- -((pass 1 "PASS :foonet:changeme")) -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((pass 10 "PASS :foonet:changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16") (0 ":irc.foonet.org 003 tester :This server was created Tue, 01 Jun 2021 07:49:22 UTC") @@ -17,7 +17,7 @@ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) -((mode-user 5.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") ;; No mode answer (0 ":irc.znc.in 306 tester :You have been marked as being away") (0 ":tester!~u@HIDDEN JOIN #chan") @@ -38,12 +38,12 @@ (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: When there is nothing living but thee, thou shalt be welcome. I had rather be a beggar's dog than Apemantus.") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :bob: You have simply misused our sex in your love-prate: we must have your doublot and hose plucked over your head, and show the world what the bird hath done to her own nest.")) -((privmsg-a 6 "PRIVMSG rando :I here") +((privmsg-a 10 "PRIVMSG rando :I here") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: And I will make thee think thy swan a crow.") (0.1 ":rando!~u@HIDDEN PRIVMSG tester :u are dumb") (0.1 ":alice!~u@HIDDEN PRIVMSG #chan :bob: Lie not, to say mine eyes are murderers.")) -((privmsg-b 3 "PRIVMSG rando :not so") +((privmsg-b 10 "PRIVMSG rando :not so") (0.1 ":bob!~u@HIDDEN PRIVMSG #chan :alice: Commit myself, my person, and the cause.") ;; Nick change (0.1 ":rando!~u@HIDDEN NICK frenemy") diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el index 32e7556d602..972faa5c73f 100644 --- a/test/lisp/erc/resources/erc-scenarios-common.el +++ b/test/lisp/erc/resources/erc-scenarios-common.el @@ -288,7 +288,7 @@ erc-scenarios-common--base-network-id-bouncer (erc-d-t-search-for 1 "<bob>") (erc-d-t-absent-for 0.1 "<joe>") (should (eq erc-server-process erc-server-process-foo)) - (erc-d-t-search-for 10 "ape is dead") + (erc-d-t-search-for 15 "ape is dead") (erc-d-t-wait-for 5 (not (erc-server-process-alive))))) (ert-info ("#chan@<esid> is exclusive to barnet") diff --git a/test/lisp/erc/resources/services/auth-source/libera.eld b/test/lisp/erc/resources/services/auth-source/libera.eld index c8dbc9d425a..dfc25221508 100644 --- a/test/lisp/erc/resources/services/auth-source/libera.eld +++ b/test/lisp/erc/resources/services/auth-source/libera.eld @@ -1,6 +1,6 @@ ;; -*- mode: lisp-data; -*- -((nick 1 "NICK tester")) -((user 1 "USER user 0 * :tester") +((nick 10 "NICK tester")) +((user 5 "USER user 0 * :tester") (0.26 ":zirconium.libera.chat NOTICE * :*** Checking Ident") (0.01 ":zirconium.libera.chat NOTICE * :*** Looking up your hostname...") (0.01 ":zirconium.libera.chat NOTICE * :*** No Ident response") @@ -35,15 +35,15 @@ (0.01 ":zirconium.libera.chat 372 tester :- Email: support@HIDDEN") (0.00 ":zirconium.libera.chat 376 tester :End of /MOTD command.")) -((mode-user 1.2 "MODE tester +i") +((mode-user 10 "MODE tester +i") (0.02 ":tester MODE tester :+Zi") (0.02 ":NickServ!NickServ@HIDDEN NOTICE tester :This nickname is registered. Please choose a different nickname, or identify via \2/msg NickServ IDENTIFY tester <password>\2")) -((privmsg 2 "PRIVMSG NickServ :IDENTIFY changeme") +((privmsg 10 "PRIVMSG NickServ :IDENTIFY changeme") (0.96 ":NickServ!NickServ@HIDDEN NOTICE tester :You are now identified for \2tester\2.") (0.25 ":NickServ!NickServ@HIDDEN NOTICE tester :Last login from: \2~tester@HIDDEN/tester\2 on Jun 18 01:15:56 2021 +0000.")) -((quit 5 "QUIT :\2ERC\2") +((quit 10 "QUIT :\2ERC\2") (0.19 ":tester!~user@HIDDEN QUIT :Client Quit")) ((linger 1 LINGER)) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Deprecate-erc-button-nickname-callback-function.patch From f8982577fb61863d47497e86686ca20a932b71da Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 7 Aug 2023 03:35:56 -0700 Subject: [PATCH 2/3] [5.6] Deprecate erc-button-nickname-callback-function * lisp/erc/erc-button.el (erc-button-nickname-callback-function): Deprecate this function-valued variable, first introduced in ERC 5.6, to dissuade consumers of the old `erc-button-alist' nickname interface from meddling with the on-click callback of buttonized nicks. They should instead add their own propertizing logic in something like `erc-insert-modify-hook'. Also change default callback to a wrapper that discards all but the first arg. This effectively declares that `erc-data' values may contain more than one element in the near future. (erc-button--perform-nick-popup): New default nick-button callback function that calls `erc-nick-popup' with the first argument and ignores the rest. (Bug#60933) --- lisp/erc/erc-button.el | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index 89a6cd131c0..bfaf4fa821a 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -279,8 +279,13 @@ erc-button-setup " entries are deprecated. Either use a variable or a function" " that conditionally calls `erc-button-add-button'."))))) -(defvar erc-button-nickname-callback-function #'erc-nick-popup - "Escape hatch for those needing a different nickname callback.") +(defvar erc-button-nickname-callback-function #'erc-button--perform-nick-popup + "Escape hatch for users needing a non-standard nick-button callback. +Value should be a function accepting a NICK and any number of +trailing arguments that are as yet unspecified. Runs when +clicking \\`<mouse-1>' or hitting \\`RET' atop a nickname button.") +(make-obsolete-variable 'erc-button-nickname-callback-function + "default provides essential functionality" "30.1") (defun erc-button-add-buttons () "Find external references in the current buffer and make buttons of them. @@ -745,6 +750,10 @@ erc-nick-popup (funcall code nick) (eval code `((nick . ,nick))))))) +(defun erc-button--perform-nick-popup (nick &rest _) + "Call `erc-nick-popup' with NICK." + (erc-nick-popup nick)) + ;;; Callback functions (defun erc-button-describe-symbol (symbol-name) "Describe SYMBOL-NAME. -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Add-line-wise-movement-commands-for-erc-fill-wra.patch From b6685530bd6fc8faba289df0672fe0be942f95bc Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 6 Aug 2023 22:05:26 -0700 Subject: [PATCH 3/3] [5.6] Add line-wise movement commands for erc-fill-wrap * lisp/erc/erc-fill.el (erc-fill--wrap-escape-hidden-speaker): New helper to move point to beginning of visible text. (erc-fill--wrap-beginning-of-line): Factor out adjustment for hidden speakers. (erc-fill--wrap-previous-line, erc-fill--wrap-next-line): Add commands for moving to previous and next line in a manner consistent with the value of `erc-fill--wrap-visual-keys'. (erc-fill-warp-mode-map): Add bindings for `next-line' and `previous-line'. (erc-fill-wrap-mode): Revise doc string. (erc-fill-wrap-nudge): Fix vertical anchoring so that point's line remains fixed throughout the adjustment. The previous approach crudely approximated the current window line by betting that all messages are roughly the same length. It also wrongly assumed that `point-max' at least equaled `window-end'. That is, it did not account for blank space between EOB and the bottom of the window. (Bug#60936) --- lisp/erc/erc-fill.el | 70 +++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e2a82582a3f..7eace924da7 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -262,6 +262,14 @@ erc-fill--wrap-kill-line ;; `kill-line' anyway so that users can see the error. (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) +(defun erc-fill--wrap-escape-hidden-speaker () + "Move to start of message text when left of speaker. +Basically mimic what `move-beginning-of-line' does with invisible text." + (when-let ((erc-fill-wrap-merge) + (prop (get-text-property (point) 'display)) + ((or (equal prop "") (eq 'margin (car-safe (car-safe prop)))))) + (goto-char (text-property-not-all (point) (pos-eol) 'display prop)))) + (defun erc-fill--wrap-beginning-of-line (arg) "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." (interactive "^p") @@ -271,10 +279,22 @@ erc-fill--wrap-beginning-of-line (if (get-text-property (point) 'erc-prompt) (goto-char erc-input-marker) ;; Mimic what `move-beginning-of-line' does with invisible text. - (when-let ((erc-fill-wrap-merge) - (prop (get-text-property (point) 'display)) - ((or (equal prop "") (eq 'margin (car-safe (car-safe prop)))))) - (goto-char (text-property-not-all (point) (pos-eol) 'display prop))))) + (erc-fill--wrap-escape-hidden-speaker))) + +(defun erc-fill--wrap-previous-line (&optional arg try-vscroll) + "Move to ARGth previous screen or logical line." + (interactive "^p\np") + (if erc-fill--wrap-visual-keys + (with-no-warnings (previous-line arg try-vscroll)) + (prog1 (previous-logical-line arg try-vscroll) + (erc-fill--wrap-escape-hidden-speaker)))) + +(defun erc-fill--wrap-next-line (&optional arg try-vscroll) + "Move to ARGth next screen or logical line." + (interactive "^p\np") + (if erc-fill--wrap-visual-keys + (with-no-warnings (next-line arg try-vscroll)) + (next-logical-line arg try-vscroll))) (defun erc-fill--wrap-end-of-line (arg) "Defer to `move-end-of-line' or `end-of-visual-line'." @@ -320,6 +340,8 @@ erc-fill-wrap-mode-map "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line "<remap> <toggle-truncate-lines>" #'erc-fill-wrap-toggle-truncate-lines + "<remap> <next-line>" #'erc-fill--wrap-next-line + "<remap> <previous-line>" #'erc-fill--wrap-previous-line "C-c a" #'erc-fill-wrap-cycle-visual-movement ;; Not sure if this is problematic because `erc-bol' takes no args. "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) @@ -359,28 +381,36 @@ erc-fill--wrap-ensure-dependencies ;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) (define-erc-module fill-wrap nil "Fill style leveraging `visual-line-mode'. -This local module displays nicks overhanging leftward to a common -offset, as determined by the option `erc-fill-static-center'. It -depends on the `fill', `stamp', and `button' modules and assumes -users who've defined their own `erc-insert-timestamp-function' -have also customized the option `erc-fill-wrap-margin-side' to an -explicit side. To use this module, either include `fill-wrap' in -`erc-modules' or set `erc-fill-function' to `erc-fill-wrap'. -Manually invoking one of the minor-mode toggles is not -recommended. +This module displays nicks overhanging leftward to a common +offset, as determined by the option `erc-fill-static-center'. To +use it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. Most users will want to +enable the `scrolltobottom' module as well. Once active, use +\\[erc-fill-wrap-nudge] to adjust the width of the indent and the +stamp margin, and use \\[erc-fill-wrap-toggle-truncate-lines] for +cycling between logical- and screen-oriented movement commands. This module imposes various restrictions on the appearance of timestamps. Most notably, it insists on displaying them in the margins. Users preferring left-sided stamps may notice that ERC also displays the prompt in the left margin, possibly truncating -or padding it to constrain it to the margin's width. When stamps +or padding it to constrain it to the margin's width. +Additionally, this module assumes that users providing their own +`erc-insert-timestamp-function' have also customized the option +`erc-fill-wrap-margin-side' to an explicit side. When stamps appear in the right margin, which they do by default, users may find that ERC actually appends them to copy-as-killed messages without an intervening space. This normally poses at most a minor inconvenience, however users of the `log' module may prefer a workaround provided by `erc-stamp-prefix-log-filter', which strips trailing stamps from logged messages and instead prepends -them to every line." +them to every line. + +As a so-called \"local\" module, `fill-wrap' depends on the +global modules `fill', `stamp', and `button'; it activates them +as needed when initializing. Please note that enabling and +disabling this module by invoking one of its minor-mode toggles +is not recommended." ((erc-fill--wrap-ensure-dependencies) (erc--restore-initialize-priors erc-fill-wrap-mode erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys @@ -548,8 +578,8 @@ erc-fill-wrap-nudge (user-error "Command called in an undisplayed buffer")) (let* ((total (erc-fill--wrap-nudge arg)) (leftp erc-stamp--margin-left-p) - (win-ratio (/ (float (- (window-point) (window-start))) - (- (window-end nil t) (window-start))))) + ;; Anchor current line vertically. + (line (count-screen-lines (window-start) (window-point)))) (when (zerop arg) (setq arg 1)) (erc-compat-call @@ -564,7 +594,7 @@ erc-fill-wrap-nudge (lambda () (interactive) (cl-incf total (erc-fill--wrap-nudge a)) - (recenter (round (* win-ratio (window-height)))))))) + (recenter line))))) (dolist (key '(?\) ?_ ?+)) (let ((a (pcase key (?\) 0) @@ -575,7 +605,7 @@ erc-fill-wrap-nudge (interactive) (erc-stamp--adjust-margin (- a) (zerop a)) (when leftp (erc-stamp--refresh-left-margin-prompt)) - (recenter (round (* win-ratio (window-height)))))))) + (recenter line))))) map) t (lambda () @@ -584,7 +614,7 @@ erc-fill-wrap-nudge (if leftp left-margin-width right-margin-width))) "Use %k for further adjustment" 1) - (recenter (round (* win-ratio (window-height)))))) + (recenter line))) (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 28 Jul 2023 23:59:33 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jul 28 19:59:33 2023 Received: from localhost ([127.0.0.1]:46270 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qPXMr-00034w-AK for submit <at> debbugs.gnu.org; Fri, 28 Jul 2023 19:59:33 -0400 Received: from mail-108-mta225.mxroute.com ([136.175.108.225]:38131) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qPXMp-00034o-Af for 60936 <at> debbugs.gnu.org; Fri, 28 Jul 2023 19:59:32 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta225.mxroute.com (ZoneMTA) with ESMTPSA id 1899ef163b50004cef.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 28 Jul 2023 23:59:27 +0000 X-Zone-Loop: 14db22a7be30d513d9bbe22ed0a29417bb01b7e77fc6 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=1li/p6/SwXvqo9wERQ8SJbHsWiLXlo+k2uRqlYem61Y=; b=ZAnVm3he1KpaA1dTp+fqQ0YKoE RGOvKE+DiHwvsDG8w1G4hE26U2Cp9wXKKjthapGHW1gcIv9KDkWtotcl49ug56XeTbuAhG7bK0YoB RYWlVKysmDfnSD09m5toDqqny3fVT+WIw8rS/3bvBgXuFItr7ollOw/RHuShvPu1GjODpH6KnATc0 3syNcV1yMDiW5Dh7gXq7lswWylazkUfdjGPdXYqrL4ZlN/WuXToCd9MYeSKMvlYsp2Elpo75jcvAx DzXWHjXO3Ul9Tdi4KAHdkv/GnqNhAX40+VSUp992lIb1bGlkk0ebCVMCoy1m98wzkc2Q1SEq59r91 oxBVxOzA==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87h6pug23c.fsf@HIDDEN> (J. P.'s message of "Sun, 23 Jul 2023 07:00:07 -0700") References: <87tu0nao77.fsf@HIDDEN> <87msztl4xu.fsf@HIDDEN> <87a5vsjb3q.fsf@HIDDEN> <87351iiueu.fsf@HIDDEN> <87h6pug23c.fsf@HIDDEN> Date: Fri, 28 Jul 2023 16:59:18 -0700 Message-ID: <875y63si3t.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > Unfortunately, it introduced a regression involving CTCP ACTIONs from > consecutive speakers. To reproduce, say something in a target buffer, > then do a "/me something" immediately afterward. You'll see that ERC > inserts > > <nick> something > something > > instead of > > <nick> something > * nick something > > or > > <nick> something > * nick something > > The attached patch should fix this. This has been installed as 8623159b Fix CTCP ACTION regression in erc-fill-wrap Thanks.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 23 Jul 2023 14:00:18 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Sun Jul 23 10:00:18 2023 Received: from localhost ([127.0.0.1]:41084 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qNZdB-0004WV-9w for submit <at> debbugs.gnu.org; Sun, 23 Jul 2023 10:00:17 -0400 Received: from mail-108-mta108.mxroute.com ([136.175.108.108]:35399) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qNZd8-0004WL-RG for 60936 <at> debbugs.gnu.org; Sun, 23 Jul 2023 10:00:16 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta108.mxroute.com (ZoneMTA) with ESMTPSA id 189830cf5940004cef.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 23 Jul 2023 14:00:11 +0000 X-Zone-Loop: ff16db9224b180e914a45018ca13007bc335321c9b7c 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=WnII9XzbeXSrNTa83/1nlxS1NQK3EwKzPbA0Sy+kdJU=; b=QRTktNWfXZT87wa8bxFux9eitb z7phrZvjxXQM3RUWgppCHSQEQnUJsrlQTa6v8LTab/Fbkefaz3DGGKRux4qgC1tjNEDdXRhpjz+EU qLiIWt0L+977rtuvRPC8Rkdl+dAHTV+MDSZS7SxVkvPN3YLsDA83gKBpRFKPcfCvWRiCtrPe3h9OD uQx3tIh/tjqJWQ2Prvy6sZWv8oCYpZkAlN5UlLPW6S8Ib2aUjb+y6IAKSO1aO0IQyJ0ZxkIkGlEha I6NzJF+3OxIpjfSM6VGjmWFTyjCsn7he1+WjVFMSkRKtENAnUUO5kFdjbNTr2LAux5f82fJvJnca+ oY+RyEDw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87351iiueu.fsf@HIDDEN> (J. P.'s message of "Thu, 20 Jul 2023 06:28:41 -0700") References: <87tu0nao77.fsf@HIDDEN> <87msztl4xu.fsf@HIDDEN> <87a5vsjb3q.fsf@HIDDEN> <87351iiueu.fsf@HIDDEN> Date: Sun, 23 Jul 2023 07:00:07 -0700 Message-ID: <87h6pug23c.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain "J.P." <jp@HIDDEN> writes: > v3 (left-margin enhancement). Extend stamp-only text properties to > leading white space on right-sided stamps occupying their own line. This was installed as * 63d8b2a59a4 Make erc-fill-wrap work with left-sided stamps Unfortunately, it introduced a regression involving CTCP ACTIONs from consecutive speakers. To reproduce, say something in a target buffer, then do a "/me something" immediately afterward. You'll see that ERC inserts <nick> something something instead of <nick> something * nick something or <nick> something * nick something The attached patch should fix this. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Fix-CTCP-ACTION-regression-in-erc-fill-wrap.patch Content-Transfer-Encoding: quoted-printable From 0812d0b35e07d36d1747d5483e7da6ca5ac81c1d Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sat, 22 Jul 2023 14:07:38 -0700 Subject: [PATCH] [5.6] Fix CTCP ACTION regression in erc-fill-wrap * lisp/erc/erc-fill.el (erc-fill--wrap-continued-message-p): Fail when current message is a CTCP ACTION. This fixes a regression introduced by 63d8b2a59a4 "Make erc-fill-wrap work with left-sided stamps". * test/lisp/erc/erc-fill-tests.el: (erc-fill-wrap--merge-action): New test. * test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld: New test data file. (Bug#60936) --- lisp/erc/erc-fill.el | 3 +- test/lisp/erc/erc-fill-tests.el | 40 +++++++++++++++++++ .../fill/snapshots/merge-wrap-01.eld | 1 + 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 17eb0002f08..e2a82582a3f 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -443,12 +443,13 @@ erc-fill--wrap-continued-message-p (cons (get-text-property m 'erc-timestamp) (get-text-property spr 'erc-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)) (speaker (next-single-property-change (point-min) 'erc-speak= er)) + ((not (eq (get-text-property speaker 'erc-ctcp) 'ACTION))) (nick (get-text-property speaker 'erc-speaker)) - (props) ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) =20 diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index 67622da9f3d..b81d0c15558 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -241,6 +241,46 @@ erc-fill-wrap--merge "<bob> " "<alice> " "<alice> " "<bob> " "<bob> " "<Dummy> " "<Dumm= y> ") (erc-fill-tests--compare "merge-02-right"))))) =20 +(ert-deftest erc-fill-wrap--merge-action () + :tags '(:unstable) + (unless (>=3D emacs-major-version 29) + (ert-skip "Emacs version too low, missing `buffer-text-pixel-size'")) + + (erc-fill-tests--wrap-populate + + (lambda () + ;; Set this here so that the first few messages are from 1970 + (let ((erc-fill-tests--time-vals (lambda () 1680332400))) + (erc-fill-tests--insert-privmsg "bob" "zero.") + + (erc-process-ctcp-query + erc-server-process + (make-erc-response + :unparsed ":bob!~u@fake PRIVMSG #chan :\1ACTION one\1" + :sender "bob!~u@fake" :command "PRIVMSG" + :command-args '("#chan" "\1ACTION one\1") :contents "\1ACTION one= \1") + "bob" "~u" "fake") + + (erc-fill-tests--insert-privmsg "bob" "two.") + + ;; Compat switch to opt out of overhanging speaker. + (let (erc-fill--wrap-action-dedent-p) + (erc-process-ctcp-query + erc-server-process + (make-erc-response + :unparsed ":bob!~u@fake PRIVMSG #chan :\1ACTION three\1" + :sender "bob!~u@fake" :command "PRIVMSG" + :command-args '("#chan" "\1ACTION three\1") + :contents "\1ACTION three\1") + "bob" "~u" "fake")) + + (erc-fill-tests--insert-privmsg "bob" "four.")) + + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes + "*** " "<alice> " "<bob> " "<bob> " "* bob " "<bob> " "* " "<bob> ") + (erc-fill-tests--compare "merge-wrap-01")))) + (ert-deftest erc-fill-line-spacing () :tags '(:unstable) (unless (>=3D emacs-major-version 29) diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/tes= t/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld new file mode 100644 index 00000000000..a3d533c87b5 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[= Sat Apr 1 2023]\n<bob> zero.[07:00]\n* bob one\n<bob> two.\n* bob three\n<= bob> four.\n" 2 20 (erc-timestamp 0 line-prefix (space :width (- 27 (18))) = field erc-timestamp) 20 21 (erc-timestamp 0 field erc-timestamp) 21 183 (er= c-timestamp 0 wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :w= idth (- 27 (4)))) 183 190 (erc-timestamp 0 field erc-timestamp wrap-prefix = #2# line-prefix #3# display #1=3D(#7=3D(margin right-margin) #("[00:00]" 0 = 7 (display #1# invisible timestamp font-lock-face erc-timestamp-face)))) 19= 1 192 (erc-timestamp 0 wrap-prefix #2# line-prefix #4=3D(space :width (- 27= (8))) erc-command PRIVMSG) 192 197 (erc-timestamp 0 wrap-prefix #2# line-p= refix #4# erc-command PRIVMSG) 197 199 (erc-timestamp 0 wrap-prefix #2# lin= e-prefix #4# erc-command PRIVMSG) 199 202 (erc-timestamp 0 wrap-prefix #2# = line-prefix #4# erc-command PRIVMSG) 202 315 (erc-timestamp 0 wrap-prefix #= 2# line-prefix #4# erc-command PRIVMSG) 315 316 (erc-timestamp 0 erc-comman= d PRIVMSG) 316 348 (erc-timestamp 0 wrap-prefix #2# line-prefix #4# erc-com= mand PRIVMSG) 349 350 (erc-timestamp 0 wrap-prefix #2# line-prefix #5=3D(sp= ace :width (- 27 (6))) erc-command PRIVMSG) 350 353 (erc-timestamp 0 wrap-p= refix #2# line-prefix #5# erc-command PRIVMSG) 353 355 (erc-timestamp 0 wra= p-prefix #2# line-prefix #5# erc-command PRIVMSG) 355 360 (erc-timestamp 0 = wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 360 435 (erc-timestamp= 0 wrap-prefix #2# line-prefix #5# erc-command PRIVMSG) 436 454 (erc-timest= amp 1680332400 line-prefix (space :width (- 27 (18))) field erc-timestamp) = 454 455 (erc-timestamp 1680332400 field erc-timestamp) 455 456 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #6=3D(space :width (- 27 (6))) er= c-command PRIVMSG) 456 459 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #6# erc-command PRIVMSG) 459 466 (erc-timestamp 1680332400 wrap-prefi= x #2# line-prefix #6# erc-command PRIVMSG) 466 473 (erc-timestamp 168033240= 0 field erc-timestamp wrap-prefix #2# line-prefix #6# display #8=3D(#7# #("= [07:00]" 0 7 (display #8# invisible timestamp font-lock-face erc-timestamp-= face)))) 474 476 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9= =3D(space :width (- 27 (6))) erc-ctcp ACTION erc-command PRIVMSG) 476 479 (= erc-timestamp 1680332400 wrap-prefix #2# line-prefix #9# erc-ctcp ACTION er= c-command PRIVMSG) 479 483 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #9# erc-ctcp ACTION erc-command PRIVMSG) 484 485 (erc-timestamp 16803= 32400 wrap-prefix #2# line-prefix #10=3D(space :width (- 27 (6))) erc-comma= nd PRIVMSG) 485 488 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #= 10# erc-command PRIVMSG) 488 494 (erc-timestamp 1680332400 wrap-prefix #2# = line-prefix #10# erc-command PRIVMSG) 495 497 (erc-timestamp 1680332400 wra= p-prefix #2# line-prefix #11=3D(space :width (- 27 (2))) erc-ctcp ACTION er= c-command PRIVMSG) 497 500 (erc-timestamp 1680332400 wrap-prefix #2# line-p= refix #11# erc-ctcp ACTION erc-command PRIVMSG) 500 506 (erc-timestamp 1680= 332400 wrap-prefix #2# line-prefix #11# erc-ctcp ACTION erc-command PRIVMSG= ) 507 508 (erc-timestamp 1680332400 wrap-prefix #2# line-prefix #12=3D(spac= e :width (- 27 (6))) erc-command PRIVMSG) 508 511 (erc-timestamp 1680332400= wrap-prefix #2# line-prefix #12# erc-command PRIVMSG) 511 518 (erc-timesta= mp 1680332400 wrap-prefix #2# line-prefix #12# erc-command PRIVMSG)) \ No newline at end of file --=20 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 20 Jul 2023 13:28:58 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jul 20 09:28:57 2023 Received: from localhost ([127.0.0.1]:58027 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qMTiA-0001jg-A8 for submit <at> debbugs.gnu.org; Thu, 20 Jul 2023 09:28:57 -0400 Received: from mail-108-mta28.mxroute.com ([136.175.108.28]:39203) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qMTi6-0001jU-0A for 60936 <at> debbugs.gnu.org; Thu, 20 Jul 2023 09:28:53 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta28.mxroute.com (ZoneMTA) with ESMTPSA id 189737d15df0004cef.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Thu, 20 Jul 2023 13:28:44 +0000 X-Zone-Loop: 508db40f9526ed5c1f985161e48dc2bfd61563535ee5 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=CENjDCSvNCJOTZH0ruSZmRVqC3/ZLWuA/4LhROcJXdI=; b=Rd8HVvGZ3MBb4DhTrUg8nUMDr4 o6YzllIjV19ygteLgtfh5+3PShOVxOd1sub0LWwFdHX12wAXOAJ4hdUasTb4chrD0LHfiug6YUlej mMWwT1THrfi0/HJNRAOAxrU34Gjjo3tkmGc4DP+ZloYpLSXUX7YuxXqWXPIwpP8t31FgxT3Bj+WhB dqOx8FXC2uk8J89QMmNywUGA7ISF3vPvWLv9v7ynMGHBmlZQnYxkosZVlR4GRVmpyTmg3kFyM+/u2 5pNHvQlLJ34VDUSGbCrukI43c+kj9CHMSubar9quqz3ha+2CEXgMVgbT8V7NW2PxzLimM0p64zG1E GY/mj/OQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87a5vsjb3q.fsf@HIDDEN> (J. P.'s message of "Wed, 19 Jul 2023 06:15:53 -0700") References: <87tu0nao77.fsf@HIDDEN> <87msztl4xu.fsf@HIDDEN> <87a5vsjb3q.fsf@HIDDEN> Date: Thu, 20 Jul 2023 06:28:41 -0700 Message-ID: <87351iiueu.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain v3 (left-margin enhancement). Extend stamp-only text properties to leading white space on right-sided stamps occupying their own line. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v2-v3.diff From 91fcae659fd6193475f5c92c95837072e8e717da Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 20 Jul 2023 05:39:13 -0700 Subject: [PATCH 0/1] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (1): [5.6] Make erc-fill-wrap work with left-sided stamps etc/ERC-NEWS | 20 +- lisp/erc/erc-backend.el | 23 +- lisp/erc/erc-compat.el | 1 + lisp/erc/erc-fill.el | 126 ++++++++--- lisp/erc/erc-stamp.el | 210 +++++++++++++----- lisp/erc/erc.el | 26 ++- test/lisp/erc/erc-fill-tests.el | 37 +++ test/lisp/erc/erc-stamp-tests.el | 29 ++- test/lisp/erc/erc-tests.el | 6 + .../fill/snapshots/stamps-left-01.eld | 1 + 10 files changed, 362 insertions(+), 117 deletions(-) create mode 100644 test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld Interdiff: diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 2369aeeabc2..13e49a9123d 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -225,7 +225,8 @@ Chiefly, 'rear-sticky' has been replaced by 'erc-command', which records the IRC command (or numeric) associated with a message. Less impactfully, the value of the 'field' property for ERC's prompt has changed from 't' to the more useful 'erc-prompt', although the -property of the same name has been retained. +property of the same name has been retained and now has a value of +'hidden' when disconnected. *** Members of insert- and send-related hooks have been reordered. Built-in and third-party modules rely on certain hooks for adjusting @@ -258,6 +259,16 @@ Additionally, the 'stamp' module now merges its 'invisible' property with existing ones, when present, and it includes all white space around stamps when doing so. +Moreover, such "propertizing" of surrounding white space now extends +to all 'stamp'-applied properties, like 'field', in all intervening +space between message text and timestamps. This constitutes a +breaking change from the perspective of detecting a timestamp's +bounds. For example, ERC has always propertized leading space before +right-sided stamps on the same line as message text but not those +folded onto the next line. This inconsistency made stamp detection +overly complex and produced uneven results when toggling stamp +visibility. + *** The role of a module's Custom group is now more clearly defined. Associating built-in modules with Custom groups and provided library features has improved. More specifically, a module's group now enjoys diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 6c2228f6337..2c5be590c60 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -355,28 +355,33 @@ fill-wrap "Fill style leveraging `visual-line-mode'. This local module displays nicks overhanging leftward to a common offset, as determined by the option `erc-fill-static-center'. It -depends on the `fill' and `button' modules and assumes users -who've defined their own `erc-insert-timestamp-function' have -also customized the option `erc-fill-wrap-margin-side' to an +depends on the `fill', `stamp', and `button' modules and assumes +users who've defined their own `erc-insert-timestamp-function' +have also customized the option `erc-fill-wrap-margin-side' to an explicit side. To use this module, either include `fill-wrap' in -`erc-modules' or set `erc-fill-function' to -`erc-fill-wrap' (recommended). You can also manually invoke one -of the minor-mode toggles if really necessary. - -When stamps appear in the right margin, which they do by default, -users may find that ERC actually appends them to copy-as-killed -messages without an intervening space. This normally poses at -most a minor nuisance, however users of the `log' module may -prefer a workaround provided by `erc-stamp-prefix-log-filter', -which strips trailing stamps from logged messages and instead -prepends them to every line." +`erc-modules' or set `erc-fill-function' to `erc-fill-wrap'. +Manually invoking one of the minor-mode toggles is not +recommended. + +This module imposes various restrictions on the appearance of +timestamps. Most notably, it insists on displaying them in the +margins. Users preferring left-sided stamps may notice that ERC +also displays the prompt in the left margin, possibly truncating +or padding it to constrain it to the margin's width. When stamps +appear in the right margin, which they do by default, users may +find that ERC actually appends them to copy-as-killed messages +without an intervening space. This normally poses at most a +minor inconvenience, however users of the `log' module may prefer +a workaround provided by `erc-stamp-prefix-log-filter', which +strips trailing stamps from logged messages and instead prepends +them to every line." ((erc-fill--wrap-ensure-dependencies) (erc--restore-initialize-priors erc-fill-wrap-mode erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys erc-fill--wrap-value erc-fill-static-center erc-stamp--margin-width erc-fill-wrap-margin-width - left-margin-width 0 - right-margin-width 0) + left-margin-width left-margin-width + right-margin-width right-margin-width) ;; Only give this a local binding if known for sure. (when erc-fill-wrap-margin-side (setq erc-stamp--margin-left-p @@ -384,8 +389,7 @@ fill-wrap (setq erc-fill--function #'erc-fill-wrap) (add-function :after (local 'erc-stamp--insert-date-function) #'erc-fill--wrap-stamp-insert-prefixed-date) - (when (or erc-stamp-mode (memq 'stamp erc-modules)) - (erc-stamp--display-margin-mode +1)) + (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)) @@ -393,16 +397,15 @@ fill-wrap (add-hook 'erc-button--prev-next-predicate-functions #'erc-fill--wrap-merged-button-p nil t)) (visual-line-mode +1)) - ((when erc-stamp--display-margin-mode - (erc-stamp--display-margin-mode -1)) + ((visual-line-mode -1) + (erc-stamp--display-margin-mode -1) (kill-local-variable 'erc-fill--wrap-value) (kill-local-variable 'erc-fill--function) (kill-local-variable 'erc-fill--wrap-visual-keys) (remove-hook 'erc-button--prev-next-predicate-functions #'erc-fill--wrap-merged-button-p t) (remove-function (local 'erc-stamp--insert-date-function) - #'erc-fill--wrap-stamp-insert-prefixed-date) - (visual-line-mode -1)) + #'erc-fill--wrap-stamp-insert-prefixed-date)) 'local) (defvar-local erc-fill--wrap-length-function nil diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index eff99766d81..f98e0b04426 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -404,7 +404,8 @@ erc-stamp--display-margin-mode #'erc-stamp--display-prompt-in-left-margin nil t))) (remove-function (local 'filter-buffer-substring-function) #'erc--remove-text-properties) - (add-hook 'erc-after-connect #'erc-stamp--init-margins-on-connect t) + (remove-hook 'erc-after-connect + #'erc-stamp--init-margins-on-connect t) (remove-hook 'erc--refresh-prompt-hook #'erc-stamp--display-prompt-in-left-margin t) (remove-hook 'erc--setup-buffer-hook @@ -413,7 +414,6 @@ erc-stamp--display-margin-mode 'left-margin-width 'right-margin-width)) (kill-local-variable 'fringes-outside-margins) - (kill-local-variable 'erc-stamp--margin-prompt-width) (kill-local-variable 'erc-stamp--margin-left-p) (kill-local-variable 'erc-stamp--margin-width) (when (eq (current-buffer) (window-buffer)) @@ -504,6 +504,12 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--omit-properties-on-folded-lines nil + "Skip properties before right stamps occupying their own line. +This escape hatch restores pre-5.6 behavior that left leading +white space alone (unpropertized) for right-sided stamps folded +onto their own line.") + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -572,7 +578,8 @@ erc-insert-timestamp-right (let ((s (+ erc-timestamp-use-align-to (string-width string)))) (put-text-property from (point) 'display `(space :align-to (- right ,s))))) - ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + ((guard (>= col pos)) (newline) (indent-to pos) + (when erc-stamp--omit-properties-on-folded-lines (setq from (point)))) (_ (indent-to pos))) (insert string) (dolist (p erc-stamp--inherited-props) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index f6de087a09a..c448416cd69 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -56,7 +56,7 @@ erc-stamp-tests--insert-right (advice-remove 'erc-format-timestamp 'ert-deftest--erc-timestamp-use-align-to))) -(ert-deftest erc-timestamp-use-align-to--nil () +(defun erc-stamp-tests--use-align-to--nil (compat) (erc-stamp-tests--insert-right (lambda () @@ -83,12 +83,20 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "twenty characters")) (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) - ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\[ (char-after (field-beginning (point))))) + ;; Field includes leading whitespace. + (should (eql (if compat ?\[ ?\n) + (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) -(ert-deftest erc-timestamp-use-align-to--t () +(ert-deftest erc-timestamp-use-align-to--nil () + (ert-info ("Field starts on stamp text (compat)") + (let ((erc-stamp--omit-properties-on-folded-lines t)) + (erc-stamp-tests--use-align-to--nil 'compat))) + (ert-info ("Field includes leaidng white space") + (erc-stamp-tests--use-align-to--nil nil))) + +(defun erc-stamp-tests--use-align-to--t (compat) (erc-stamp-tests--insert-right (lambda () @@ -110,10 +118,17 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) - ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (field-beginning (point))))) + ;; Field includes leading space. + (should (eql (if compat ?\[ ?\n) (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) +(ert-deftest erc-timestamp-use-align-to--t () + (ert-info ("Field starts on stamp text (compat)") + (let ((erc-stamp--omit-properties-on-folded-lines t)) + (erc-stamp-tests--use-align-to--t 'compat))) + (ert-info ("Field includes leaidng white space") + (erc-stamp-tests--use-align-to--t nil))) + (ert-deftest erc-timestamp-use-align-to--integer () (erc-stamp-tests--insert-right (lambda () -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Make-erc-fill-wrap-work-with-left-sided-stamps.patch Content-Transfer-Encoding: quoted-printable From 91fcae659fd6193475f5c92c95837072e8e717da Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 14 Jul 2023 06:12:30 -0700 Subject: [PATCH 1/1] [5.6] Make erc-fill-wrap work with left-sided stamps * etc/ERC-NEWS: Remove all mention of option `erc-timestamp-align-to' supporting a value of `margin', which has been abandoned. Mention expanded area around time stamps exhibiting stamp-related properties. * lisp/erc/erc-backend.el (erc--reveal-prompt, erc--conceal-prompt): New generic functions with default implementations factored out from `erc--unhide-prompt' and `erc--hide-prompt'. (erc--prompt-hidden-p): New internal predicate function. (erc--unhide-prompt): Defer to `erc--reveal-prompt' and set `erc-prompt' text property to t. (erc--hide-prompt): Defer to `erc--conceal-prompt' and set `erc-prompt' text property to `hidden'. * lisp/erc/erc-compat.el (erc-compat--29-browse-url-irc): Add FIXME comment for likely insufficient test of function equality. * lisp/erc/erc-fill.el (erc-fill-wrap-margin-width, erc-fill-wrap-margin-side): New options to control side and initial width of `fill-wrap' margin. (erc-fill--wrap-beginning-of-line): Fix bug involving non-string valued `display' props. (erc-fill-wrap-toggle-truncate-lines): New command to re-enable `visual-line-mode' when toggling off `truncate-lines'. (erc-fill-wrap-mode, erc-fill-wrap-enable): Update doc string, persist a few local vars, and conditionally set `erc-stamp--margin-left-p'. (erc-fill-wrap-nudge): Update doc string and account for left-hand stamps. (erc-timestamp-offset): Add comment regarding conditional guard based on function-valued option. * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Remove value variant `margin', which was originally intended to be new in ERC 5.6. This functionality was all but useless without the internal minor mode `erc-stamp--display-margin-mode' active. (erc-stamp-right-margin-width): Remove unused option new in 5.6. (erc-stamp--display-margin-force): Remove unused function. (erc-stamp--margin-width, erc-stamp--margin-left-p): New internal var. (erc-stamp--margin-left-p, erc-stamp--init-margins-on-connect): New functions for other modules that use `erc-stamp--display-margin-mode'. (erc-stamp--adjust-right-margin, erc-stamp--adjust-margin): Rename function to latter and accommodate left-hand stamps. (erc-stamp--inherited-props): Relocate from lower down in file. (erc-stamp--display-margin-mode): Update function name, and adjust setup and teardown to accommodate left-handed stamps. Don't add advice around `erc-insert-timestamp-function'. (erc-stamp--last-prompt, erc-stamp--display-prompt-in-left-margin): New function and helper var to convert a normal inserted prompt so that it appears in the left margin. (erc-stamp--refresh-left-margin-prompt): Helper for other modules to quickly refresh prompt outside of insert hooks. (erc--reveal-prompt, erc--conceal-prompt): New implementations for when `erc-stamp--display-margin-mode' is active. (erc-insert-timestamp-left): Convert to defmethod and provide implementation for `erc-stamp--display-margin-mode'. (erc-stamp--omit-properties-on-folded-lines): New variable, an escape hatch for propertizing white space before right-side stamps folded over onto another line. (erc-insert-timestamp-right): Don't expect `erc-timestamp-align-to' to ever be the symbol `margin'. Move handling for that case to one contingent on the internal minor mode `erc-stamp--display-margin-mode' being active. Add text properties preceding stamps folded over onto another line. See related news entry for rationale. This is arguably a breaking change. * lisp/erc/erc.el (erc--refresh-prompt-hook): New variable. (erc--refresh-prompt): Fix bug in which user-defined prompt functions failed to hide when quitting in server buffers. Run new hook `erc--refresh-prompt-hook'. (erc-display-prompt): Add comment noting that the text property `erc-prompt' now actually matters. It's t while a session is running and `hidden' when disconnected. * test/lisp/erc/erc-fill-tests.el (erc-fill--left-hand-stamps): New test. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--margin, erc-stamp--display-margin-mode--right): Rename test to latter. (erc-stamp-tests--use-align-to--nil, erc-stamp-tests--use-align-to--t): New functions to allow optionally asserting pre-5.6 behavior regarding leading white space on right-hand stamps that exist on their own line. (erc-timestamp-use-align-to--nil, ert-deftest erc-timestamp-use-align-to--t): Parameterize with compatibility flag. * test/lisp/erc/erc-tests.el (erc-hide-prompt): Add some assertions for new possible value of `erc-prompt' text property. * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: New test data file. (Bug#60936) --- etc/ERC-NEWS | 20 +- lisp/erc/erc-backend.el | 23 +- lisp/erc/erc-compat.el | 1 + lisp/erc/erc-fill.el | 126 ++++++++--- lisp/erc/erc-stamp.el | 210 +++++++++++++----- lisp/erc/erc.el | 26 ++- test/lisp/erc/erc-fill-tests.el | 37 +++ test/lisp/erc/erc-stamp-tests.el | 29 ++- test/lisp/erc/erc-tests.el | 6 + .../fill/snapshots/stamps-left-01.eld | 1 + 10 files changed, 362 insertions(+), 117 deletions(-) create mode 100644 test/lisp/erc/resources/fill/snapshots/stamps-left-01.e= ld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 4c881e32ab4..13e49a9123d 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -103,11 +103,8 @@ side window. Hit '<RET>' over a nick to spawn a "/QUE= RY" or a ** The option 'erc-timestamp-use-align-to' is more versatile. While this option has always offered to right-align stamps via the 'display' text property, it's now more effective at doing so when set -to a number indicating an offset from the right edge. And when set to -the symbol 'margin', it displays stamps in the right margin, although, -at the moment, this is mostly intended for use by other modules, such -as 'fill-wrap', described above. For both these variants, users of -the 'log' module may want to customize 'erc-log-filter-function' to +to a number indicating an offset from the right edge. Users of the +'log' module may want to customize 'erc-log-filter-function' to 'erc-stamp-prefix-log-filter' to avoid ragged right-hand stamps appearing in their saved logs. =20 @@ -228,7 +225,8 @@ Chiefly, 'rear-sticky' has been replaced by 'erc-comman= d', which records the IRC command (or numeric) associated with a message. Less impactfully, the value of the 'field' property for ERC's prompt has changed from 't' to the more useful 'erc-prompt', although the -property of the same name has been retained. +property of the same name has been retained and now has a value of +'hidden' when disconnected. =20 *** Members of insert- and send-related hooks have been reordered. Built-in and third-party modules rely on certain hooks for adjusting @@ -261,6 +259,16 @@ Additionally, the 'stamp' module now merges its 'invis= ible' property with existing ones, when present, and it includes all white space around stamps when doing so. =20 +Moreover, such "propertizing" of surrounding white space now extends +to all 'stamp'-applied properties, like 'field', in all intervening +space between message text and timestamps. This constitutes a +breaking change from the perspective of detecting a timestamp's +bounds. For example, ERC has always propertized leading space before +right-sided stamps on the same line as message text but not those +folded onto the next line. This inconsistency made stamp detection +overly complex and produced uneven results when toggling stamp +visibility. + *** The role of a module's Custom group is now more clearly defined. Associating built-in modules with Custom groups and provided library features has improved. More specifically, a module's group now enjoys diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 363509d17fa..eb3ec39fedd 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1045,13 +1045,25 @@ erc-process-sentinel-1 ;; unexpected disconnect (erc-process-sentinel-2 event buffer)))) =20 +(cl-defmethod erc--reveal-prompt () + (remove-text-properties erc-insert-marker erc-input-marker + '(display nil))) + +(cl-defmethod erc--conceal-prompt () + (add-text-properties erc-insert-marker (1- erc-input-marker) + `(display ,erc-prompt-hidden))) + +(defun erc--prompt-hidden-p () + (and (marker-position erc-insert-marker) + (eq (get-text-property erc-insert-marker 'erc-prompt) 'hidden))) + (defun erc--unhide-prompt () (remove-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert t) (when (and (marker-position erc-insert-marker) (marker-position erc-input-marker)) (with-silent-modifications - (remove-text-properties erc-insert-marker erc-input-marker - '(display nil))))) + (put-text-property erc-insert-marker (1- erc-input-marker) 'erc-prom= pt t) + (erc--reveal-prompt)))) =20 (defun erc--unhide-prompt-on-self-insert () (when (and (eq this-command #'self-insert-command) @@ -1059,6 +1071,8 @@ erc--unhide-prompt-on-self-insert (erc--unhide-prompt))) =20 (defun erc--hide-prompt (proc) + "Hide prompt in all buffers of server. +Change value of property `erc-prompt' from t to `hidden'." (erc-with-all-buffers-of-server proc nil (when (and erc-hide-prompt (or (eq erc-hide-prompt t) @@ -1072,8 +1086,9 @@ erc--hide-prompt (marker-position erc-input-marker) (get-text-property erc-insert-marker 'erc-prompt)) (with-silent-modifications - (add-text-properties erc-insert-marker (1- erc-input-marker) - `(display ,erc-prompt-hidden))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'erc-prompt 'hidden) + (erc--conceal-prompt)) (add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 91 t= )))) =20 (defun erc-process-sentinel (cproc event) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index f451aaee754..912a4bc576c 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -418,6 +418,7 @@ erc-compat--29-browse-url-irc (require 'url-irc) (let* ((url (url-generic-parse-url string)) (url-irc-function + ;; FIXME this should probably use `symbol-function'. (if (function-equal url-irc-function 'url-irc-erc) (lambda (host port chan user pass) (erc-handle-irc-url host port chan user pass (url-type url= ))) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index a65c95f1d85..2c5be590c60 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -116,6 +116,25 @@ erc-fill-column "The column at which a filled paragraph is broken." :type 'integer) =20 +(defcustom erc-fill-wrap-margin-width nil + "Starting width in columns of dedicated stamp margin. +When nil, ERC normally pretends its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +However, when `erc-fill-wrap-margin-side' is `left' or +\"resolves\" to `left', ERC uses the width of the prompt if it's +wider on MOTD's end, which really only matters when `erc-prompt' +is a function." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defcustom erc-fill-wrap-margin-side nil + "Margin side to use with `erc-fill-wrap-mode'. +A value of nil means ERC should decide based on the value of +`erc-insert-timestamp-function', which does not work for +user-defined functions." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) (const left) (const right))) + (defcustom erc-fill-line-spacing nil "Extra space between messages on graphical displays. This may need adjusting depending on how your faces are @@ -253,9 +272,9 @@ erc-fill--wrap-beginning-of-line (goto-char erc-input-marker) ;; Mimic what `move-beginning-of-line' does with invisible text. (when-let ((erc-fill-wrap-merge) - (empty (get-text-property (point) 'display)) - ((string-empty-p empty))) - (goto-char (text-property-not-all (point) (pos-eol) 'display empty))= ))) + (prop (get-text-property (point) 'display)) + ((or (equal prop "") (eq 'margin (car-safe (car-safe prop))= )))) + (goto-char (text-property-not-all (point) (pos-eol) 'display prop)))= )) =20 (defun erc-fill--wrap-end-of-line (arg) "Defer to `move-end-of-line' or `end-of-visual-line'." @@ -278,12 +297,29 @@ erc-fill-wrap-cycle-visual-movement ('non-input nil)))) (message "erc-fill-wrap movement: %S" erc-fill--wrap-visual-keys)) =20 +(defun erc-fill-wrap-toggle-truncate-lines (arg) + "Toggle `truncate-lines' and maybe reinstate `visual-line-mode'." + (interactive "P") + (let ((wantp (if arg + (natnump (prefix-numeric-value arg)) + (not truncate-lines))) + (buffer (current-buffer))) + (if wantp + (setq truncate-lines t) + (walk-windows (lambda (window) + (when (eq buffer (window-buffer window)) + (set-window-hscroll window 0))) + nil t) + (visual-line-mode +1))) + (force-mode-line-update)) + (defvar-keymap erc-fill-wrap-mode-map ; Compat 29 :doc "Keymap for ERC's `fill-wrap' module." :parent visual-line-mode-map "<remap> <kill-line>" #'erc-fill--wrap-kill-line "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "<remap> <toggle-truncate-lines>" #'erc-fill-wrap-toggle-truncate-lines "C-c a" #'erc-fill-wrap-cycle-visual-movement ;; Not sure if this is problematic because `erc-bol' takes no args. "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) @@ -319,25 +355,41 @@ fill-wrap "Fill style leveraging `visual-line-mode'. This local module displays nicks overhanging leftward to a common offset, as determined by the option `erc-fill-static-center'. It -depends on the `fill' and `button' modules and assumes the option -`erc-insert-timestamp-function' is `erc-insert-timestamp-right' -or the default `erc-insert-timestamp-left-and-right', so that it -can display right-hand stamps in the right margin. A value of -`erc-insert-timestamp-left' is unsupported. To use it, either -include `fill-wrap' in `erc-modules' or set `erc-fill-function' -to `erc-fill-wrap' (recommended). You can also manually invoke -one of the minor-mode toggles if really necessary." +depends on the `fill', `stamp', and `button' modules and assumes +users who've defined their own `erc-insert-timestamp-function' +have also customized the option `erc-fill-wrap-margin-side' to an +explicit side. To use this module, either include `fill-wrap' in +`erc-modules' or set `erc-fill-function' to `erc-fill-wrap'. +Manually invoking one of the minor-mode toggles is not +recommended. + +This module imposes various restrictions on the appearance of +timestamps. Most notably, it insists on displaying them in the +margins. Users preferring left-sided stamps may notice that ERC +also displays the prompt in the left margin, possibly truncating +or padding it to constrain it to the margin's width. When stamps +appear in the right margin, which they do by default, users may +find that ERC actually appends them to copy-as-killed messages +without an intervening space. This normally poses at most a +minor inconvenience, however users of the `log' module may prefer +a workaround provided by `erc-stamp-prefix-log-filter', which +strips trailing stamps from logged messages and instead prepends +them to every line." ((erc-fill--wrap-ensure-dependencies) - ;; Restore or initialize local state variables. (erc--restore-initialize-priors erc-fill-wrap-mode erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys - erc-fill--wrap-value erc-fill-static-center) + erc-fill--wrap-value erc-fill-static-center + erc-stamp--margin-width erc-fill-wrap-margin-width + left-margin-width left-margin-width + right-margin-width right-margin-width) + ;; Only give this a local binding if known for sure. + (when erc-fill-wrap-margin-side + (setq erc-stamp--margin-left-p + (pcase erc-fill-wrap-margin-side ('right nil) ('left t)))) (setq erc-fill--function #'erc-fill-wrap) - ;; Internal integrations. (add-function :after (local 'erc-stamp--insert-date-function) #'erc-fill--wrap-stamp-insert-prefixed-date) - (when (or erc-stamp-mode (memq 'stamp erc-modules)) - (erc-stamp--display-margin-mode +1)) + (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)) @@ -345,16 +397,15 @@ fill-wrap (add-hook 'erc-button--prev-next-predicate-functions #'erc-fill--wrap-merged-button-p nil t)) (visual-line-mode +1)) - ((when erc-stamp--display-margin-mode - (erc-stamp--display-margin-mode -1)) + ((visual-line-mode -1) + (erc-stamp--display-margin-mode -1) (kill-local-variable 'erc-fill--wrap-value) (kill-local-variable 'erc-fill--function) (kill-local-variable 'erc-fill--wrap-visual-keys) (remove-hook 'erc-button--prev-next-predicate-functions #'erc-fill--wrap-merged-button-p t) (remove-function (local 'erc-stamp--insert-date-function) - #'erc-fill--wrap-stamp-insert-prefixed-date) - (visual-line-mode -1)) + #'erc-fill--wrap-stamp-insert-prefixed-date)) 'local) =20 (defvar-local erc-fill--wrap-length-function nil @@ -381,18 +432,21 @@ erc-fill--wrap-continued-message-p (widen) (when (eq 'erc-timestamp (field-at-pos m)) (set-marker m (field-end m))) - (and (eq 'PRIVMSG (get-text-property m 'erc-command= )) - (not (eq (get-text-property m 'erc-ctcp) 'ACTI= ON)) - (cons (get-text-property m 'erc-timestamp) - (get-text-property (1+ m) 'erc-data))))) + (and-let* + (((eq 'PRIVMSG (get-text-property m 'erc-comman= d))) + ((not (eq (get-text-property m 'erc-ctcp) + 'ACTION))) + (spr (next-single-property-change m 'erc-speak= er))) + (cons (get-text-property m 'erc-timestamp) + (get-text-property spr 'erc-speaker))))) (ts (pop 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)) - (nick (buffer-substring-no-properties - (1+ (point-min)) (- (point) 2))) + (speaker (next-single-property-change (point-min) 'erc-speak= er)) + (nick (get-text-property speaker 'erc-speaker)) (props) - ((erc-nick-equal-p (car props) nick)))) + ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) =20 (defun erc-fill--wrap-stamp-insert-prefixed-date (&rest args) @@ -476,8 +530,8 @@ erc-fill-wrap-nudge \\`=3D' Increase indentation by one column \\`-' Decrease indentation by one column \\`0' Reset indentation to the default - \\`+' Shift right margin rightward (shrink) by one column - \\`_' Shift right margin leftward (grow) by one column + \\`+' Shift margin boundary rightward by one column + \\`_' Shift margin boundary leftward by one column \\`)' Reset the right margin to the default =20 Note that misalignment may occur when messages contain @@ -489,6 +543,7 @@ erc-fill-wrap-nudge (unless (get-buffer-window) (user-error "Command called in an undisplayed buffer")) (let* ((total (erc-fill--wrap-nudge arg)) + (leftp erc-stamp--margin-left-p) (win-ratio (/ (float (- (window-point) (window-start))) (- (window-end nil t) (window-start))))) (when (zerop arg) @@ -509,18 +564,20 @@ erc-fill-wrap-nudge (dolist (key '(?\) ?_ ?+)) (let ((a (pcase key (?\) 0) - (?_ (- (abs arg))) - (?+ (abs arg))))) + (?_ (if leftp (abs arg) (- (abs arg)))) + (?+ (if leftp (- (abs arg)) (abs arg)))))) (define-key map (vector (list key)) (lambda () (interactive) - (erc-stamp--adjust-right-margin (- a)) + (erc-stamp--adjust-margin (- a) (zerop a)) + (when leftp (erc-stamp--refresh-left-margin-promp= t)) (recenter (round (* win-ratio (window-height)))))= ))) map) t (lambda () - (message "Fill prefix: %d (%+d col%s)" - erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + (message "Fill prefix: %d (%+d col%s); Margin: %d" + erc-fill--wrap-value total (if (> (abs total) 1) "s" "") + (if leftp left-margin-width right-margin-width))) "Use %k for further adjustment" 1) (recenter (round (* win-ratio (window-height)))))) @@ -536,6 +593,7 @@ erc-timestamp-offset "Get length of timestamp if inserted left." (if (and (boundp 'erc-timestamp-format) erc-timestamp-format + ;; FIXME use a more robust test than symbol equivalence. (eq erc-insert-timestamp-function 'erc-insert-timestamp-left) (not erc-hide-timestamps)) (length (format-time-string erc-timestamp-format)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 83ee4a200ed..f98e0b04426 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -281,49 +281,67 @@ erc-timestamp-use-align-to set to `erc-insert-timestamp-right' or that option's default, `erc-insert-timestamp-left-and-right'. If the value is a positive integer, alignment occurs that many columns from the -right edge. If the value is `margin', the stamp appears in the -right margin when visible. +right edge. =20 Enabling this option produces a side effect in that stamps aren't indented in saved logs. When its value is an integer, this option adds a space after the end of a message if the stamp doesn't already start with one. And when its value is t, it adds -a single space, unconditionally. And while this option never -adds a space when its value is `margin', ERC does offer a -workaround in `erc-stamp-prefix-log-filter', which strips -trailing stamps from messages and puts them before every line." - :type '(choice boolean integer (const margin)) +a single space, unconditionally." + :type '(choice boolean integer) :package-version '(ERC . "5.6")) ; FIXME sync on release =20 -(defcustom erc-stamp-right-margin-width nil - "Width in columns of the right margin. -When this option is nil, pretend its value is one column greater -than the `string-width' of the formatted `erc-timestamp-format'. -This option only matters when `erc-timestamp-use-align-to' is set -to `margin'." - :package-version '(ERC . "5.6") ; FIXME sync on release - :type '(choice (const nil) integer)) - -(defun erc-stamp--display-margin-force (orig &rest r) - (let ((erc-timestamp-use-align-to 'margin)) - (apply orig r))) - -(defun erc-stamp--adjust-right-margin (cols) - "Adjust right margin by COLS. -When COLS is zero, reset width to `erc-stamp-right-margin-width' -or one col more than the `string-width' of -`erc-timestamp-format'." - (let ((width - (if (zerop cols) - (or erc-stamp-right-margin-width - (1+ (string-width (or erc-timestamp-last-inserted-right - (erc-format-timestamp - (current-time) - erc-timestamp-format))))) - (+ right-margin-width cols)))) - (setq right-margin-width width) +(defvar-local erc-stamp--margin-width nil + "Width in columns of margin for `erc-stamp--display-margin-mode'. +Only consulted when resetting or initializing margin.") + +(defvar-local erc-stamp--margin-left-p nil + "Whether `erc-stamp--display-margin-mode' uses the left margin. +During initialization, the mode respects this variable's existing +value if it already has a local binding. Otherwise, modules can +bind this to any value while enabling the mode. If it's nil, ERC +will check to see if `erc-insert-timestamp-function' is +`erc-insert-timestamp-left', interpreting the latter as a non-nil +value. It'll then coerce any non-nil value to t.") + +(defun erc-stamp--margin-left-p (&optional value) + (and (or value + (function-equal (symbol-function (default-value + 'erc-insert-timestamp-functio= n)) + (symbol-function 'erc-insert-timestamp-left))) + t)) + +(defun erc-stamp--init-margins-on-connect (&rest _) + (let ((existing (if erc-stamp--margin-left-p + left-margin-width + right-margin-width))) + (erc-stamp--adjust-margin existing 'resetp))) + +(defun erc-stamp--adjust-margin (cols &optional resetp) + "Adjust managed margin by increment COLS. +With RESETP, set margin's width to COLS. However, if COLS is +zero, set the width to a non-nil `erc-stamp--margin-width'. +Otherwise, go with the `string-width' of `erc-timestamp-format'. +However, when `erc-stamp--margin-left-p' is non-nil and the +prompt is wider, use its width instead." + (let* ((leftp erc-stamp--margin-left-p) + (width + (if resetp + (or (and (not (zerop cols)) cols) + erc-stamp--margin-width + (max (if leftp (string-width (erc-prompt)) 0) + (1+ (string-width + (or (if leftp + erc-timestamp-last-inserted + erc-timestamp-last-inserted-right) + (erc-format-timestamp + (current-time) erc-timestamp-format)))))) + (+ (if leftp left-margin-width right-margin-width) cols)))) + (set (if leftp 'left-margin-width 'right-margin-width) width) (when (eq (current-buffer) (window-buffer)) - (set-window-margins nil left-margin-width width)))) + (set-window-margins nil + (if leftp width left-margin-width) + (if leftp right-margin-width width))))) =20 ;;;###autoload (defun erc-stamp-prefix-log-filter (text) @@ -348,39 +366,101 @@ erc-stamp-prefix-log-filter (zerop (forward-line)))) "") =20 +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (declare-function erc--remove-text-properties "erc" (string)) =20 -;; If people want to use this directly, we can convert it into -;; a local module. +;; If people want to use this directly, we can convert it into a local +;; module. Also, `erc-insert-timestamp-right' hard codes its display +;; property to use `right-margin', and `erc-insert-timestamp-left' +;; does the same for `left-margin'. However, there's no reason a +;; trailing stamp couldn't be displayed on the left and vice versa. +;; Note: this adds advice that breaks `erc-timestamp-offset' because +;; the thinking is there's no use case in which that function would be +;; called while this mode is active. See note below for more. (define-minor-mode erc-stamp--display-margin-mode "Internal minor mode for built-in modules integrating with `stamp'. -It binds `erc-timestamp-use-align-to' to `margin' around calls to -`erc-insert-timestamp-function' in the current buffer, and sets -the right window margin to `erc-stamp-right-margin-width'. It -also arranges to remove most text properties when a user kills -message text so that stamps will be visible when yanked." +Manages chosen window margin and arranges to remove `display' +text properties in killed text to reveal stamps." :interactive nil (if erc-stamp--display-margin-mode (progn (setq fringes-outside-margins t) (when (eq (current-buffer) (window-buffer)) (set-window-buffer (selected-window) (current-buffer))) - (erc-stamp--adjust-right-margin 0) + (unless (local-variable-p 'erc-stamp--margin-left-p) + (setq erc-stamp--margin-left-p + (erc-stamp--margin-left-p erc-stamp--margin-left-p))) + (if (or erc-server-connected (not (functionp erc-prompt))) + (erc-stamp--init-margins-on-connect) + (add-hook 'erc-after-connect + #'erc-stamp--init-margins-on-connect nil t)) (add-function :filter-return (local 'filter-buffer-substring-funct= ion) #'erc--remove-text-properties) - (add-function :around (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force)) + (add-hook 'erc--setup-buffer-hook + #'erc-stamp--refresh-left-margin-prompt nil t) + (when erc-stamp--margin-left-p + (add-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin nil t))) (remove-function (local 'filter-buffer-substring-function) #'erc--remove-text-properties) - (remove-function (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force) - (kill-local-variable 'right-margin-width) + (remove-hook 'erc-after-connect + #'erc-stamp--init-margins-on-connect t) + (remove-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin t) + (remove-hook 'erc--setup-buffer-hook + #'erc-stamp--refresh-left-margin-prompt t) + (kill-local-variable (if erc-stamp--margin-left-p + 'left-margin-width + 'right-margin-width)) (kill-local-variable 'fringes-outside-margins) + (kill-local-variable 'erc-stamp--margin-left-p) + (kill-local-variable 'erc-stamp--margin-width) (when (eq (current-buffer) (window-buffer)) (set-window-margins nil left-margin-width nil) (set-window-buffer (selected-window) (current-buffer))))) =20 -(defun erc-insert-timestamp-left (string) +(defvar-local erc-stamp--last-prompt nil) + +(defun erc-stamp--display-prompt-in-left-margin () + "Show prompt in the left margin with padding." + (when (or (not erc-stamp--last-prompt) (functionp erc-prompt) + (> (string-width erc-stamp--last-prompt) left-margin-width)) + (let ((s (buffer-substring erc-insert-marker (1- erc-input-marker)))) + ;; Prevent #("abc" n m (display ((...) #("abc" p q (display...)))) + (remove-text-properties 0 (length s) '(display nil) s) + (when (and erc-stamp--last-prompt + (>=3D (string-width erc-stamp--last-prompt) left-margin-w= idth)) + (let ((sm (truncate-string-to-width s (1- left-margin-width) 0 nil= t))) + ;; This papers over a subtle off-by-1 bug here. + (unless (equal sm s) + (setq s (concat sm (substring s -1)))))) + (setq erc-stamp--last-prompt (string-pad s left-margin-width nil t))= )) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt)) + erc-stamp--last-prompt) + +(defun erc-stamp--refresh-left-margin-prompt () + "Forcefully-recompute display property of prompt in left margin." + (with-silent-modifications + (unless (functionp erc-prompt) + (setq erc-stamp--last-prompt nil)) + (erc--refresh-prompt))) + +(cl-defmethod erc--reveal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt))) + +(cl-defmethod erc--conceal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (let ((prompt (string-pad erc-prompt-hidden left-margin-width nil 'start= ))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,prompt)))) + +(cl-defmethod erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." (goto-char (point-min)) (let* ((ignore-p (and erc-timestamp-only-if-changed-flag @@ -392,6 +472,22 @@ erc-insert-timestamp-left (erc-put-text-property 0 len 'invisible erc-stamp--invisible-property = s) (insert s))) =20 +(cl-defmethod erc-insert-timestamp-left + (string &context (erc-stamp--display-margin-mode (eql t))) + (unless (and erc-timestamp-only-if-changed-flag + (string-equal string erc-timestamp-last-inserted)) + (goto-char (point-min)) + (insert-before-markers-and-inherit + (setq erc-timestamp-last-inserted string)) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (point) p))) + (put-text-property (point-min) (point) p v))) + (erc-put-text-property (point-min) (point) 'invisible + erc-stamp--invisible-property) + (put-text-property (point-min) (point) 'field 'erc-timestamp) + (put-text-property (point-min) (point) + 'display `((margin left-margin) ,string)))) + (defun erc-insert-aligned (string pos) "Insert STRING at the POSth column. =20 @@ -408,7 +504,11 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) =20 -(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) +(defvar erc-stamp--omit-properties-on-folded-lines nil + "Skip properties before right stamps occupying their own line. +This escape hatch restores pre-5.6 behavior that left leading +white space alone (unpropertized) for right-sided stamps folded +onto their own line.") =20 (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. @@ -465,6 +565,9 @@ erc-insert-timestamp-right ;; For compatibility reasons, the `erc-timestamp' field includes ;; intervening white space unless a hard break is warranted. (pcase erc-timestamp-use-align-to + ((guard erc-stamp--display-margin-mode) + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) stri= ng)) ((and 't (guard (< col pos))) (insert " ") (put-text-property from (point) 'display `(space :align-to ,pos))) @@ -475,11 +578,8 @@ erc-insert-timestamp-right (let ((s (+ erc-timestamp-use-align-to (string-width string)))) (put-text-property from (point) 'display `(space :align-to (- right ,s))))) - ('margin - (put-text-property 0 (length string) - 'display `((margin right-margin) ,string) - string)) - ((guard (>=3D col pos)) (newline) (indent-to pos) (setq from (poin= t))) + ((guard (>=3D col pos)) (newline) (indent-to pos) + (when erc-stamp--omit-properties-on-folded-lines (setq from (poin= t)))) (_ (indent-to pos))) (insert string) (dolist (p erc-stamp--inherited-props) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index eca6a90d706..d519bf221b9 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2879,19 +2879,23 @@ erc--assert-input-bounds (cl-assert (< erc-insert-marker erc-input-marker)) (cl-assert (=3D (field-end erc-insert-marker) erc-input-marker))= ))) =20 +(defvar erc--refresh-prompt-hook nil) + (defun erc--refresh-prompt () "Re-render ERC's prompt when the option `erc-prompt' is a function." (erc--assert-input-bounds) - (when (functionp erc-prompt) - (save-excursion - (goto-char erc-insert-marker) - (set-marker-insertion-type erc-insert-marker nil) - ;; Avoid `erc-prompt' (the named function), which appends a - ;; space, and `erc-display-prompt', which propertizes all but - ;; that space. - (insert-and-inherit (funcall erc-prompt)) - (set-marker-insertion-type erc-insert-marker t) - (delete-region (point) (1- erc-input-marker))))) + (unless (erc--prompt-hidden-p) + (when (functionp erc-prompt) + (save-excursion + (goto-char erc-insert-marker) + (set-marker-insertion-type erc-insert-marker nil) + ;; Avoid `erc-prompt' (the named function), which appends a + ;; space, and `erc-display-prompt', which propertizes all but + ;; that space. + (insert-and-inherit (funcall erc-prompt)) + (set-marker-insertion-type erc-insert-marker t) + (delete-region (point) (1- erc-input-marker)))) + (run-hooks 'erc--refresh-prompt-hook))) =20 (defun erc-display-line-1 (string buffer) "Display STRING in `erc-mode' BUFFER. @@ -4804,7 +4808,7 @@ erc-display-prompt ;; shall remain part of the prompt. (setq prompt (propertize prompt 'rear-nonsticky t - 'erc-prompt t + 'erc-prompt t ; t or `hidden' 'field 'erc-prompt 'front-sticky t 'read-only t)) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index 99ec4a9635e..67622da9f3d 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -340,4 +340,41 @@ erc-fill-wrap-visual-keys--prompt (should (search-backward "ERC> " nil t)) (execute-kbd-macro "\C-a"))))) =20 +(ert-deftest erc-fill--left-hand-stamps () + :tags '(:unstable) + (unless (>=3D emacs-major-version 29) + (ert-skip "Emacs version too low, missing `buffer-text-pixel-size'")) + + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-insert-timestamp-function #'erc-insert-timestamp-left)) + (erc-fill-tests--wrap-populate + (lambda () + (should (=3D 8 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 4 8 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face))))) + (erc-fill-tests--compare "stamps-left-01") + + (ert-info ("Shrink left margin by 1 col") + (erc-stamp--adjust-margin -1) + (with-silent-modifications (erc--refresh-prompt)) + (should (=3D 7 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 3 7 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face)))))))))) + ;;; erc-fill-tests.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tes= ts.el index 6da7ed4503d..c448416cd69 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -56,7 +56,7 @@ erc-stamp-tests--insert-right (advice-remove 'erc-format-timestamp 'ert-deftest--erc-timestamp-use-align-to))) =20 -(ert-deftest erc-timestamp-use-align-to--nil () +(defun erc-stamp-tests--use-align-to--nil (compat) (erc-stamp-tests--insert-right (lambda () =20 @@ -83,12 +83,20 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "twenty characters")) (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) - ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\[ (char-after (field-beginning (point))))) + ;; Field includes leading whitespace. + (should (eql (if compat ?\[ ?\n) + (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) =20 -(ert-deftest erc-timestamp-use-align-to--t () +(ert-deftest erc-timestamp-use-align-to--nil () + (ert-info ("Field starts on stamp text (compat)") + (let ((erc-stamp--omit-properties-on-folded-lines t)) + (erc-stamp-tests--use-align-to--nil 'compat))) + (ert-info ("Field includes leaidng white space") + (erc-stamp-tests--use-align-to--nil nil))) + +(defun erc-stamp-tests--use-align-to--t (compat) (erc-stamp-tests--insert-right (lambda () =20 @@ -110,10 +118,17 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) - ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (field-beginning (point))))) + ;; Field includes leading space. + (should (eql (if compat ?\[ ?\n) (char-after (field-beginning (poin= t))))) (should (eql ?\n (char-after (field-end (point))))))))) =20 +(ert-deftest erc-timestamp-use-align-to--t () + (ert-info ("Field starts on stamp text (compat)") + (let ((erc-stamp--omit-properties-on-folded-lines t)) + (erc-stamp-tests--use-align-to--t 'compat))) + (ert-info ("Field includes leaidng white space") + (erc-stamp-tests--use-align-to--t nil))) + (ert-deftest erc-timestamp-use-align-to--integer () (erc-stamp-tests--insert-right (lambda () @@ -140,7 +155,7 @@ erc-timestamp-use-align-to--integer (should (eql ?\s (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) =20 -(ert-deftest erc-timestamp-use-align-to--margin () +(ert-deftest erc-stamp--display-margin-mode--right () (erc-stamp-tests--insert-right (lambda () (erc-stamp--display-margin-mode +1) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b5db5fe8764..fff3c4cb704 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -219,6 +219,7 @@ erc-hide-prompt (setq erc-hide-prompt '(server)) (with-current-buffer "ServNet" (erc--hide-prompt erc-server-process) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay)))) =20 (with-current-buffer "#chan" @@ -229,6 +230,7 @@ erc-hide-prompt =20 (with-current-buffer "ServNet" (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: channel") @@ -242,7 +244,9 @@ erc-hide-prompt =20 (with-current-buffer "#chan" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: query") @@ -253,7 +257,9 @@ erc-hide-prompt =20 (with-current-buffer "bob" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display))) =20 (with-current-buffer "#chan" diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld new file mode 100644 index 00000000000..f62b65cd170 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -0,0 +1 @@ +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 9 (erc= -timestamp 0 display (#4=3D(margin left-margin) #("[00:00]" 0 7 (invisible = timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-pre= fix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 27 (4)))) 9 17= 1 (erc-timestamp 0 wrap-prefix #1# line-prefix #2#) 172 179 (erc-timestamp = 0 display (#4# #("[00:00]" 0 7 (invisible timestamp font-lock-face erc-time= stamp-face))) field erc-timestamp wrap-prefix #1# line-prefix #3=3D(space := width (- 27 (8)))) 179 180 (erc-timestamp 0 wrap-prefix #1# line-prefix #3#= erc-command PRIVMSG) 180 185 (erc-timestamp 0 wrap-prefix #1# line-prefix = #3# erc-command PRIVMSG) 185 187 (erc-timestamp 0 wrap-prefix #1# line-pref= ix #3# erc-command PRIVMSG) 187 190 (erc-timestamp 0 wrap-prefix #1# line-p= refix #3# erc-command PRIVMSG) 190 303 (erc-timestamp 0 wrap-prefix #1# lin= e-prefix #3# erc-command PRIVMSG) 303 304 (erc-timestamp 0 erc-command PRIV= MSG) 304 336 (erc-timestamp 0 wrap-prefix #1# line-prefix #3# erc-command P= RIVMSG) 337 344 (erc-timestamp 0 display (#4# #("[00:00]" 0 7 (invisible ti= mestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefi= x #1# line-prefix #5=3D(space :width (- 27 (6)))) 344 345 (erc-timestamp 0 = wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 345 348 (erc-timestamp= 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 348 350 (erc-timest= amp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 350 355 (erc-tim= estamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 355 430 (erc-= timestamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file --=20 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 19 Jul 2023 13:16:06 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jul 19 09:16:06 2023 Received: from localhost ([127.0.0.1]:55198 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qM72C-0008Fb-Cq for submit <at> debbugs.gnu.org; Wed, 19 Jul 2023 09:16:06 -0400 Received: from mail-108-mta194.mxroute.com ([136.175.108.194]:33739) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qM728-0008Ec-KY for 60936 <at> debbugs.gnu.org; Wed, 19 Jul 2023 09:16:03 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta194.mxroute.com (ZoneMTA) with ESMTPSA id 1896e4b08030004cef.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 19 Jul 2023 13:15:58 +0000 X-Zone-Loop: 709e818877d21c638b32f8feb40add9fe534e618dea8 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=f/20YFL0U1g8m/mQCZgjpWYVtd/kY9Oi8m94wCdSjJE=; b=lX3VeuoXcjIOTD9PhXoOSmkh2u +nfelxsbZxu1uw5UIPZI6hBouDuG7DGk+hEOecPLqis49J7/J1o8CRrp7kya4sqxVDq0UXJsM4hkd 748eeF0i95CBqGo3Wh8zvz31tImtOBcHjPr68tYyR5OfTxroVfSaxr52fMOeuAlXqvbBP4ety4ZXG nzsON2QmkxLuBjA4xlQoSGIj0FYRWudMvK0g5MHiAIquMOw7I0Wl0evW2qDZ/QuMbYwq6/vTefFKh 3vG02lEHrpDd3Nu78sbVAF6a3abaAZX8l63bYfXAK8hyO2ALAOuyCVE70pSwy7cXY79UUWFWvX+tn b3c4xYjA==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87msztl4xu.fsf@HIDDEN> (J. P.'s message of "Tue, 18 Jul 2023 06:33:49 -0700") References: <87tu0nao77.fsf@HIDDEN> <87msztl4xu.fsf@HIDDEN> Date: Wed, 19 Jul 2023 06:15:53 -0700 Message-ID: <87a5vsjb3q.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain v2 (left-margin enhancement). Merge subsequent messages from a status-prefixed speaker. Fix prompt not appearing in left margin on /QUERY. Fix `visual-line-mode' not being restored after toggling off `truncate-lines'. Have `erc-fill-wrap-nudge' print margin width. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v1-v2.diff From a6ad80553d5ef1d332de3a1e4bbdf85eaf36b1fc Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 19 Jul 2023 06:00:55 -0700 Subject: [PATCH 0/1] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (1): [5.6] Make erc-fill-wrap work with left-hand stamps etc/ERC-NEWS | 7 +- lisp/erc/erc-backend.el | 23 +- lisp/erc/erc-compat.el | 1 + lisp/erc/erc-fill.el | 111 +++++++--- lisp/erc/erc-stamp.el | 203 +++++++++++++----- lisp/erc/erc.el | 26 ++- test/lisp/erc/erc-fill-tests.el | 37 ++++ test/lisp/erc/erc-stamp-tests.el | 2 +- test/lisp/erc/erc-tests.el | 6 + .../fill/snapshots/stamps-left-01.eld | 1 + 10 files changed, 313 insertions(+), 104 deletions(-) create mode 100644 test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld Interdiff: diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 9f39f41133d..6c2228f6337 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -129,8 +129,8 @@ erc-fill-wrap-margin-width (defcustom erc-fill-wrap-margin-side nil "Margin side to use with `erc-fill-wrap-mode'. -A value of nil means ERC should decide based on -`erc-insert-timestamp-function', which obviously cannot work for +A value of nil means ERC should decide based on the value of +`erc-insert-timestamp-function', which does not work for user-defined functions." :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (const left) (const right))) @@ -297,12 +297,29 @@ erc-fill-wrap-cycle-visual-movement ('non-input nil)))) (message "erc-fill-wrap movement: %S" erc-fill--wrap-visual-keys)) +(defun erc-fill-wrap-toggle-truncate-lines (arg) + "Toggle `truncate-lines' and maybe reinstate `visual-line-mode'." + (interactive "P") + (let ((wantp (if arg + (natnump (prefix-numeric-value arg)) + (not truncate-lines))) + (buffer (current-buffer))) + (if wantp + (setq truncate-lines t) + (walk-windows (lambda (window) + (when (eq buffer (window-buffer window)) + (set-window-hscroll window 0))) + nil t) + (visual-line-mode +1))) + (force-mode-line-update)) + (defvar-keymap erc-fill-wrap-mode-map ; Compat 29 :doc "Keymap for ERC's `fill-wrap' module." :parent visual-line-mode-map "<remap> <kill-line>" #'erc-fill--wrap-kill-line "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "<remap> <toggle-truncate-lines>" #'erc-fill-wrap-toggle-truncate-lines "C-c a" #'erc-fill-wrap-cycle-visual-movement ;; Not sure if this is problematic because `erc-bol' takes no args. "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) @@ -361,9 +378,9 @@ fill-wrap left-margin-width 0 right-margin-width 0) ;; Only give this a local binding if known for sure. - (pcase erc-fill-wrap-margin-side - ('right (setq erc-stamp--margin-left-p nil)) - ('left (setq erc-stamp--margin-left-p t))) + (when erc-fill-wrap-margin-side + (setq erc-stamp--margin-left-p + (pcase erc-fill-wrap-margin-side ('right nil) ('left t)))) (setq erc-fill--function #'erc-fill-wrap) (add-function :after (local 'erc-stamp--insert-date-function) #'erc-fill--wrap-stamp-insert-prefixed-date) @@ -412,18 +429,21 @@ erc-fill--wrap-continued-message-p (widen) (when (eq 'erc-timestamp (field-at-pos m)) (set-marker m (field-end m))) - (and (eq 'PRIVMSG (get-text-property m 'erc-command)) - (not (eq (get-text-property m 'erc-ctcp) 'ACTION)) - (cons (get-text-property m 'erc-timestamp) - (get-text-property (1+ m) 'erc-data))))) + (and-let* + (((eq 'PRIVMSG (get-text-property m 'erc-command))) + ((not (eq (get-text-property m 'erc-ctcp) + 'ACTION))) + (spr (next-single-property-change m 'erc-speaker))) + (cons (get-text-property m 'erc-timestamp) + (get-text-property spr 'erc-speaker))))) (ts (pop 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)) - (nick (buffer-substring-no-properties - (1+ (point-min)) (- (point) 2))) + (speaker (next-single-property-change (point-min) 'erc-speaker)) + (nick (get-text-property speaker 'erc-speaker)) (props) - ((erc-nick-equal-p (car props) nick)))) + ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) (defun erc-fill--wrap-stamp-insert-prefixed-date (&rest args) @@ -520,6 +540,7 @@ erc-fill-wrap-nudge (unless (get-buffer-window) (user-error "Command called in an undisplayed buffer")) (let* ((total (erc-fill--wrap-nudge arg)) + (leftp erc-stamp--margin-left-p) (win-ratio (/ (float (- (window-point) (window-start))) (- (window-end nil t) (window-start))))) (when (zerop arg) @@ -538,11 +559,10 @@ erc-fill-wrap-nudge (cl-incf total (erc-fill--wrap-nudge a)) (recenter (round (* win-ratio (window-height)))))))) (dolist (key '(?\) ?_ ?+)) - (let* ((leftp erc-stamp--margin-left-p) - (a (pcase key - (?\) 0) - (?_ (if leftp (abs arg) (- (abs arg)))) - (?+ (if leftp (- (abs arg)) (abs arg)))))) + (let ((a (pcase key + (?\) 0) + (?_ (if leftp (abs arg) (- (abs arg)))) + (?+ (if leftp (- (abs arg)) (abs arg)))))) (define-key map (vector (list key)) (lambda () (interactive) @@ -552,8 +572,9 @@ erc-fill-wrap-nudge map) t (lambda () - (message "Fill prefix: %d (%+d col%s)" - erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + (message "Fill prefix: %d (%+d col%s); Margin: %d" + erc-fill--wrap-value total (if (> (abs total) 1) "s" "") + (if leftp left-margin-width right-margin-width))) "Use %k for further adjustment" 1) (recenter (round (* win-ratio (window-height)))))) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 727d334f13b..eff99766d81 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -397,6 +397,8 @@ erc-stamp--display-margin-mode #'erc-stamp--init-margins-on-connect nil t)) (add-function :filter-return (local 'filter-buffer-substring-function) #'erc--remove-text-properties) + (add-hook 'erc--setup-buffer-hook + #'erc-stamp--refresh-left-margin-prompt nil t) (when erc-stamp--margin-left-p (add-hook 'erc--refresh-prompt-hook #'erc-stamp--display-prompt-in-left-margin nil t))) @@ -405,6 +407,8 @@ erc-stamp--display-margin-mode (add-hook 'erc-after-connect #'erc-stamp--init-margins-on-connect t) (remove-hook 'erc--refresh-prompt-hook #'erc-stamp--display-prompt-in-left-margin t) + (remove-hook 'erc--setup-buffer-hook + #'erc-stamp--refresh-left-margin-prompt t) (kill-local-variable (if erc-stamp--margin-left-p 'left-margin-width 'right-margin-width)) -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Make-erc-fill-wrap-work-with-left-hand-stamps.patch Content-Transfer-Encoding: quoted-printable From a6ad80553d5ef1d332de3a1e4bbdf85eaf36b1fc Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 14 Jul 2023 06:12:30 -0700 Subject: [PATCH 1/1] [5.6] Make erc-fill-wrap work with left-hand stamps * etc/ERC-NEWS: Remove all mention of option `erc-timestamp-align-to' supporting a value of `margin', which has been removed. * lisp/erc/erc-backend.el (erc--reveal-prompt, erc--conceal-prompt): New generic functions with default implementations factored out from `erc--unhide-prompt' and `erc--hide-prompt'. (erc--prompt-hidden-p): New internal predicate function. (erc--unhide-prompt): Defer to `erc--reveal-prompt' and set `erc-prompt' text property to t. (erc--hide-prompt): Defer to `erc--conceal-prompt' and set `erc-prompt' text property to `hidden'. * lisp/erc/erc-compat.el (erc-compat--29-browse-url-irc): Add FIXME comment for likely insufficient test of function equality. * lisp/erc/erc-fill.el (erc-fill-wrap-margin-width, erc-fill-wrap-margin-side): New options to control side and initial width of `fill-wrap' margin. (erc-fill--wrap-beginning-of-line): Fix bug involving non-string valued `display' props. (erc-fill-wrap-toggle-truncate-lines): New command to re-enable `visual-line-mode' when toggling off `truncate-lines'. (erc-fill-wrap-mode, erc-fill-wrap-enable): Update doc string, persist a few local vars, and conditionally set `erc-stamp--margin-left-p'. (erc-fill-wrap-nudge): Update doc string and account for left-hand stamps. (erc-timestamp-offset): Add comment regarding conditional guard based on function-valued option. * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Remove value variant `margin', which was originally intended to be new in ERC 5.6. This functionality was all but useless without the internal minor mode `erc-stamp--display-margin-mode' active. (erc-stamp-right-margin-width): Remove unused option new in 5.6. (erc-stamp--display-margin-force): Remove unused function. (erc-stamp--margin-width, erc-stamp--margin-left-p): New internal var. (erc-stamp--margin-left-p, erc-stamp--init-margins-on-connect): New functions for other modules that use `erc-stamp--display-margin-mode'. (erc-stamp--adjust-right-margin, erc-stamp--adjust-margin): Rename function to latter and accommodate left-hand stamps. (erc-stamp--inherited-props): Relocate from lower down in file. (erc-stamp--display-margin-mode): Update function name, and adjust setup and teardown to accommodate left-handed stamps. Don't add advice around `erc-insert-timestamp-function'. (erc-stamp--last-prompt, erc-stamp--display-prompt-in-left-margin): New function and helper var to convert a normal inserted prompt so that it appears in the left margin. (erc-stamp--refresh-left-margin-prompt): Helper for other modules to quickly refresh prompt outside of insert hooks. (erc--reveal-prompt, erc--conceal-prompt): New implementations for when `erc-stamp--display-margin-mode' is active. (erc-insert-timestamp-left): Convert to defmethod and provide implementation for `erc-stamp--display-margin-mode'. (erc-insert-timestamp-right): Don't expect `erc-timestamp-align-to' to ever be the symbol `margin'. Move handling for that case to one contingent on the internal minor mode `erc-stamp--display-margin-mode' being active. * lisp/erc/erc.el (erc--refresh-prompt-hook): New variable. (erc--refresh-prompt): Fix bug in which user-defined prompt functions failed to hide when quitting in server buffers. Run new hook `erc--refresh-prompt-hook'. (erc-display-prompt): Add comment noting that the text property `erc-prompt' now actually matters. It's t while a session is running and `hidden' when disconnected. * test/lisp/erc/erc-fill-tests.el (erc-fill--left-hand-stamps): New test. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--margin, erc-stamp--display-margin-mode--right): Rename test to latter. * test/lisp/erc/erc-tests.el (erc-hide-prompt): Add some assertions for new possible value of `erc-prompt' text property. * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: New test data file. (Bug#60936) --- etc/ERC-NEWS | 7 +- lisp/erc/erc-backend.el | 23 +- lisp/erc/erc-compat.el | 1 + lisp/erc/erc-fill.el | 111 +++++++--- lisp/erc/erc-stamp.el | 203 +++++++++++++----- lisp/erc/erc.el | 26 ++- test/lisp/erc/erc-fill-tests.el | 37 ++++ test/lisp/erc/erc-stamp-tests.el | 2 +- test/lisp/erc/erc-tests.el | 6 + .../fill/snapshots/stamps-left-01.eld | 1 + 10 files changed, 313 insertions(+), 104 deletions(-) create mode 100644 test/lisp/erc/resources/fill/snapshots/stamps-left-01.e= ld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index cd0b8e5f823..379d5eb2ad0 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -102,11 +102,8 @@ side window. Hit '<RET>' over a nick to spawn a "/QUE= RY" or a ** The option 'erc-timestamp-use-align-to' is more versatile. While this option has always offered to right-align stamps via the 'display' text property, it's now more effective at doing so when set -to a number indicating an offset from the right edge. And when set to -the symbol 'margin', it displays stamps in the right margin, although, -at the moment, this is mostly intended for use by other modules, such -as 'fill-wrap', described above. For both these variants, users of -the 'log' module may want to customize 'erc-log-filter-function' to +to a number indicating an offset from the right edge. Users of the +'log' module may want to customize 'erc-log-filter-function' to 'erc-stamp-prefix-log-filter' to avoid ragged right-hand stamps appearing in their saved logs. =20 diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 363509d17fa..eb3ec39fedd 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1045,13 +1045,25 @@ erc-process-sentinel-1 ;; unexpected disconnect (erc-process-sentinel-2 event buffer)))) =20 +(cl-defmethod erc--reveal-prompt () + (remove-text-properties erc-insert-marker erc-input-marker + '(display nil))) + +(cl-defmethod erc--conceal-prompt () + (add-text-properties erc-insert-marker (1- erc-input-marker) + `(display ,erc-prompt-hidden))) + +(defun erc--prompt-hidden-p () + (and (marker-position erc-insert-marker) + (eq (get-text-property erc-insert-marker 'erc-prompt) 'hidden))) + (defun erc--unhide-prompt () (remove-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert t) (when (and (marker-position erc-insert-marker) (marker-position erc-input-marker)) (with-silent-modifications - (remove-text-properties erc-insert-marker erc-input-marker - '(display nil))))) + (put-text-property erc-insert-marker (1- erc-input-marker) 'erc-prom= pt t) + (erc--reveal-prompt)))) =20 (defun erc--unhide-prompt-on-self-insert () (when (and (eq this-command #'self-insert-command) @@ -1059,6 +1071,8 @@ erc--unhide-prompt-on-self-insert (erc--unhide-prompt))) =20 (defun erc--hide-prompt (proc) + "Hide prompt in all buffers of server. +Change value of property `erc-prompt' from t to `hidden'." (erc-with-all-buffers-of-server proc nil (when (and erc-hide-prompt (or (eq erc-hide-prompt t) @@ -1072,8 +1086,9 @@ erc--hide-prompt (marker-position erc-input-marker) (get-text-property erc-insert-marker 'erc-prompt)) (with-silent-modifications - (add-text-properties erc-insert-marker (1- erc-input-marker) - `(display ,erc-prompt-hidden))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'erc-prompt 'hidden) + (erc--conceal-prompt)) (add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 91 t= )))) =20 (defun erc-process-sentinel (cproc event) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index f451aaee754..912a4bc576c 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -418,6 +418,7 @@ erc-compat--29-browse-url-irc (require 'url-irc) (let* ((url (url-generic-parse-url string)) (url-irc-function + ;; FIXME this should probably use `symbol-function'. (if (function-equal url-irc-function 'url-irc-erc) (lambda (host port chan user pass) (erc-handle-irc-url host port chan user pass (url-type url= ))) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index a65c95f1d85..6c2228f6337 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -116,6 +116,25 @@ erc-fill-column "The column at which a filled paragraph is broken." :type 'integer) =20 +(defcustom erc-fill-wrap-margin-width nil + "Starting width in columns of dedicated stamp margin. +When nil, ERC normally pretends its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +However, when `erc-fill-wrap-margin-side' is `left' or +\"resolves\" to `left', ERC uses the width of the prompt if it's +wider on MOTD's end, which really only matters when `erc-prompt' +is a function." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defcustom erc-fill-wrap-margin-side nil + "Margin side to use with `erc-fill-wrap-mode'. +A value of nil means ERC should decide based on the value of +`erc-insert-timestamp-function', which does not work for +user-defined functions." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) (const left) (const right))) + (defcustom erc-fill-line-spacing nil "Extra space between messages on graphical displays. This may need adjusting depending on how your faces are @@ -253,9 +272,9 @@ erc-fill--wrap-beginning-of-line (goto-char erc-input-marker) ;; Mimic what `move-beginning-of-line' does with invisible text. (when-let ((erc-fill-wrap-merge) - (empty (get-text-property (point) 'display)) - ((string-empty-p empty))) - (goto-char (text-property-not-all (point) (pos-eol) 'display empty))= ))) + (prop (get-text-property (point) 'display)) + ((or (equal prop "") (eq 'margin (car-safe (car-safe prop))= )))) + (goto-char (text-property-not-all (point) (pos-eol) 'display prop)))= )) =20 (defun erc-fill--wrap-end-of-line (arg) "Defer to `move-end-of-line' or `end-of-visual-line'." @@ -278,12 +297,29 @@ erc-fill-wrap-cycle-visual-movement ('non-input nil)))) (message "erc-fill-wrap movement: %S" erc-fill--wrap-visual-keys)) =20 +(defun erc-fill-wrap-toggle-truncate-lines (arg) + "Toggle `truncate-lines' and maybe reinstate `visual-line-mode'." + (interactive "P") + (let ((wantp (if arg + (natnump (prefix-numeric-value arg)) + (not truncate-lines))) + (buffer (current-buffer))) + (if wantp + (setq truncate-lines t) + (walk-windows (lambda (window) + (when (eq buffer (window-buffer window)) + (set-window-hscroll window 0))) + nil t) + (visual-line-mode +1))) + (force-mode-line-update)) + (defvar-keymap erc-fill-wrap-mode-map ; Compat 29 :doc "Keymap for ERC's `fill-wrap' module." :parent visual-line-mode-map "<remap> <kill-line>" #'erc-fill--wrap-kill-line "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "<remap> <toggle-truncate-lines>" #'erc-fill-wrap-toggle-truncate-lines "C-c a" #'erc-fill-wrap-cycle-visual-movement ;; Not sure if this is problematic because `erc-bol' takes no args. "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) @@ -319,21 +355,33 @@ fill-wrap "Fill style leveraging `visual-line-mode'. This local module displays nicks overhanging leftward to a common offset, as determined by the option `erc-fill-static-center'. It -depends on the `fill' and `button' modules and assumes the option -`erc-insert-timestamp-function' is `erc-insert-timestamp-right' -or the default `erc-insert-timestamp-left-and-right', so that it -can display right-hand stamps in the right margin. A value of -`erc-insert-timestamp-left' is unsupported. To use it, either -include `fill-wrap' in `erc-modules' or set `erc-fill-function' -to `erc-fill-wrap' (recommended). You can also manually invoke -one of the minor-mode toggles if really necessary." +depends on the `fill' and `button' modules and assumes users +who've defined their own `erc-insert-timestamp-function' have +also customized the option `erc-fill-wrap-margin-side' to an +explicit side. To use this module, either include `fill-wrap' in +`erc-modules' or set `erc-fill-function' to +`erc-fill-wrap' (recommended). You can also manually invoke one +of the minor-mode toggles if really necessary. + +When stamps appear in the right margin, which they do by default, +users may find that ERC actually appends them to copy-as-killed +messages without an intervening space. This normally poses at +most a minor nuisance, however users of the `log' module may +prefer a workaround provided by `erc-stamp-prefix-log-filter', +which strips trailing stamps from logged messages and instead +prepends them to every line." ((erc-fill--wrap-ensure-dependencies) - ;; Restore or initialize local state variables. (erc--restore-initialize-priors erc-fill-wrap-mode erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys - erc-fill--wrap-value erc-fill-static-center) + erc-fill--wrap-value erc-fill-static-center + erc-stamp--margin-width erc-fill-wrap-margin-width + left-margin-width 0 + right-margin-width 0) + ;; Only give this a local binding if known for sure. + (when erc-fill-wrap-margin-side + (setq erc-stamp--margin-left-p + (pcase erc-fill-wrap-margin-side ('right nil) ('left t)))) (setq erc-fill--function #'erc-fill-wrap) - ;; Internal integrations. (add-function :after (local 'erc-stamp--insert-date-function) #'erc-fill--wrap-stamp-insert-prefixed-date) (when (or erc-stamp-mode (memq 'stamp erc-modules)) @@ -381,18 +429,21 @@ erc-fill--wrap-continued-message-p (widen) (when (eq 'erc-timestamp (field-at-pos m)) (set-marker m (field-end m))) - (and (eq 'PRIVMSG (get-text-property m 'erc-command= )) - (not (eq (get-text-property m 'erc-ctcp) 'ACTI= ON)) - (cons (get-text-property m 'erc-timestamp) - (get-text-property (1+ m) 'erc-data))))) + (and-let* + (((eq 'PRIVMSG (get-text-property m 'erc-comman= d))) + ((not (eq (get-text-property m 'erc-ctcp) + 'ACTION))) + (spr (next-single-property-change m 'erc-speak= er))) + (cons (get-text-property m 'erc-timestamp) + (get-text-property spr 'erc-speaker))))) (ts (pop 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)) - (nick (buffer-substring-no-properties - (1+ (point-min)) (- (point) 2))) + (speaker (next-single-property-change (point-min) 'erc-speak= er)) + (nick (get-text-property speaker 'erc-speaker)) (props) - ((erc-nick-equal-p (car props) nick)))) + ((erc-nick-equal-p props nick)))) (set-marker erc-fill--wrap-last-msg (point-min)))) =20 (defun erc-fill--wrap-stamp-insert-prefixed-date (&rest args) @@ -476,8 +527,8 @@ erc-fill-wrap-nudge \\`=3D' Increase indentation by one column \\`-' Decrease indentation by one column \\`0' Reset indentation to the default - \\`+' Shift right margin rightward (shrink) by one column - \\`_' Shift right margin leftward (grow) by one column + \\`+' Shift margin boundary rightward by one column + \\`_' Shift margin boundary leftward by one column \\`)' Reset the right margin to the default =20 Note that misalignment may occur when messages contain @@ -489,6 +540,7 @@ erc-fill-wrap-nudge (unless (get-buffer-window) (user-error "Command called in an undisplayed buffer")) (let* ((total (erc-fill--wrap-nudge arg)) + (leftp erc-stamp--margin-left-p) (win-ratio (/ (float (- (window-point) (window-start))) (- (window-end nil t) (window-start))))) (when (zerop arg) @@ -509,18 +561,20 @@ erc-fill-wrap-nudge (dolist (key '(?\) ?_ ?+)) (let ((a (pcase key (?\) 0) - (?_ (- (abs arg))) - (?+ (abs arg))))) + (?_ (if leftp (abs arg) (- (abs arg)))) + (?+ (if leftp (- (abs arg)) (abs arg)))))) (define-key map (vector (list key)) (lambda () (interactive) - (erc-stamp--adjust-right-margin (- a)) + (erc-stamp--adjust-margin (- a) (zerop a)) + (when leftp (erc-stamp--refresh-left-margin-promp= t)) (recenter (round (* win-ratio (window-height)))))= ))) map) t (lambda () - (message "Fill prefix: %d (%+d col%s)" - erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + (message "Fill prefix: %d (%+d col%s); Margin: %d" + erc-fill--wrap-value total (if (> (abs total) 1) "s" "") + (if leftp left-margin-width right-margin-width))) "Use %k for further adjustment" 1) (recenter (round (* win-ratio (window-height)))))) @@ -536,6 +590,7 @@ erc-timestamp-offset "Get length of timestamp if inserted left." (if (and (boundp 'erc-timestamp-format) erc-timestamp-format + ;; FIXME use a more robust test than symbol equivalence. (eq erc-insert-timestamp-function 'erc-insert-timestamp-left) (not erc-hide-timestamps)) (length (format-time-string erc-timestamp-format)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 83ee4a200ed..eff99766d81 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -281,49 +281,67 @@ erc-timestamp-use-align-to set to `erc-insert-timestamp-right' or that option's default, `erc-insert-timestamp-left-and-right'. If the value is a positive integer, alignment occurs that many columns from the -right edge. If the value is `margin', the stamp appears in the -right margin when visible. +right edge. =20 Enabling this option produces a side effect in that stamps aren't indented in saved logs. When its value is an integer, this option adds a space after the end of a message if the stamp doesn't already start with one. And when its value is t, it adds -a single space, unconditionally. And while this option never -adds a space when its value is `margin', ERC does offer a -workaround in `erc-stamp-prefix-log-filter', which strips -trailing stamps from messages and puts them before every line." - :type '(choice boolean integer (const margin)) +a single space, unconditionally." + :type '(choice boolean integer) :package-version '(ERC . "5.6")) ; FIXME sync on release =20 -(defcustom erc-stamp-right-margin-width nil - "Width in columns of the right margin. -When this option is nil, pretend its value is one column greater -than the `string-width' of the formatted `erc-timestamp-format'. -This option only matters when `erc-timestamp-use-align-to' is set -to `margin'." - :package-version '(ERC . "5.6") ; FIXME sync on release - :type '(choice (const nil) integer)) - -(defun erc-stamp--display-margin-force (orig &rest r) - (let ((erc-timestamp-use-align-to 'margin)) - (apply orig r))) - -(defun erc-stamp--adjust-right-margin (cols) - "Adjust right margin by COLS. -When COLS is zero, reset width to `erc-stamp-right-margin-width' -or one col more than the `string-width' of -`erc-timestamp-format'." - (let ((width - (if (zerop cols) - (or erc-stamp-right-margin-width - (1+ (string-width (or erc-timestamp-last-inserted-right - (erc-format-timestamp - (current-time) - erc-timestamp-format))))) - (+ right-margin-width cols)))) - (setq right-margin-width width) +(defvar-local erc-stamp--margin-width nil + "Width in columns of margin for `erc-stamp--display-margin-mode'. +Only consulted when resetting or initializing margin.") + +(defvar-local erc-stamp--margin-left-p nil + "Whether `erc-stamp--display-margin-mode' uses the left margin. +During initialization, the mode respects this variable's existing +value if it already has a local binding. Otherwise, modules can +bind this to any value while enabling the mode. If it's nil, ERC +will check to see if `erc-insert-timestamp-function' is +`erc-insert-timestamp-left', interpreting the latter as a non-nil +value. It'll then coerce any non-nil value to t.") + +(defun erc-stamp--margin-left-p (&optional value) + (and (or value + (function-equal (symbol-function (default-value + 'erc-insert-timestamp-functio= n)) + (symbol-function 'erc-insert-timestamp-left))) + t)) + +(defun erc-stamp--init-margins-on-connect (&rest _) + (let ((existing (if erc-stamp--margin-left-p + left-margin-width + right-margin-width))) + (erc-stamp--adjust-margin existing 'resetp))) + +(defun erc-stamp--adjust-margin (cols &optional resetp) + "Adjust managed margin by increment COLS. +With RESETP, set margin's width to COLS. However, if COLS is +zero, set the width to a non-nil `erc-stamp--margin-width'. +Otherwise, go with the `string-width' of `erc-timestamp-format'. +However, when `erc-stamp--margin-left-p' is non-nil and the +prompt is wider, use its width instead." + (let* ((leftp erc-stamp--margin-left-p) + (width + (if resetp + (or (and (not (zerop cols)) cols) + erc-stamp--margin-width + (max (if leftp (string-width (erc-prompt)) 0) + (1+ (string-width + (or (if leftp + erc-timestamp-last-inserted + erc-timestamp-last-inserted-right) + (erc-format-timestamp + (current-time) erc-timestamp-format)))))) + (+ (if leftp left-margin-width right-margin-width) cols)))) + (set (if leftp 'left-margin-width 'right-margin-width) width) (when (eq (current-buffer) (window-buffer)) - (set-window-margins nil left-margin-width width)))) + (set-window-margins nil + (if leftp width left-margin-width) + (if leftp right-margin-width width))))) =20 ;;;###autoload (defun erc-stamp-prefix-log-filter (text) @@ -348,39 +366,101 @@ erc-stamp-prefix-log-filter (zerop (forward-line)))) "") =20 +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (declare-function erc--remove-text-properties "erc" (string)) =20 -;; If people want to use this directly, we can convert it into -;; a local module. +;; If people want to use this directly, we can convert it into a local +;; module. Also, `erc-insert-timestamp-right' hard codes its display +;; property to use `right-margin', and `erc-insert-timestamp-left' +;; does the same for `left-margin'. However, there's no reason a +;; trailing stamp couldn't be displayed on the left and vice versa. +;; Note: this adds advice that breaks `erc-timestamp-offset' because +;; the thinking is there's no use case in which that function would be +;; called while this mode is active. See note below for more. (define-minor-mode erc-stamp--display-margin-mode "Internal minor mode for built-in modules integrating with `stamp'. -It binds `erc-timestamp-use-align-to' to `margin' around calls to -`erc-insert-timestamp-function' in the current buffer, and sets -the right window margin to `erc-stamp-right-margin-width'. It -also arranges to remove most text properties when a user kills -message text so that stamps will be visible when yanked." +Manages chosen window margin and arranges to remove `display' +text properties in killed text to reveal stamps." :interactive nil (if erc-stamp--display-margin-mode (progn (setq fringes-outside-margins t) (when (eq (current-buffer) (window-buffer)) (set-window-buffer (selected-window) (current-buffer))) - (erc-stamp--adjust-right-margin 0) + (unless (local-variable-p 'erc-stamp--margin-left-p) + (setq erc-stamp--margin-left-p + (erc-stamp--margin-left-p erc-stamp--margin-left-p))) + (if (or erc-server-connected (not (functionp erc-prompt))) + (erc-stamp--init-margins-on-connect) + (add-hook 'erc-after-connect + #'erc-stamp--init-margins-on-connect nil t)) (add-function :filter-return (local 'filter-buffer-substring-funct= ion) #'erc--remove-text-properties) - (add-function :around (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force)) + (add-hook 'erc--setup-buffer-hook + #'erc-stamp--refresh-left-margin-prompt nil t) + (when erc-stamp--margin-left-p + (add-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin nil t))) (remove-function (local 'filter-buffer-substring-function) #'erc--remove-text-properties) - (remove-function (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force) - (kill-local-variable 'right-margin-width) + (add-hook 'erc-after-connect #'erc-stamp--init-margins-on-connect t) + (remove-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin t) + (remove-hook 'erc--setup-buffer-hook + #'erc-stamp--refresh-left-margin-prompt t) + (kill-local-variable (if erc-stamp--margin-left-p + 'left-margin-width + 'right-margin-width)) (kill-local-variable 'fringes-outside-margins) + (kill-local-variable 'erc-stamp--margin-prompt-width) + (kill-local-variable 'erc-stamp--margin-left-p) + (kill-local-variable 'erc-stamp--margin-width) (when (eq (current-buffer) (window-buffer)) (set-window-margins nil left-margin-width nil) (set-window-buffer (selected-window) (current-buffer))))) =20 -(defun erc-insert-timestamp-left (string) +(defvar-local erc-stamp--last-prompt nil) + +(defun erc-stamp--display-prompt-in-left-margin () + "Show prompt in the left margin with padding." + (when (or (not erc-stamp--last-prompt) (functionp erc-prompt) + (> (string-width erc-stamp--last-prompt) left-margin-width)) + (let ((s (buffer-substring erc-insert-marker (1- erc-input-marker)))) + ;; Prevent #("abc" n m (display ((...) #("abc" p q (display...)))) + (remove-text-properties 0 (length s) '(display nil) s) + (when (and erc-stamp--last-prompt + (>=3D (string-width erc-stamp--last-prompt) left-margin-w= idth)) + (let ((sm (truncate-string-to-width s (1- left-margin-width) 0 nil= t))) + ;; This papers over a subtle off-by-1 bug here. + (unless (equal sm s) + (setq s (concat sm (substring s -1)))))) + (setq erc-stamp--last-prompt (string-pad s left-margin-width nil t))= )) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt)) + erc-stamp--last-prompt) + +(defun erc-stamp--refresh-left-margin-prompt () + "Forcefully-recompute display property of prompt in left margin." + (with-silent-modifications + (unless (functionp erc-prompt) + (setq erc-stamp--last-prompt nil)) + (erc--refresh-prompt))) + +(cl-defmethod erc--reveal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt))) + +(cl-defmethod erc--conceal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (let ((prompt (string-pad erc-prompt-hidden left-margin-width nil 'start= ))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,prompt)))) + +(cl-defmethod erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." (goto-char (point-min)) (let* ((ignore-p (and erc-timestamp-only-if-changed-flag @@ -392,6 +472,22 @@ erc-insert-timestamp-left (erc-put-text-property 0 len 'invisible erc-stamp--invisible-property = s) (insert s))) =20 +(cl-defmethod erc-insert-timestamp-left + (string &context (erc-stamp--display-margin-mode (eql t))) + (unless (and erc-timestamp-only-if-changed-flag + (string-equal string erc-timestamp-last-inserted)) + (goto-char (point-min)) + (insert-before-markers-and-inherit + (setq erc-timestamp-last-inserted string)) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (point) p))) + (put-text-property (point-min) (point) p v))) + (erc-put-text-property (point-min) (point) 'invisible + erc-stamp--invisible-property) + (put-text-property (point-min) (point) 'field 'erc-timestamp) + (put-text-property (point-min) (point) + 'display `((margin left-margin) ,string)))) + (defun erc-insert-aligned (string pos) "Insert STRING at the POSth column. =20 @@ -408,8 +504,6 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) =20 -(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) - (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -465,6 +559,9 @@ erc-insert-timestamp-right ;; For compatibility reasons, the `erc-timestamp' field includes ;; intervening white space unless a hard break is warranted. (pcase erc-timestamp-use-align-to + ((guard erc-stamp--display-margin-mode) + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) stri= ng)) ((and 't (guard (< col pos))) (insert " ") (put-text-property from (point) 'display `(space :align-to ,pos))) @@ -475,10 +572,6 @@ erc-insert-timestamp-right (let ((s (+ erc-timestamp-use-align-to (string-width string)))) (put-text-property from (point) 'display `(space :align-to (- right ,s))))) - ('margin - (put-text-property 0 (length string) - 'display `((margin right-margin) ,string) - string)) ((guard (>=3D col pos)) (newline) (indent-to pos) (setq from (poin= t))) (_ (indent-to pos))) (insert string) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 03c21059a92..c90f20cc9a4 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2879,19 +2879,23 @@ erc--assert-input-bounds (cl-assert (< erc-insert-marker erc-input-marker)) (cl-assert (=3D (field-end erc-insert-marker) erc-input-marker))= ))) =20 +(defvar erc--refresh-prompt-hook nil) + (defun erc--refresh-prompt () "Re-render ERC's prompt when the option `erc-prompt' is a function." (erc--assert-input-bounds) - (when (functionp erc-prompt) - (save-excursion - (goto-char erc-insert-marker) - (set-marker-insertion-type erc-insert-marker nil) - ;; Avoid `erc-prompt' (the named function), which appends a - ;; space, and `erc-display-prompt', which propertizes all but - ;; that space. - (insert-and-inherit (funcall erc-prompt)) - (set-marker-insertion-type erc-insert-marker t) - (delete-region (point) (1- erc-input-marker))))) + (unless (erc--prompt-hidden-p) + (when (functionp erc-prompt) + (save-excursion + (goto-char erc-insert-marker) + (set-marker-insertion-type erc-insert-marker nil) + ;; Avoid `erc-prompt' (the named function), which appends a + ;; space, and `erc-display-prompt', which propertizes all but + ;; that space. + (insert-and-inherit (funcall erc-prompt)) + (set-marker-insertion-type erc-insert-marker t) + (delete-region (point) (1- erc-input-marker)))) + (run-hooks 'erc--refresh-prompt-hook))) =20 (defun erc-display-line-1 (string buffer) "Display STRING in `erc-mode' BUFFER. @@ -4804,7 +4808,7 @@ erc-display-prompt ;; shall remain part of the prompt. (setq prompt (propertize prompt 'rear-nonsticky t - 'erc-prompt t + 'erc-prompt t ; t or `hidden' 'field 'erc-prompt 'front-sticky t 'read-only t)) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index 99ec4a9635e..67622da9f3d 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -340,4 +340,41 @@ erc-fill-wrap-visual-keys--prompt (should (search-backward "ERC> " nil t)) (execute-kbd-macro "\C-a"))))) =20 +(ert-deftest erc-fill--left-hand-stamps () + :tags '(:unstable) + (unless (>=3D emacs-major-version 29) + (ert-skip "Emacs version too low, missing `buffer-text-pixel-size'")) + + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-insert-timestamp-function #'erc-insert-timestamp-left)) + (erc-fill-tests--wrap-populate + (lambda () + (should (=3D 8 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 4 8 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face))))) + (erc-fill-tests--compare "stamps-left-01") + + (ert-info ("Shrink left margin by 1 col") + (erc-stamp--adjust-margin -1) + (with-silent-modifications (erc--refresh-prompt)) + (should (=3D 7 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 3 7 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face)))))))))) + ;;; erc-fill-tests.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tes= ts.el index 6da7ed4503d..f6de087a09a 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -140,7 +140,7 @@ erc-timestamp-use-align-to--integer (should (eql ?\s (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) =20 -(ert-deftest erc-timestamp-use-align-to--margin () +(ert-deftest erc-stamp--display-margin-mode--right () (erc-stamp-tests--insert-right (lambda () (erc-stamp--display-margin-mode +1) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b5db5fe8764..fff3c4cb704 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -219,6 +219,7 @@ erc-hide-prompt (setq erc-hide-prompt '(server)) (with-current-buffer "ServNet" (erc--hide-prompt erc-server-process) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay)))) =20 (with-current-buffer "#chan" @@ -229,6 +230,7 @@ erc-hide-prompt =20 (with-current-buffer "ServNet" (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: channel") @@ -242,7 +244,9 @@ erc-hide-prompt =20 (with-current-buffer "#chan" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: query") @@ -253,7 +257,9 @@ erc-hide-prompt =20 (with-current-buffer "bob" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display))) =20 (with-current-buffer "#chan" diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld new file mode 100644 index 00000000000..f62b65cd170 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -0,0 +1 @@ +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 9 (erc= -timestamp 0 display (#4=3D(margin left-margin) #("[00:00]" 0 7 (invisible = timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-pre= fix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 27 (4)))) 9 17= 1 (erc-timestamp 0 wrap-prefix #1# line-prefix #2#) 172 179 (erc-timestamp = 0 display (#4# #("[00:00]" 0 7 (invisible timestamp font-lock-face erc-time= stamp-face))) field erc-timestamp wrap-prefix #1# line-prefix #3=3D(space := width (- 27 (8)))) 179 180 (erc-timestamp 0 wrap-prefix #1# line-prefix #3#= erc-command PRIVMSG) 180 185 (erc-timestamp 0 wrap-prefix #1# line-prefix = #3# erc-command PRIVMSG) 185 187 (erc-timestamp 0 wrap-prefix #1# line-pref= ix #3# erc-command PRIVMSG) 187 190 (erc-timestamp 0 wrap-prefix #1# line-p= refix #3# erc-command PRIVMSG) 190 303 (erc-timestamp 0 wrap-prefix #1# lin= e-prefix #3# erc-command PRIVMSG) 303 304 (erc-timestamp 0 erc-command PRIV= MSG) 304 336 (erc-timestamp 0 wrap-prefix #1# line-prefix #3# erc-command P= RIVMSG) 337 344 (erc-timestamp 0 display (#4# #("[00:00]" 0 7 (invisible ti= mestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefi= x #1# line-prefix #5=3D(space :width (- 27 (6)))) 344 345 (erc-timestamp 0 = wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 345 348 (erc-timestamp= 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 348 350 (erc-timest= amp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 350 355 (erc-tim= estamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 355 430 (erc-= timestamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file --=20 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 18 Jul 2023 13:55:48 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jul 18 09:55:48 2023 Received: from localhost ([127.0.0.1]:53261 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qLlB4-0005Gc-5u for submit <at> debbugs.gnu.org; Tue, 18 Jul 2023 09:55:48 -0400 Received: from mail-108-mta144.mxroute.com ([136.175.108.144]:35233) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qLlAy-0005Ce-2t for 60936 <at> debbugs.gnu.org; Tue, 18 Jul 2023 09:55:44 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta144.mxroute.com (ZoneMTA) with ESMTPSA id 1896948f2730004cef.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Tue, 18 Jul 2023 13:55:35 +0000 X-Zone-Loop: affcc4d308be3aeaf07ea91e84572f17a694abdd6789 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=JVookHi96o4A5BWDeoOuGNyuaZLvA/TUbn/fb09XYYA=; b=hs/PCFYJDdd0eUruvmEiGwI/KA MYfqHPvy5jGxqAkQQR0/1szzpt1ncq6Udc9ZFiVPKrkJo2agTzjKF3ZEX9mEJFseObK+MJQyYg2ZC T35Jocse/13QnXVafmuqxx5HfJqS2rWWv8ocBhCauTGjfuAvc12lO+wULoe3H41yfyASHp/8UdNRq Sd0l3iTZxqy9JmwwPmL0+S1nDg2U1N+JLdGv+ez5SEc/yZXYdyaPexa155CYIVOd0bVm2/r1x9Y48 kuaDX134fLNz6BkRZQR47pY+xXvFaXx383wRxAbijcP76s13NAOXKaoa3r/1L9ykm7gNSDteUDBVj Eru6PSQw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87msztl4xu.fsf@HIDDEN> (J. P.'s message of "Tue, 18 Jul 2023 06:33:49 -0700") References: <87tu0nao77.fsf@HIDDEN> <87msztl4xu.fsf@HIDDEN> Date: Tue, 18 Jul 2023 06:55:31 -0700 Message-ID: <871qh5l3xo.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Quick fixup (misc/test-custom-opts just caught some sloppiness in my Custom :type specs). --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Make-erc-fill-wrap-work-with-left-hand-stamps.patch Content-Transfer-Encoding: quoted-printable From 828db2d91b0f47f8a758e3011bb3cbf817168564 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 14 Jul 2023 06:12:30 -0700 Subject: [PATCH] [5.6] Make erc-fill-wrap work with left-hand stamps * etc/ERC-NEWS: Remove all mention of option `erc-timestamp-align-to' supporting a value of `margin', which has been removed. * lisp/erc/erc-backend.el (erc--reveal-prompt, erc--conceal-prompt): New generic functions with default implementations factored out from `erc--unhide-prompt' and `erc--hide-prompt'. (erc--prompt-hidden-p): New internal predicate function. (erc--unhide-prompt): Defer to `erc--reveal-prompt' and set `erc-prompt' text property to t. (erc--hide-prompt): Defer to `erc--conceal-prompt' and set `erc-prompt' text property to `hidden'. * lisp/erc/erc-compat.el (erc-compat--29-browse-url-irc): Add FIXME comment for likely insufficient test of function equality. * lisp/erc/erc-fill.el (erc-fill-wrap-margin-width, erc-fill-wrap-margin-side): New options to control side and initial width of `fill-wrap' margin. (erc-fill--wrap-beginning-of-line): Fix bug involving non-string valued `display' props. (erc-fill-wrap-mode, erc-fill-wrap-enable): Update doc string, persist a few local vars, and conditionally set `erc-stamp--margin-left-p'. (erc-fill-wrap-nudge): Update doc string and account for left-hand stamps. (erc-timestamp-offset): Add comment regarding conditional guard based on function-valued option. * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Remove value variant `margin', which was originally intended to be new in ERC 5.6. This functionality was all but useless without the internal minor mode `erc-stamp--display-margin-mode' active. (erc-stamp-right-margin-width): Remove unused option new in 5.6. (erc-stamp--display-margin-force): Remove unused function. (erc-stamp--margin-width, erc-stamp--margin-left-p): New internal var. (erc-stamp--margin-left-p, erc-stamp--init-margins-on-connect): New functions for other modules that use `erc-stamp--display-margin-mode'. (erc-stamp--adjust-right-margin, erc-stamp--adjust-margin): Rename function to latter and accommodate left-hand stamps. (erc-stamp--inherited-props): Relocate from lower down in file. (erc-stamp--display-margin-mode): Update function name, and adjust setup and teardown to accommodate left-handed stamps. Don't add advice around `erc-insert-timestamp-function'. (erc-stamp--last-prompt, erc-stamp--display-prompt-in-left-margin): New function and helper var to convert a normal inserted prompt so that it appears in the left margin. (erc-stamp--refresh-left-margin-prompt): Helper for other modules to quickly refresh prompt outside of insert hooks. (erc--reveal-prompt, erc--conceal-prompt): New implementations for when `erc-stamp--display-margin-mode' is active. (erc-insert-timestamp-left): Convert to defmethod and provide implementation for `erc-stamp--display-margin-mode'. (erc-insert-timestamp-right): Don't expect `erc-timestamp-align-to' to ever be the symbol `margin'. Move handling for that case to one contingent on the internal minor mode `erc-stamp--display-margin-mode' being active. * lisp/erc/erc.el (erc--refresh-prompt-hook): New variable. (erc--refresh-prompt): Fix bug in which user-defined prompt functions failed to hide when quitting in server buffers. Run new hook `erc--refresh-prompt-hook'. (erc-display-prompt): Add comment noting that the text property `erc-prompt' now actually matters. It's t while a session is running and `hidden' when disconnected. * test/lisp/erc/erc-fill-tests.el (erc-fill--left-hand-stamps): New test. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--margin, erc-stamp--display-margin-mode--right): Rename test to latter. * test/lisp/erc/erc-tests.el (erc-hide-prompt): Add some assertions for new possible value of `erc-prompt' text property. * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: New test data file. (Bug#60936) --- etc/ERC-NEWS | 7 +- lisp/erc/erc-backend.el | 23 +- lisp/erc/erc-compat.el | 1 + lisp/erc/erc-fill.el | 76 +++++-- lisp/erc/erc-stamp.el | 199 +++++++++++++----- lisp/erc/erc.el | 26 ++- test/lisp/erc/erc-fill-tests.el | 37 ++++ test/lisp/erc/erc-stamp-tests.el | 2 +- test/lisp/erc/erc-tests.el | 6 + .../fill/snapshots/stamps-left-01.eld | 1 + 10 files changed, 281 insertions(+), 97 deletions(-) create mode 100644 test/lisp/erc/resources/fill/snapshots/stamps-left-01.e= ld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index cd0b8e5f823..379d5eb2ad0 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -102,11 +102,8 @@ side window. Hit '<RET>' over a nick to spawn a "/QUE= RY" or a ** The option 'erc-timestamp-use-align-to' is more versatile. While this option has always offered to right-align stamps via the 'display' text property, it's now more effective at doing so when set -to a number indicating an offset from the right edge. And when set to -the symbol 'margin', it displays stamps in the right margin, although, -at the moment, this is mostly intended for use by other modules, such -as 'fill-wrap', described above. For both these variants, users of -the 'log' module may want to customize 'erc-log-filter-function' to +to a number indicating an offset from the right edge. Users of the +'log' module may want to customize 'erc-log-filter-function' to 'erc-stamp-prefix-log-filter' to avoid ragged right-hand stamps appearing in their saved logs. =20 diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 363509d17fa..eb3ec39fedd 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1045,13 +1045,25 @@ erc-process-sentinel-1 ;; unexpected disconnect (erc-process-sentinel-2 event buffer)))) =20 +(cl-defmethod erc--reveal-prompt () + (remove-text-properties erc-insert-marker erc-input-marker + '(display nil))) + +(cl-defmethod erc--conceal-prompt () + (add-text-properties erc-insert-marker (1- erc-input-marker) + `(display ,erc-prompt-hidden))) + +(defun erc--prompt-hidden-p () + (and (marker-position erc-insert-marker) + (eq (get-text-property erc-insert-marker 'erc-prompt) 'hidden))) + (defun erc--unhide-prompt () (remove-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert t) (when (and (marker-position erc-insert-marker) (marker-position erc-input-marker)) (with-silent-modifications - (remove-text-properties erc-insert-marker erc-input-marker - '(display nil))))) + (put-text-property erc-insert-marker (1- erc-input-marker) 'erc-prom= pt t) + (erc--reveal-prompt)))) =20 (defun erc--unhide-prompt-on-self-insert () (when (and (eq this-command #'self-insert-command) @@ -1059,6 +1071,8 @@ erc--unhide-prompt-on-self-insert (erc--unhide-prompt))) =20 (defun erc--hide-prompt (proc) + "Hide prompt in all buffers of server. +Change value of property `erc-prompt' from t to `hidden'." (erc-with-all-buffers-of-server proc nil (when (and erc-hide-prompt (or (eq erc-hide-prompt t) @@ -1072,8 +1086,9 @@ erc--hide-prompt (marker-position erc-input-marker) (get-text-property erc-insert-marker 'erc-prompt)) (with-silent-modifications - (add-text-properties erc-insert-marker (1- erc-input-marker) - `(display ,erc-prompt-hidden))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'erc-prompt 'hidden) + (erc--conceal-prompt)) (add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 91 t= )))) =20 (defun erc-process-sentinel (cproc event) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index f451aaee754..912a4bc576c 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -418,6 +418,7 @@ erc-compat--29-browse-url-irc (require 'url-irc) (let* ((url (url-generic-parse-url string)) (url-irc-function + ;; FIXME this should probably use `symbol-function'. (if (function-equal url-irc-function 'url-irc-erc) (lambda (host port chan user pass) (erc-handle-irc-url host port chan user pass (url-type url= ))) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index a65c95f1d85..9f39f41133d 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -116,6 +116,25 @@ erc-fill-column "The column at which a filled paragraph is broken." :type 'integer) =20 +(defcustom erc-fill-wrap-margin-width nil + "Starting width in columns of dedicated stamp margin. +When nil, ERC normally pretends its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +However, when `erc-fill-wrap-margin-side' is `left' or +\"resolves\" to `left', ERC uses the width of the prompt if it's +wider on MOTD's end, which really only matters when `erc-prompt' +is a function." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defcustom erc-fill-wrap-margin-side nil + "Margin side to use with `erc-fill-wrap-mode'. +A value of nil means ERC should decide based on +`erc-insert-timestamp-function', which obviously cannot work for +user-defined functions." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) (const left) (const right))) + (defcustom erc-fill-line-spacing nil "Extra space between messages on graphical displays. This may need adjusting depending on how your faces are @@ -253,9 +272,9 @@ erc-fill--wrap-beginning-of-line (goto-char erc-input-marker) ;; Mimic what `move-beginning-of-line' does with invisible text. (when-let ((erc-fill-wrap-merge) - (empty (get-text-property (point) 'display)) - ((string-empty-p empty))) - (goto-char (text-property-not-all (point) (pos-eol) 'display empty))= ))) + (prop (get-text-property (point) 'display)) + ((or (equal prop "") (eq 'margin (car-safe (car-safe prop))= )))) + (goto-char (text-property-not-all (point) (pos-eol) 'display prop)))= )) =20 (defun erc-fill--wrap-end-of-line (arg) "Defer to `move-end-of-line' or `end-of-visual-line'." @@ -319,21 +338,33 @@ fill-wrap "Fill style leveraging `visual-line-mode'. This local module displays nicks overhanging leftward to a common offset, as determined by the option `erc-fill-static-center'. It -depends on the `fill' and `button' modules and assumes the option -`erc-insert-timestamp-function' is `erc-insert-timestamp-right' -or the default `erc-insert-timestamp-left-and-right', so that it -can display right-hand stamps in the right margin. A value of -`erc-insert-timestamp-left' is unsupported. To use it, either -include `fill-wrap' in `erc-modules' or set `erc-fill-function' -to `erc-fill-wrap' (recommended). You can also manually invoke -one of the minor-mode toggles if really necessary." +depends on the `fill' and `button' modules and assumes users +who've defined their own `erc-insert-timestamp-function' have +also customized the option `erc-fill-wrap-margin-side' to an +explicit side. To use this module, either include `fill-wrap' in +`erc-modules' or set `erc-fill-function' to +`erc-fill-wrap' (recommended). You can also manually invoke one +of the minor-mode toggles if really necessary. + +When stamps appear in the right margin, which they do by default, +users may find that ERC actually appends them to copy-as-killed +messages without an intervening space. This normally poses at +most a minor nuisance, however users of the `log' module may +prefer a workaround provided by `erc-stamp-prefix-log-filter', +which strips trailing stamps from logged messages and instead +prepends them to every line." ((erc-fill--wrap-ensure-dependencies) - ;; Restore or initialize local state variables. (erc--restore-initialize-priors erc-fill-wrap-mode erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys - erc-fill--wrap-value erc-fill-static-center) + erc-fill--wrap-value erc-fill-static-center + erc-stamp--margin-width erc-fill-wrap-margin-width + left-margin-width 0 + right-margin-width 0) + ;; Only give this a local binding if known for sure. + (pcase erc-fill-wrap-margin-side + ('right (setq erc-stamp--margin-left-p nil)) + ('left (setq erc-stamp--margin-left-p t))) (setq erc-fill--function #'erc-fill-wrap) - ;; Internal integrations. (add-function :after (local 'erc-stamp--insert-date-function) #'erc-fill--wrap-stamp-insert-prefixed-date) (when (or erc-stamp-mode (memq 'stamp erc-modules)) @@ -476,8 +507,8 @@ erc-fill-wrap-nudge \\`=3D' Increase indentation by one column \\`-' Decrease indentation by one column \\`0' Reset indentation to the default - \\`+' Shift right margin rightward (shrink) by one column - \\`_' Shift right margin leftward (grow) by one column + \\`+' Shift margin boundary rightward by one column + \\`_' Shift margin boundary leftward by one column \\`)' Reset the right margin to the default =20 Note that misalignment may occur when messages contain @@ -507,14 +538,16 @@ erc-fill-wrap-nudge (cl-incf total (erc-fill--wrap-nudge a)) (recenter (round (* win-ratio (window-height)))))= ))) (dolist (key '(?\) ?_ ?+)) - (let ((a (pcase key - (?\) 0) - (?_ (- (abs arg))) - (?+ (abs arg))))) + (let* ((leftp erc-stamp--margin-left-p) + (a (pcase key + (?\) 0) + (?_ (if leftp (abs arg) (- (abs arg)))) + (?+ (if leftp (- (abs arg)) (abs arg)))))) (define-key map (vector (list key)) (lambda () (interactive) - (erc-stamp--adjust-right-margin (- a)) + (erc-stamp--adjust-margin (- a) (zerop a)) + (when leftp (erc-stamp--refresh-left-margin-promp= t)) (recenter (round (* win-ratio (window-height)))))= ))) map) t @@ -536,6 +569,7 @@ erc-timestamp-offset "Get length of timestamp if inserted left." (if (and (boundp 'erc-timestamp-format) erc-timestamp-format + ;; FIXME use a more robust test than symbol equivalence. (eq erc-insert-timestamp-function 'erc-insert-timestamp-left) (not erc-hide-timestamps)) (length (format-time-string erc-timestamp-format)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 83ee4a200ed..727d334f13b 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -281,49 +281,67 @@ erc-timestamp-use-align-to set to `erc-insert-timestamp-right' or that option's default, `erc-insert-timestamp-left-and-right'. If the value is a positive integer, alignment occurs that many columns from the -right edge. If the value is `margin', the stamp appears in the -right margin when visible. +right edge. =20 Enabling this option produces a side effect in that stamps aren't indented in saved logs. When its value is an integer, this option adds a space after the end of a message if the stamp doesn't already start with one. And when its value is t, it adds -a single space, unconditionally. And while this option never -adds a space when its value is `margin', ERC does offer a -workaround in `erc-stamp-prefix-log-filter', which strips -trailing stamps from messages and puts them before every line." - :type '(choice boolean integer (const margin)) +a single space, unconditionally." + :type '(choice boolean integer) :package-version '(ERC . "5.6")) ; FIXME sync on release =20 -(defcustom erc-stamp-right-margin-width nil - "Width in columns of the right margin. -When this option is nil, pretend its value is one column greater -than the `string-width' of the formatted `erc-timestamp-format'. -This option only matters when `erc-timestamp-use-align-to' is set -to `margin'." - :package-version '(ERC . "5.6") ; FIXME sync on release - :type '(choice (const nil) integer)) - -(defun erc-stamp--display-margin-force (orig &rest r) - (let ((erc-timestamp-use-align-to 'margin)) - (apply orig r))) - -(defun erc-stamp--adjust-right-margin (cols) - "Adjust right margin by COLS. -When COLS is zero, reset width to `erc-stamp-right-margin-width' -or one col more than the `string-width' of -`erc-timestamp-format'." - (let ((width - (if (zerop cols) - (or erc-stamp-right-margin-width - (1+ (string-width (or erc-timestamp-last-inserted-right - (erc-format-timestamp - (current-time) - erc-timestamp-format))))) - (+ right-margin-width cols)))) - (setq right-margin-width width) +(defvar-local erc-stamp--margin-width nil + "Width in columns of margin for `erc-stamp--display-margin-mode'. +Only consulted when resetting or initializing margin.") + +(defvar-local erc-stamp--margin-left-p nil + "Whether `erc-stamp--display-margin-mode' uses the left margin. +During initialization, the mode respects this variable's existing +value if it already has a local binding. Otherwise, modules can +bind this to any value while enabling the mode. If it's nil, ERC +will check to see if `erc-insert-timestamp-function' is +`erc-insert-timestamp-left', interpreting the latter as a non-nil +value. It'll then coerce any non-nil value to t.") + +(defun erc-stamp--margin-left-p (&optional value) + (and (or value + (function-equal (symbol-function (default-value + 'erc-insert-timestamp-functio= n)) + (symbol-function 'erc-insert-timestamp-left))) + t)) + +(defun erc-stamp--init-margins-on-connect (&rest _) + (let ((existing (if erc-stamp--margin-left-p + left-margin-width + right-margin-width))) + (erc-stamp--adjust-margin existing 'resetp))) + +(defun erc-stamp--adjust-margin (cols &optional resetp) + "Adjust managed margin by increment COLS. +With RESETP, set margin's width to COLS. However, if COLS is +zero, set the width to a non-nil `erc-stamp--margin-width'. +Otherwise, go with the `string-width' of `erc-timestamp-format'. +However, when `erc-stamp--margin-left-p' is non-nil and the +prompt is wider, use its width instead." + (let* ((leftp erc-stamp--margin-left-p) + (width + (if resetp + (or (and (not (zerop cols)) cols) + erc-stamp--margin-width + (max (if leftp (string-width (erc-prompt)) 0) + (1+ (string-width + (or (if leftp + erc-timestamp-last-inserted + erc-timestamp-last-inserted-right) + (erc-format-timestamp + (current-time) erc-timestamp-format)))))) + (+ (if leftp left-margin-width right-margin-width) cols)))) + (set (if leftp 'left-margin-width 'right-margin-width) width) (when (eq (current-buffer) (window-buffer)) - (set-window-margins nil left-margin-width width)))) + (set-window-margins nil + (if leftp width left-margin-width) + (if leftp right-margin-width width))))) =20 ;;;###autoload (defun erc-stamp-prefix-log-filter (text) @@ -348,39 +366,97 @@ erc-stamp-prefix-log-filter (zerop (forward-line)))) "") =20 +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (declare-function erc--remove-text-properties "erc" (string)) =20 -;; If people want to use this directly, we can convert it into -;; a local module. +;; If people want to use this directly, we can convert it into a local +;; module. Also, `erc-insert-timestamp-right' hard codes its display +;; property to use `right-margin', and `erc-insert-timestamp-left' +;; does the same for `left-margin'. However, there's no reason a +;; trailing stamp couldn't be displayed on the left and vice versa. +;; Note: this adds advice that breaks `erc-timestamp-offset' because +;; the thinking is there's no use case in which that function would be +;; called while this mode is active. See note below for more. (define-minor-mode erc-stamp--display-margin-mode "Internal minor mode for built-in modules integrating with `stamp'. -It binds `erc-timestamp-use-align-to' to `margin' around calls to -`erc-insert-timestamp-function' in the current buffer, and sets -the right window margin to `erc-stamp-right-margin-width'. It -also arranges to remove most text properties when a user kills -message text so that stamps will be visible when yanked." +Manages chosen window margin and arranges to remove `display' +text properties in killed text to reveal stamps." :interactive nil (if erc-stamp--display-margin-mode (progn (setq fringes-outside-margins t) (when (eq (current-buffer) (window-buffer)) (set-window-buffer (selected-window) (current-buffer))) - (erc-stamp--adjust-right-margin 0) + (unless (local-variable-p 'erc-stamp--margin-left-p) + (setq erc-stamp--margin-left-p + (erc-stamp--margin-left-p erc-stamp--margin-left-p))) + (if (or erc-server-connected (not (functionp erc-prompt))) + (erc-stamp--init-margins-on-connect) + (add-hook 'erc-after-connect + #'erc-stamp--init-margins-on-connect nil t)) (add-function :filter-return (local 'filter-buffer-substring-funct= ion) #'erc--remove-text-properties) - (add-function :around (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force)) + (when erc-stamp--margin-left-p + (add-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin nil t))) (remove-function (local 'filter-buffer-substring-function) #'erc--remove-text-properties) - (remove-function (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force) - (kill-local-variable 'right-margin-width) + (add-hook 'erc-after-connect #'erc-stamp--init-margins-on-connect t) + (remove-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin t) + (kill-local-variable (if erc-stamp--margin-left-p + 'left-margin-width + 'right-margin-width)) (kill-local-variable 'fringes-outside-margins) + (kill-local-variable 'erc-stamp--margin-prompt-width) + (kill-local-variable 'erc-stamp--margin-left-p) + (kill-local-variable 'erc-stamp--margin-width) (when (eq (current-buffer) (window-buffer)) (set-window-margins nil left-margin-width nil) (set-window-buffer (selected-window) (current-buffer))))) =20 -(defun erc-insert-timestamp-left (string) +(defvar-local erc-stamp--last-prompt nil) + +(defun erc-stamp--display-prompt-in-left-margin () + "Show prompt in the left margin with padding." + (when (or (not erc-stamp--last-prompt) (functionp erc-prompt) + (> (string-width erc-stamp--last-prompt) left-margin-width)) + (let ((s (buffer-substring erc-insert-marker (1- erc-input-marker)))) + ;; Prevent #("abc" n m (display ((...) #("abc" p q (display...)))) + (remove-text-properties 0 (length s) '(display nil) s) + (when (and erc-stamp--last-prompt + (>=3D (string-width erc-stamp--last-prompt) left-margin-w= idth)) + (let ((sm (truncate-string-to-width s (1- left-margin-width) 0 nil= t))) + ;; This papers over a subtle off-by-1 bug here. + (unless (equal sm s) + (setq s (concat sm (substring s -1)))))) + (setq erc-stamp--last-prompt (string-pad s left-margin-width nil t))= )) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt)) + erc-stamp--last-prompt) + +(defun erc-stamp--refresh-left-margin-prompt () + "Forcefully-recompute display property of prompt in left margin." + (with-silent-modifications + (unless (functionp erc-prompt) + (setq erc-stamp--last-prompt nil)) + (erc--refresh-prompt))) + +(cl-defmethod erc--reveal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt))) + +(cl-defmethod erc--conceal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (let ((prompt (string-pad erc-prompt-hidden left-margin-width nil 'start= ))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,prompt)))) + +(cl-defmethod erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." (goto-char (point-min)) (let* ((ignore-p (and erc-timestamp-only-if-changed-flag @@ -392,6 +468,22 @@ erc-insert-timestamp-left (erc-put-text-property 0 len 'invisible erc-stamp--invisible-property = s) (insert s))) =20 +(cl-defmethod erc-insert-timestamp-left + (string &context (erc-stamp--display-margin-mode (eql t))) + (unless (and erc-timestamp-only-if-changed-flag + (string-equal string erc-timestamp-last-inserted)) + (goto-char (point-min)) + (insert-before-markers-and-inherit + (setq erc-timestamp-last-inserted string)) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (point) p))) + (put-text-property (point-min) (point) p v))) + (erc-put-text-property (point-min) (point) 'invisible + erc-stamp--invisible-property) + (put-text-property (point-min) (point) 'field 'erc-timestamp) + (put-text-property (point-min) (point) + 'display `((margin left-margin) ,string)))) + (defun erc-insert-aligned (string pos) "Insert STRING at the POSth column. =20 @@ -408,8 +500,6 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) =20 -(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) - (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -465,6 +555,9 @@ erc-insert-timestamp-right ;; For compatibility reasons, the `erc-timestamp' field includes ;; intervening white space unless a hard break is warranted. (pcase erc-timestamp-use-align-to + ((guard erc-stamp--display-margin-mode) + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) stri= ng)) ((and 't (guard (< col pos))) (insert " ") (put-text-property from (point) 'display `(space :align-to ,pos))) @@ -475,10 +568,6 @@ erc-insert-timestamp-right (let ((s (+ erc-timestamp-use-align-to (string-width string)))) (put-text-property from (point) 'display `(space :align-to (- right ,s))))) - ('margin - (put-text-property 0 (length string) - 'display `((margin right-margin) ,string) - string)) ((guard (>=3D col pos)) (newline) (indent-to pos) (setq from (poin= t))) (_ (indent-to pos))) (insert string) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 03c21059a92..c90f20cc9a4 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2879,19 +2879,23 @@ erc--assert-input-bounds (cl-assert (< erc-insert-marker erc-input-marker)) (cl-assert (=3D (field-end erc-insert-marker) erc-input-marker))= ))) =20 +(defvar erc--refresh-prompt-hook nil) + (defun erc--refresh-prompt () "Re-render ERC's prompt when the option `erc-prompt' is a function." (erc--assert-input-bounds) - (when (functionp erc-prompt) - (save-excursion - (goto-char erc-insert-marker) - (set-marker-insertion-type erc-insert-marker nil) - ;; Avoid `erc-prompt' (the named function), which appends a - ;; space, and `erc-display-prompt', which propertizes all but - ;; that space. - (insert-and-inherit (funcall erc-prompt)) - (set-marker-insertion-type erc-insert-marker t) - (delete-region (point) (1- erc-input-marker))))) + (unless (erc--prompt-hidden-p) + (when (functionp erc-prompt) + (save-excursion + (goto-char erc-insert-marker) + (set-marker-insertion-type erc-insert-marker nil) + ;; Avoid `erc-prompt' (the named function), which appends a + ;; space, and `erc-display-prompt', which propertizes all but + ;; that space. + (insert-and-inherit (funcall erc-prompt)) + (set-marker-insertion-type erc-insert-marker t) + (delete-region (point) (1- erc-input-marker)))) + (run-hooks 'erc--refresh-prompt-hook))) =20 (defun erc-display-line-1 (string buffer) "Display STRING in `erc-mode' BUFFER. @@ -4804,7 +4808,7 @@ erc-display-prompt ;; shall remain part of the prompt. (setq prompt (propertize prompt 'rear-nonsticky t - 'erc-prompt t + 'erc-prompt t ; t or `hidden' 'field 'erc-prompt 'front-sticky t 'read-only t)) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index 99ec4a9635e..67622da9f3d 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -340,4 +340,41 @@ erc-fill-wrap-visual-keys--prompt (should (search-backward "ERC> " nil t)) (execute-kbd-macro "\C-a"))))) =20 +(ert-deftest erc-fill--left-hand-stamps () + :tags '(:unstable) + (unless (>=3D emacs-major-version 29) + (ert-skip "Emacs version too low, missing `buffer-text-pixel-size'")) + + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-insert-timestamp-function #'erc-insert-timestamp-left)) + (erc-fill-tests--wrap-populate + (lambda () + (should (=3D 8 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 4 8 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face))))) + (erc-fill-tests--compare "stamps-left-01") + + (ert-info ("Shrink left margin by 1 col") + (erc-stamp--adjust-margin -1) + (with-silent-modifications (erc--refresh-prompt)) + (should (=3D 7 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 3 7 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face)))))))))) + ;;; erc-fill-tests.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tes= ts.el index 6da7ed4503d..f6de087a09a 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -140,7 +140,7 @@ erc-timestamp-use-align-to--integer (should (eql ?\s (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) =20 -(ert-deftest erc-timestamp-use-align-to--margin () +(ert-deftest erc-stamp--display-margin-mode--right () (erc-stamp-tests--insert-right (lambda () (erc-stamp--display-margin-mode +1) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b5db5fe8764..fff3c4cb704 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -219,6 +219,7 @@ erc-hide-prompt (setq erc-hide-prompt '(server)) (with-current-buffer "ServNet" (erc--hide-prompt erc-server-process) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay)))) =20 (with-current-buffer "#chan" @@ -229,6 +230,7 @@ erc-hide-prompt =20 (with-current-buffer "ServNet" (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: channel") @@ -242,7 +244,9 @@ erc-hide-prompt =20 (with-current-buffer "#chan" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: query") @@ -253,7 +257,9 @@ erc-hide-prompt =20 (with-current-buffer "bob" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display))) =20 (with-current-buffer "#chan" diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld new file mode 100644 index 00000000000..f62b65cd170 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -0,0 +1 @@ +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 9 (erc= -timestamp 0 display (#4=3D(margin left-margin) #("[00:00]" 0 7 (invisible = timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-pre= fix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 27 (4)))) 9 17= 1 (erc-timestamp 0 wrap-prefix #1# line-prefix #2#) 172 179 (erc-timestamp = 0 display (#4# #("[00:00]" 0 7 (invisible timestamp font-lock-face erc-time= stamp-face))) field erc-timestamp wrap-prefix #1# line-prefix #3=3D(space := width (- 27 (8)))) 179 180 (erc-timestamp 0 wrap-prefix #1# line-prefix #3#= erc-command PRIVMSG) 180 185 (erc-timestamp 0 wrap-prefix #1# line-prefix = #3# erc-command PRIVMSG) 185 187 (erc-timestamp 0 wrap-prefix #1# line-pref= ix #3# erc-command PRIVMSG) 187 190 (erc-timestamp 0 wrap-prefix #1# line-p= refix #3# erc-command PRIVMSG) 190 303 (erc-timestamp 0 wrap-prefix #1# lin= e-prefix #3# erc-command PRIVMSG) 303 304 (erc-timestamp 0 erc-command PRIV= MSG) 304 336 (erc-timestamp 0 wrap-prefix #1# line-prefix #3# erc-command P= RIVMSG) 337 344 (erc-timestamp 0 display (#4# #("[00:00]" 0 7 (invisible ti= mestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefi= x #1# line-prefix #5=3D(space :width (- 27 (6)))) 344 345 (erc-timestamp 0 = wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 345 348 (erc-timestamp= 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 348 350 (erc-timest= amp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 350 355 (erc-tim= estamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 355 430 (erc-= timestamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file --=20 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 18 Jul 2023 13:34:04 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jul 18 09:34:04 2023 Received: from localhost ([127.0.0.1]:52184 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qLkq1-0004Pk-Su for submit <at> debbugs.gnu.org; Tue, 18 Jul 2023 09:34:04 -0400 Received: from mail-108-mta65.mxroute.com ([136.175.108.65]:39937) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qLkpx-0004PW-Qn for 60936 <at> debbugs.gnu.org; Tue, 18 Jul 2023 09:34:00 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta65.mxroute.com (ZoneMTA) with ESMTPSA id 189693512650004cef.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Tue, 18 Jul 2023 13:33:53 +0000 X-Zone-Loop: e6596667c119d592c9a000fdaa2c96f30fd138469671 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=/KmYJHcHXpDPj6lExksTlYtny+CsWI6EwvWDVenfZMY=; b=U7Uafni8X7S5aDsV/8Qg2oVYND AyHrZI66GvxAky1l9yrfpMKJ/8mtJHNuWm3NlzF/Y8qxyGuh1GrrKSRNR6Q8KhInTHZIkA2NPg1s6 kYZkObDzpz83Lxeikg0W5Rs7aL45a39yb2nHEyd/gvsSG8SvVlhpUfYGxO52GyX60NWYOrLN3suoA qRTEsKAfoMfwJMVHLTvdstjX5nn9cLDGbU8LBjP/EpTHPx0bKCGiMsOcRQZ3Q7KwQKX9TtMuuqQ2b rzCWjm5vRkxj5DKSIvKFB4Ub+DkHgas72M4l+ZGKFs5pESauyabmIxjXhJilf44/go4LEbhHyI4t1 /Npoj2eQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Tue, 18 Jul 2023 06:33:49 -0700 Message-ID: <87msztl4xu.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain This feature initially included a small omission in its lack of support for left-sided time stamps. Apparently, they're popular enough to warrant the additional complexity. The attached patch attempts to add that support as well as fix a few related bugs. It currently introduces two options: `erc-fill-wrap-margin-width' `erc-fill-wrap-margin-side' Both are nil by default, but the second must be customized for users who define their own `erc-insert-timestamp-function'. Note that this variant behaves a little differently with regard to the prompt, which appears in the left margin via `display' properties. The option `erc-fill-wrap-width' controls the margin's starting width, which defaults to either stamp width or prompt width: whichever's wider on MOTD. The prompt is padded on the left and truncated on the right if need be to conform to the margin. This look may take some getting used to, but I think most will agree that it's preferable to the alternative, which would see the prompt floating in no man's land, between the margin and the "static center," where speaker labels are right-aligned. As with the right margin, the left can also be adjusted in-session with the command `erc-fill-wrap-nudge' and the keys `)', `_', and `+'. On a related note, I'm also proposing we remove the `margin' Custom :type choice for the option `erc-timestamp-align-to' (new in 5.6). It was only ever tangentially related and doesn't really do much, and it only really existed to service the needs of the internal minor mode `erc-stamp--display-margin-mode'. Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Make-erc-fill-wrap-work-with-left-hand-stamps.patch Content-Transfer-Encoding: quoted-printable From 9760eb1d16503f173f6ea952c41e5efcb2010a61 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 14 Jul 2023 06:12:30 -0700 Subject: [PATCH] [5.6] Make erc-fill-wrap work with left-hand stamps * etc/ERC-NEWS: Remove all mention of option `erc-timestamp-align-to' supporting a value of `margin', which has been removed. * lisp/erc/erc-backend.el (erc--reveal-prompt, erc--conceal-prompt): New generic functions with default implementations factored out from `erc--unhide-prompt' and `erc--hide-prompt'. (erc--prompt-hidden-p): New internal predicate function. (erc--unhide-prompt): Defer to `erc--reveal-prompt' and set `erc-prompt' text property to t. (erc--hide-prompt): Defer to `erc--conceal-prompt' and set `erc-prompt' text property to `hidden'. * lisp/erc/erc-compat.el (erc-compat--29-browse-url-irc): Add FIXME comment for likely insufficient test of function equality. * lisp/erc/erc-fill.el (erc-fill-wrap-margin-width, erc-fill-wrap-margin-side): New options to control side and initial width of `fill-wrap' margin. (erc-fill--wrap-beginning-of-line): Fix bug involving non-string valued `display' props. (erc-fill-wrap-mode, erc-fill-wrap-enable): Update doc string, persist a few local vars, and conditionally set `erc-stamp--margin-left-p'. (erc-fill-wrap-nudge): Update doc string and account for left-hand stamps. (erc-timestamp-offset): Add comment regarding conditional guard based on function-valued option. * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Remove value variant `margin', which was originally intended to be new in ERC 5.6. This functionality was all but useless without the internal minor mode `erc-stamp--display-margin-mode' active. (erc-stamp-right-margin-width): Remove unused option new in 5.6. (erc-stamp--display-margin-force): Remove unused function. (erc-stamp--margin-width, erc-stamp--margin-left-p): New internal var. (erc-stamp--margin-left-p, erc-stamp--init-margins-on-connect): New functions for other modules that use `erc-stamp--display-margin-mode'. (erc-stamp--adjust-right-margin, erc-stamp--adjust-margin): Rename function to latter and accommodate left-hand stamps. (erc-stamp--inherited-props): Relocate from lower down in file. (erc-stamp--display-margin-mode): Update function name, and adjust setup and teardown to accommodate left-handed stamps. Don't add advice around `erc-insert-timestamp-function'. (erc-stamp--last-prompt, erc-stamp--display-prompt-in-left-margin): New function and helper var to convert a normal inserted prompt so that it appears in the left margin. (erc-stamp--refresh-left-margin-prompt): Helper for other modules to quickly refresh prompt outside of insert hooks. (erc--reveal-prompt, erc--conceal-prompt): New implementations for when `erc-stamp--display-margin-mode' is active. (erc-insert-timestamp-left): Convert to defmethod and provide implementation for `erc-stamp--display-margin-mode'. (erc-insert-timestamp-right): Don't expect `erc-timestamp-align-to' to ever be the symbol `margin'. Move handling for that case to one contingent on the internal minor mode `erc-stamp--display-margin-mode' being active. * lisp/erc/erc.el (erc--refresh-prompt-hook): New variable. (erc--refresh-prompt): Fix bug in which user-defined prompt functions failed to hide when quitting in server buffers. Run new hook `erc--refresh-prompt-hook'. (erc-display-prompt): Add comment noting that the text property `erc-prompt' now actually matters. It's t while a session is running and `hidden' when disconnected. * test/lisp/erc/erc-fill-tests.el (erc-fill--left-hand-stamps): New test. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--margin, erc-stamp--display-margin-mode--right): Rename test to latter. * test/lisp/erc/erc-tests.el (erc-hide-prompt): Add some assertions for new possible value of `erc-prompt' text property. * test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld: New test data file. (Bug#60936) --- etc/ERC-NEWS | 7 +- lisp/erc/erc-backend.el | 23 +- lisp/erc/erc-compat.el | 1 + lisp/erc/erc-fill.el | 76 +++++-- lisp/erc/erc-stamp.el | 199 +++++++++++++----- lisp/erc/erc.el | 26 ++- test/lisp/erc/erc-fill-tests.el | 37 ++++ test/lisp/erc/erc-stamp-tests.el | 2 +- test/lisp/erc/erc-tests.el | 6 + .../fill/snapshots/stamps-left-01.eld | 1 + 10 files changed, 281 insertions(+), 97 deletions(-) create mode 100644 test/lisp/erc/resources/fill/snapshots/stamps-left-01.e= ld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index cd0b8e5f823..379d5eb2ad0 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -102,11 +102,8 @@ side window. Hit '<RET>' over a nick to spawn a "/QUE= RY" or a ** The option 'erc-timestamp-use-align-to' is more versatile. While this option has always offered to right-align stamps via the 'display' text property, it's now more effective at doing so when set -to a number indicating an offset from the right edge. And when set to -the symbol 'margin', it displays stamps in the right margin, although, -at the moment, this is mostly intended for use by other modules, such -as 'fill-wrap', described above. For both these variants, users of -the 'log' module may want to customize 'erc-log-filter-function' to +to a number indicating an offset from the right edge. Users of the +'log' module may want to customize 'erc-log-filter-function' to 'erc-stamp-prefix-log-filter' to avoid ragged right-hand stamps appearing in their saved logs. =20 diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 363509d17fa..eb3ec39fedd 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1045,13 +1045,25 @@ erc-process-sentinel-1 ;; unexpected disconnect (erc-process-sentinel-2 event buffer)))) =20 +(cl-defmethod erc--reveal-prompt () + (remove-text-properties erc-insert-marker erc-input-marker + '(display nil))) + +(cl-defmethod erc--conceal-prompt () + (add-text-properties erc-insert-marker (1- erc-input-marker) + `(display ,erc-prompt-hidden))) + +(defun erc--prompt-hidden-p () + (and (marker-position erc-insert-marker) + (eq (get-text-property erc-insert-marker 'erc-prompt) 'hidden))) + (defun erc--unhide-prompt () (remove-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert t) (when (and (marker-position erc-insert-marker) (marker-position erc-input-marker)) (with-silent-modifications - (remove-text-properties erc-insert-marker erc-input-marker - '(display nil))))) + (put-text-property erc-insert-marker (1- erc-input-marker) 'erc-prom= pt t) + (erc--reveal-prompt)))) =20 (defun erc--unhide-prompt-on-self-insert () (when (and (eq this-command #'self-insert-command) @@ -1059,6 +1071,8 @@ erc--unhide-prompt-on-self-insert (erc--unhide-prompt))) =20 (defun erc--hide-prompt (proc) + "Hide prompt in all buffers of server. +Change value of property `erc-prompt' from t to `hidden'." (erc-with-all-buffers-of-server proc nil (when (and erc-hide-prompt (or (eq erc-hide-prompt t) @@ -1072,8 +1086,9 @@ erc--hide-prompt (marker-position erc-input-marker) (get-text-property erc-insert-marker 'erc-prompt)) (with-silent-modifications - (add-text-properties erc-insert-marker (1- erc-input-marker) - `(display ,erc-prompt-hidden))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'erc-prompt 'hidden) + (erc--conceal-prompt)) (add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 91 t= )))) =20 (defun erc-process-sentinel (cproc event) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index f451aaee754..912a4bc576c 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -418,6 +418,7 @@ erc-compat--29-browse-url-irc (require 'url-irc) (let* ((url (url-generic-parse-url string)) (url-irc-function + ;; FIXME this should probably use `symbol-function'. (if (function-equal url-irc-function 'url-irc-erc) (lambda (host port chan user pass) (erc-handle-irc-url host port chan user pass (url-type url= ))) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index a65c95f1d85..99035b35011 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -116,6 +116,25 @@ erc-fill-column "The column at which a filled paragraph is broken." :type 'integer) =20 +(defcustom erc-fill-wrap-margin-width nil + "Starting width in columns of dedicated stamp margin. +When nil, ERC normally pretends its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +However, when `erc-fill-wrap-margin-side' is `left' or +\"resolves\" to `left', ERC uses the width of the prompt if it's +wider on MOTD's end, which really only matters when `erc-prompt' +is a function." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice nil integer)) + +(defcustom erc-fill-wrap-margin-side nil + "Margin side to use with `erc-fill-wrap-mode'. +A value of nil means ERC should decide based on +`erc-insert-timestamp-function', which obviously cannot work for +user-defined functions." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (choice nil) (const left) (const right))) + (defcustom erc-fill-line-spacing nil "Extra space between messages on graphical displays. This may need adjusting depending on how your faces are @@ -253,9 +272,9 @@ erc-fill--wrap-beginning-of-line (goto-char erc-input-marker) ;; Mimic what `move-beginning-of-line' does with invisible text. (when-let ((erc-fill-wrap-merge) - (empty (get-text-property (point) 'display)) - ((string-empty-p empty))) - (goto-char (text-property-not-all (point) (pos-eol) 'display empty))= ))) + (prop (get-text-property (point) 'display)) + ((or (equal prop "") (eq 'margin (car-safe (car-safe prop))= )))) + (goto-char (text-property-not-all (point) (pos-eol) 'display prop)))= )) =20 (defun erc-fill--wrap-end-of-line (arg) "Defer to `move-end-of-line' or `end-of-visual-line'." @@ -319,21 +338,33 @@ fill-wrap "Fill style leveraging `visual-line-mode'. This local module displays nicks overhanging leftward to a common offset, as determined by the option `erc-fill-static-center'. It -depends on the `fill' and `button' modules and assumes the option -`erc-insert-timestamp-function' is `erc-insert-timestamp-right' -or the default `erc-insert-timestamp-left-and-right', so that it -can display right-hand stamps in the right margin. A value of -`erc-insert-timestamp-left' is unsupported. To use it, either -include `fill-wrap' in `erc-modules' or set `erc-fill-function' -to `erc-fill-wrap' (recommended). You can also manually invoke -one of the minor-mode toggles if really necessary." +depends on the `fill' and `button' modules and assumes users +who've defined their own `erc-insert-timestamp-function' have +also customized the option `erc-fill-wrap-margin-side' to an +explicit side. To use this module, either include `fill-wrap' in +`erc-modules' or set `erc-fill-function' to +`erc-fill-wrap' (recommended). You can also manually invoke one +of the minor-mode toggles if really necessary. + +When stamps appear in the right margin, which they do by default, +users may find that ERC actually appends them to copy-as-killed +messages without an intervening space. This normally poses at +most a minor nuisance, however users of the `log' module may +prefer a workaround provided by `erc-stamp-prefix-log-filter', +which strips trailing stamps from logged messages and instead +prepends them to every line." ((erc-fill--wrap-ensure-dependencies) - ;; Restore or initialize local state variables. (erc--restore-initialize-priors erc-fill-wrap-mode erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys - erc-fill--wrap-value erc-fill-static-center) + erc-fill--wrap-value erc-fill-static-center + erc-stamp--margin-width erc-fill-wrap-margin-width + left-margin-width 0 + right-margin-width 0) + ;; Only give this a local binding if known for sure. + (pcase erc-fill-wrap-margin-side + ('right (setq erc-stamp--margin-left-p nil)) + ('left (setq erc-stamp--margin-left-p t))) (setq erc-fill--function #'erc-fill-wrap) - ;; Internal integrations. (add-function :after (local 'erc-stamp--insert-date-function) #'erc-fill--wrap-stamp-insert-prefixed-date) (when (or erc-stamp-mode (memq 'stamp erc-modules)) @@ -476,8 +507,8 @@ erc-fill-wrap-nudge \\`=3D' Increase indentation by one column \\`-' Decrease indentation by one column \\`0' Reset indentation to the default - \\`+' Shift right margin rightward (shrink) by one column - \\`_' Shift right margin leftward (grow) by one column + \\`+' Shift margin boundary rightward by one column + \\`_' Shift margin boundary leftward by one column \\`)' Reset the right margin to the default =20 Note that misalignment may occur when messages contain @@ -507,14 +538,16 @@ erc-fill-wrap-nudge (cl-incf total (erc-fill--wrap-nudge a)) (recenter (round (* win-ratio (window-height)))))= ))) (dolist (key '(?\) ?_ ?+)) - (let ((a (pcase key - (?\) 0) - (?_ (- (abs arg))) - (?+ (abs arg))))) + (let* ((leftp erc-stamp--margin-left-p) + (a (pcase key + (?\) 0) + (?_ (if leftp (abs arg) (- (abs arg)))) + (?+ (if leftp (- (abs arg)) (abs arg)))))) (define-key map (vector (list key)) (lambda () (interactive) - (erc-stamp--adjust-right-margin (- a)) + (erc-stamp--adjust-margin (- a) (zerop a)) + (when leftp (erc-stamp--refresh-left-margin-promp= t)) (recenter (round (* win-ratio (window-height)))))= ))) map) t @@ -536,6 +569,7 @@ erc-timestamp-offset "Get length of timestamp if inserted left." (if (and (boundp 'erc-timestamp-format) erc-timestamp-format + ;; FIXME use a more robust test than symbol equivalence. (eq erc-insert-timestamp-function 'erc-insert-timestamp-left) (not erc-hide-timestamps)) (length (format-time-string erc-timestamp-format)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 83ee4a200ed..727d334f13b 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -281,49 +281,67 @@ erc-timestamp-use-align-to set to `erc-insert-timestamp-right' or that option's default, `erc-insert-timestamp-left-and-right'. If the value is a positive integer, alignment occurs that many columns from the -right edge. If the value is `margin', the stamp appears in the -right margin when visible. +right edge. =20 Enabling this option produces a side effect in that stamps aren't indented in saved logs. When its value is an integer, this option adds a space after the end of a message if the stamp doesn't already start with one. And when its value is t, it adds -a single space, unconditionally. And while this option never -adds a space when its value is `margin', ERC does offer a -workaround in `erc-stamp-prefix-log-filter', which strips -trailing stamps from messages and puts them before every line." - :type '(choice boolean integer (const margin)) +a single space, unconditionally." + :type '(choice boolean integer) :package-version '(ERC . "5.6")) ; FIXME sync on release =20 -(defcustom erc-stamp-right-margin-width nil - "Width in columns of the right margin. -When this option is nil, pretend its value is one column greater -than the `string-width' of the formatted `erc-timestamp-format'. -This option only matters when `erc-timestamp-use-align-to' is set -to `margin'." - :package-version '(ERC . "5.6") ; FIXME sync on release - :type '(choice (const nil) integer)) - -(defun erc-stamp--display-margin-force (orig &rest r) - (let ((erc-timestamp-use-align-to 'margin)) - (apply orig r))) - -(defun erc-stamp--adjust-right-margin (cols) - "Adjust right margin by COLS. -When COLS is zero, reset width to `erc-stamp-right-margin-width' -or one col more than the `string-width' of -`erc-timestamp-format'." - (let ((width - (if (zerop cols) - (or erc-stamp-right-margin-width - (1+ (string-width (or erc-timestamp-last-inserted-right - (erc-format-timestamp - (current-time) - erc-timestamp-format))))) - (+ right-margin-width cols)))) - (setq right-margin-width width) +(defvar-local erc-stamp--margin-width nil + "Width in columns of margin for `erc-stamp--display-margin-mode'. +Only consulted when resetting or initializing margin.") + +(defvar-local erc-stamp--margin-left-p nil + "Whether `erc-stamp--display-margin-mode' uses the left margin. +During initialization, the mode respects this variable's existing +value if it already has a local binding. Otherwise, modules can +bind this to any value while enabling the mode. If it's nil, ERC +will check to see if `erc-insert-timestamp-function' is +`erc-insert-timestamp-left', interpreting the latter as a non-nil +value. It'll then coerce any non-nil value to t.") + +(defun erc-stamp--margin-left-p (&optional value) + (and (or value + (function-equal (symbol-function (default-value + 'erc-insert-timestamp-functio= n)) + (symbol-function 'erc-insert-timestamp-left))) + t)) + +(defun erc-stamp--init-margins-on-connect (&rest _) + (let ((existing (if erc-stamp--margin-left-p + left-margin-width + right-margin-width))) + (erc-stamp--adjust-margin existing 'resetp))) + +(defun erc-stamp--adjust-margin (cols &optional resetp) + "Adjust managed margin by increment COLS. +With RESETP, set margin's width to COLS. However, if COLS is +zero, set the width to a non-nil `erc-stamp--margin-width'. +Otherwise, go with the `string-width' of `erc-timestamp-format'. +However, when `erc-stamp--margin-left-p' is non-nil and the +prompt is wider, use its width instead." + (let* ((leftp erc-stamp--margin-left-p) + (width + (if resetp + (or (and (not (zerop cols)) cols) + erc-stamp--margin-width + (max (if leftp (string-width (erc-prompt)) 0) + (1+ (string-width + (or (if leftp + erc-timestamp-last-inserted + erc-timestamp-last-inserted-right) + (erc-format-timestamp + (current-time) erc-timestamp-format)))))) + (+ (if leftp left-margin-width right-margin-width) cols)))) + (set (if leftp 'left-margin-width 'right-margin-width) width) (when (eq (current-buffer) (window-buffer)) - (set-window-margins nil left-margin-width width)))) + (set-window-margins nil + (if leftp width left-margin-width) + (if leftp right-margin-width width))))) =20 ;;;###autoload (defun erc-stamp-prefix-log-filter (text) @@ -348,39 +366,97 @@ erc-stamp-prefix-log-filter (zerop (forward-line)))) "") =20 +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (declare-function erc--remove-text-properties "erc" (string)) =20 -;; If people want to use this directly, we can convert it into -;; a local module. +;; If people want to use this directly, we can convert it into a local +;; module. Also, `erc-insert-timestamp-right' hard codes its display +;; property to use `right-margin', and `erc-insert-timestamp-left' +;; does the same for `left-margin'. However, there's no reason a +;; trailing stamp couldn't be displayed on the left and vice versa. +;; Note: this adds advice that breaks `erc-timestamp-offset' because +;; the thinking is there's no use case in which that function would be +;; called while this mode is active. See note below for more. (define-minor-mode erc-stamp--display-margin-mode "Internal minor mode for built-in modules integrating with `stamp'. -It binds `erc-timestamp-use-align-to' to `margin' around calls to -`erc-insert-timestamp-function' in the current buffer, and sets -the right window margin to `erc-stamp-right-margin-width'. It -also arranges to remove most text properties when a user kills -message text so that stamps will be visible when yanked." +Manages chosen window margin and arranges to remove `display' +text properties in killed text to reveal stamps." :interactive nil (if erc-stamp--display-margin-mode (progn (setq fringes-outside-margins t) (when (eq (current-buffer) (window-buffer)) (set-window-buffer (selected-window) (current-buffer))) - (erc-stamp--adjust-right-margin 0) + (unless (local-variable-p 'erc-stamp--margin-left-p) + (setq erc-stamp--margin-left-p + (erc-stamp--margin-left-p erc-stamp--margin-left-p))) + (if (or erc-server-connected (not (functionp erc-prompt))) + (erc-stamp--init-margins-on-connect) + (add-hook 'erc-after-connect + #'erc-stamp--init-margins-on-connect nil t)) (add-function :filter-return (local 'filter-buffer-substring-funct= ion) #'erc--remove-text-properties) - (add-function :around (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force)) + (when erc-stamp--margin-left-p + (add-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin nil t))) (remove-function (local 'filter-buffer-substring-function) #'erc--remove-text-properties) - (remove-function (local 'erc-insert-timestamp-function) - #'erc-stamp--display-margin-force) - (kill-local-variable 'right-margin-width) + (add-hook 'erc-after-connect #'erc-stamp--init-margins-on-connect t) + (remove-hook 'erc--refresh-prompt-hook + #'erc-stamp--display-prompt-in-left-margin t) + (kill-local-variable (if erc-stamp--margin-left-p + 'left-margin-width + 'right-margin-width)) (kill-local-variable 'fringes-outside-margins) + (kill-local-variable 'erc-stamp--margin-prompt-width) + (kill-local-variable 'erc-stamp--margin-left-p) + (kill-local-variable 'erc-stamp--margin-width) (when (eq (current-buffer) (window-buffer)) (set-window-margins nil left-margin-width nil) (set-window-buffer (selected-window) (current-buffer))))) =20 -(defun erc-insert-timestamp-left (string) +(defvar-local erc-stamp--last-prompt nil) + +(defun erc-stamp--display-prompt-in-left-margin () + "Show prompt in the left margin with padding." + (when (or (not erc-stamp--last-prompt) (functionp erc-prompt) + (> (string-width erc-stamp--last-prompt) left-margin-width)) + (let ((s (buffer-substring erc-insert-marker (1- erc-input-marker)))) + ;; Prevent #("abc" n m (display ((...) #("abc" p q (display...)))) + (remove-text-properties 0 (length s) '(display nil) s) + (when (and erc-stamp--last-prompt + (>=3D (string-width erc-stamp--last-prompt) left-margin-w= idth)) + (let ((sm (truncate-string-to-width s (1- left-margin-width) 0 nil= t))) + ;; This papers over a subtle off-by-1 bug here. + (unless (equal sm s) + (setq s (concat sm (substring s -1)))))) + (setq erc-stamp--last-prompt (string-pad s left-margin-width nil t))= )) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt)) + erc-stamp--last-prompt) + +(defun erc-stamp--refresh-left-margin-prompt () + "Forcefully-recompute display property of prompt in left margin." + (with-silent-modifications + (unless (functionp erc-prompt) + (setq erc-stamp--last-prompt nil)) + (erc--refresh-prompt))) + +(cl-defmethod erc--reveal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,erc-stamp--last-prom= pt))) + +(cl-defmethod erc--conceal-prompt + (&context (erc-stamp--display-margin-mode (eql t)) + (erc-stamp--margin-left-p (eql t))) + (let ((prompt (string-pad erc-prompt-hidden left-margin-width nil 'start= ))) + (put-text-property erc-insert-marker (1- erc-input-marker) + 'display `((margin left-margin) ,prompt)))) + +(cl-defmethod erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." (goto-char (point-min)) (let* ((ignore-p (and erc-timestamp-only-if-changed-flag @@ -392,6 +468,22 @@ erc-insert-timestamp-left (erc-put-text-property 0 len 'invisible erc-stamp--invisible-property = s) (insert s))) =20 +(cl-defmethod erc-insert-timestamp-left + (string &context (erc-stamp--display-margin-mode (eql t))) + (unless (and erc-timestamp-only-if-changed-flag + (string-equal string erc-timestamp-last-inserted)) + (goto-char (point-min)) + (insert-before-markers-and-inherit + (setq erc-timestamp-last-inserted string)) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (point) p))) + (put-text-property (point-min) (point) p v))) + (erc-put-text-property (point-min) (point) 'invisible + erc-stamp--invisible-property) + (put-text-property (point-min) (point) 'field 'erc-timestamp) + (put-text-property (point-min) (point) + 'display `((margin left-margin) ,string)))) + (defun erc-insert-aligned (string pos) "Insert STRING at the POSth column. =20 @@ -408,8 +500,6 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) =20 -(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) - (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -465,6 +555,9 @@ erc-insert-timestamp-right ;; For compatibility reasons, the `erc-timestamp' field includes ;; intervening white space unless a hard break is warranted. (pcase erc-timestamp-use-align-to + ((guard erc-stamp--display-margin-mode) + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) stri= ng)) ((and 't (guard (< col pos))) (insert " ") (put-text-property from (point) 'display `(space :align-to ,pos))) @@ -475,10 +568,6 @@ erc-insert-timestamp-right (let ((s (+ erc-timestamp-use-align-to (string-width string)))) (put-text-property from (point) 'display `(space :align-to (- right ,s))))) - ('margin - (put-text-property 0 (length string) - 'display `((margin right-margin) ,string) - string)) ((guard (>=3D col pos)) (newline) (indent-to pos) (setq from (poin= t))) (_ (indent-to pos))) (insert string) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 03c21059a92..c90f20cc9a4 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2879,19 +2879,23 @@ erc--assert-input-bounds (cl-assert (< erc-insert-marker erc-input-marker)) (cl-assert (=3D (field-end erc-insert-marker) erc-input-marker))= ))) =20 +(defvar erc--refresh-prompt-hook nil) + (defun erc--refresh-prompt () "Re-render ERC's prompt when the option `erc-prompt' is a function." (erc--assert-input-bounds) - (when (functionp erc-prompt) - (save-excursion - (goto-char erc-insert-marker) - (set-marker-insertion-type erc-insert-marker nil) - ;; Avoid `erc-prompt' (the named function), which appends a - ;; space, and `erc-display-prompt', which propertizes all but - ;; that space. - (insert-and-inherit (funcall erc-prompt)) - (set-marker-insertion-type erc-insert-marker t) - (delete-region (point) (1- erc-input-marker))))) + (unless (erc--prompt-hidden-p) + (when (functionp erc-prompt) + (save-excursion + (goto-char erc-insert-marker) + (set-marker-insertion-type erc-insert-marker nil) + ;; Avoid `erc-prompt' (the named function), which appends a + ;; space, and `erc-display-prompt', which propertizes all but + ;; that space. + (insert-and-inherit (funcall erc-prompt)) + (set-marker-insertion-type erc-insert-marker t) + (delete-region (point) (1- erc-input-marker)))) + (run-hooks 'erc--refresh-prompt-hook))) =20 (defun erc-display-line-1 (string buffer) "Display STRING in `erc-mode' BUFFER. @@ -4804,7 +4808,7 @@ erc-display-prompt ;; shall remain part of the prompt. (setq prompt (propertize prompt 'rear-nonsticky t - 'erc-prompt t + 'erc-prompt t ; t or `hidden' 'field 'erc-prompt 'front-sticky t 'read-only t)) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index 99ec4a9635e..67622da9f3d 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -340,4 +340,41 @@ erc-fill-wrap-visual-keys--prompt (should (search-backward "ERC> " nil t)) (execute-kbd-macro "\C-a"))))) =20 +(ert-deftest erc-fill--left-hand-stamps () + :tags '(:unstable) + (unless (>=3D emacs-major-version 29) + (ert-skip "Emacs version too low, missing `buffer-text-pixel-size'")) + + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-insert-timestamp-function #'erc-insert-timestamp-left)) + (erc-fill-tests--wrap-populate + (lambda () + (should (=3D 8 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 4 8 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face))))) + (erc-fill-tests--compare "stamps-left-01") + + (ert-info ("Shrink left margin by 1 col") + (erc-stamp--adjust-margin -1) + (with-silent-modifications (erc--refresh-prompt)) + (should (=3D 7 left-margin-width)) + (pcase-let ((`((margin left-margin) ,displayed) + (get-text-property erc-insert-marker 'display))) + (should (equal-including-properties + displayed #(" ERC>" 3 7 + ( read-only t + front-sticky t + field erc-prompt + erc-prompt t + rear-nonsticky t + font-lock-face erc-prompt-face)))))))))) + ;;; erc-fill-tests.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tes= ts.el index 6da7ed4503d..f6de087a09a 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -140,7 +140,7 @@ erc-timestamp-use-align-to--integer (should (eql ?\s (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) =20 -(ert-deftest erc-timestamp-use-align-to--margin () +(ert-deftest erc-stamp--display-margin-mode--right () (erc-stamp-tests--insert-right (lambda () (erc-stamp--display-margin-mode +1) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b5db5fe8764..fff3c4cb704 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -219,6 +219,7 @@ erc-hide-prompt (setq erc-hide-prompt '(server)) (with-current-buffer "ServNet" (erc--hide-prompt erc-server-process) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay)))) =20 (with-current-buffer "#chan" @@ -229,6 +230,7 @@ erc-hide-prompt =20 (with-current-buffer "ServNet" (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: channel") @@ -242,7 +244,9 @@ erc-hide-prompt =20 (with-current-buffer "#chan" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display)))) =20 (ert-info ("Value: query") @@ -253,7 +257,9 @@ erc-hide-prompt =20 (with-current-buffer "bob" (should (string=3D ">" (get-text-property erc-insert-marker 'displ= ay))) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) 'hid= den)) (erc--unhide-prompt) + (should (eq (get-text-property erc-insert-marker 'erc-prompt) t)) (should-not (get-text-property erc-insert-marker 'display))) =20 (with-current-buffer "#chan" diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld b/te= st/lisp/erc/resources/fill/snapshots/stamps-left-01.eld new file mode 100644 index 00000000000..f62b65cd170 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld @@ -0,0 +1 @@ +#("\n\n[00:00]*** 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 o= wner(s), please disconnect.\n[00:00]<alice> bob: come, you are a tedious fo= ol: to the purpose. What was done to Elbow's wife, that he hath cause to co= mplain of? Come me to what was done to her.\n[00:00]<bob> alice: Either you= r unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 9 (erc= -timestamp 0 display (#4=3D(margin left-margin) #("[00:00]" 0 7 (invisible = timestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-pre= fix #1=3D(space :width 27) line-prefix #2=3D(space :width (- 27 (4)))) 9 17= 1 (erc-timestamp 0 wrap-prefix #1# line-prefix #2#) 172 179 (erc-timestamp = 0 display (#4# #("[00:00]" 0 7 (invisible timestamp font-lock-face erc-time= stamp-face))) field erc-timestamp wrap-prefix #1# line-prefix #3=3D(space := width (- 27 (8)))) 179 180 (erc-timestamp 0 wrap-prefix #1# line-prefix #3#= erc-command PRIVMSG) 180 185 (erc-timestamp 0 wrap-prefix #1# line-prefix = #3# erc-command PRIVMSG) 185 187 (erc-timestamp 0 wrap-prefix #1# line-pref= ix #3# erc-command PRIVMSG) 187 190 (erc-timestamp 0 wrap-prefix #1# line-p= refix #3# erc-command PRIVMSG) 190 303 (erc-timestamp 0 wrap-prefix #1# lin= e-prefix #3# erc-command PRIVMSG) 303 304 (erc-timestamp 0 erc-command PRIV= MSG) 304 336 (erc-timestamp 0 wrap-prefix #1# line-prefix #3# erc-command P= RIVMSG) 337 344 (erc-timestamp 0 display (#4# #("[00:00]" 0 7 (invisible ti= mestamp font-lock-face erc-timestamp-face))) field erc-timestamp wrap-prefi= x #1# line-prefix #5=3D(space :width (- 27 (6)))) 344 345 (erc-timestamp 0 = wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 345 348 (erc-timestamp= 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 348 350 (erc-timest= amp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 350 355 (erc-tim= estamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG) 355 430 (erc-= timestamp 0 wrap-prefix #1# line-prefix #5# erc-command PRIVMSG)) \ No newline at end of file --=20 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 3 Jul 2023 13:14:49 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jul 03 09:14:49 2023 Received: from localhost ([127.0.0.1]:33472 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qGJOA-0000qg-Po for submit <at> debbugs.gnu.org; Mon, 03 Jul 2023 09:14:49 -0400 Received: from mail-108-mta165.mxroute.com ([136.175.108.165]:33525) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qGJO4-0000qR-Ev for 60936 <at> debbugs.gnu.org; Mon, 03 Jul 2023 09:14:45 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta165.mxroute.com (ZoneMTA) with ESMTPSA id 1891be40033000aa88.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Mon, 03 Jul 2023 13:14:34 +0000 X-Zone-Loop: dd0ffb3dc3e2b94c67588d883e925970b6e3e6a228ef 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=zBq3pPyB6xFC7QnpNGVKxeJdz1+qMsHDWE0YZsjYWQg=; b=fARfRTppMp/J+gyhw5WoTuMJwQ AgwLNVHoWNHiFxALWJCh0C6MYzXWDZpS0WfAZ+1SrbEE/peenkizB/XwecnAP3okWyJAwVhtZzDDe E/jodm7x91SPcwdt0RXISRoYGKahnxBggqVN4OH+FGxQpy865NWIquKWBSF2QYjnlwuseOpFkBAQE OozuWtMarsNcGVlkF/NC0Ea/8W3hq/YJXtWBmHzZhiv0VaaxZIoEyN67RvHEtvr9UhmWji0Y24ehx tHx93XHlH58HrtLaGzn6umyHH1TYzvsanj8Ntg39hdEnxHdP9dJW76pvnmndlcRR9LxXWNgk3q3Vx mIvxnOAw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87jzvny7ez.fsf@HIDDEN> (J. P.'s message of "Wed, 28 Jun 2023 07:43:00 -0700") References: <87tu0nao77.fsf@HIDDEN> <87jzvny7ez.fsf@HIDDEN> Date: Mon, 03 Jul 2023 06:14:31 -0700 Message-ID: <87zg4dm91k.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain "J.P." <jp@HIDDEN> writes: > 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. Actually, the veracity of that claim is unclear and most likely bogus. What is clear is that this approach is unsustainable because related bugs are bound to crop up in the near future (if they haven't already). Basically, in trying to code defensively around possibly encountering unexpected text before inserted messages (such as leading stamps, white space, decorations, etc.), my attempted solution traded superficial robustness for a new dimension of complexity that's almost certainly unsustainable. (This outcome was more or less predicted in the justification for d880a08f "Cement ...", which this fix rather callously contravened the spirit of.) Anyway, to address all this, I think we should: 1. Revert the previous attempted fix, which now exists on HEAD as commit 99d74dcd45938e2686d93eb5649800e14a88cd84 Author: F. Jason Park <jp@HIDDEN> Date: Tue Jun 27 20:47:26 2023 -0700 Account for leading timestamps in erc-match lisp/erc/erc-match.el | 41 ++++++++---- test/lisp/erc/erc-scenarios-match.el | 120 +++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 12 deletions(-) 2. Undo the change of ordering for `erc-add-timestamp' and `erc-match-message' in `erc-insert-modify-hook' (from d880a08f "Cement ..."). 3. Take an entirely different tack bent on including (rather than omitting) time stamps from invisible messages. If not yet obvious, the impetus for the poor decision (of mine) to switch the order of those hook members was to improve the toggling of invisible elements created by the `match' module (and potentially others), and also to make logs less ragged when they feature invisible messages. I'll go ahead and install the first of the attached patches (reverting the misguided fix) and continue to iterate on the second, which proposes the more comprehensive solution described in 3. Thanks. > 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. I've decided to instead lump this in with bug#64301 (speaker labels). --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Revert-Account-for-leading-timestamps-in-erc-match.patch From 226d4371e0d022f5080859736fa9161966049f4f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 2 Jul 2023 20:57:46 -0700 Subject: [PATCH 1/2] Revert "Account for leading timestamps in erc-match" This reverts commit 99d74dcd45938e2686d93eb5649800e14a88cd84 but keeps the test file test/lisp/erc/erc-scenarios-match.el. This also implements a partial alternative solution by undoing the reordering of insert hooks owned by the `stamp' and `match' modules. The reordering was performed as part of d880a08f9592e51ada5749d10b472396683fb6ee "Cement ordering of essential hook members in ERC". The intent was to address the problem of timestamps not being hidden in matched "fool" messages. However, a better approach is to incorporate timestamps into hidden messages by merging `invisible' properties. This will be handled by a future change, most likely lumped in with bug#64301. * erc/ERC-NEWS: Fix erroneous claim about relative hook ordering pre-5.6, which somewhat informs the confusion belying the original wrongheaded change. * lisp/erc/erc-match.el (erc-match-mode, erc-match-enable): Change hook depth for `erc-insert-modify-hook' member from 60 to 50. (erc-text-matched-hook): Retain portion of updated doc string instead of reverting. * lisp/erc/erc-stamp.el (erc-stamp-mode, erc-stamp-enable): Change depth for insert and send-hook members from 50 to 60. * test/lisp/erc/erc-scenarios-match.el (erc-scenarios-match--stamp-left-current-nick erc-scenarios-match--stamp-left-fools-invisible): Temporarily disable the latter and fix expected hook ordering. * test/lisp/erc/erc-tests.el (erc--essential-hook-ordering): Fix expected order of default insert hooks. (Bug#60936) --- etc/ERC-NEWS | 2 +- lisp/erc/erc-match.el | 36 ++++++++-------------------- lisp/erc/erc-stamp.el | 4 ++-- test/lisp/erc/erc-scenarios-match.el | 11 +++++---- test/lisp/erc/erc-tests.el | 4 ++-- 5 files changed, 22 insertions(+), 35 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 2f465e247d7..5665b760ea9 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -183,7 +183,7 @@ Luckily, ERC now leverages a feature introduced in Emacs 27, "hook depth," to secure the positions of a few key members of 'erc-insert-modify-hook' and 'erc-send-modify-hook'. So far, this includes the functions 'erc-button-add-buttons', 'erc-fill', -'erc-add-timestamp', and 'erc-match-message', which now appear in that +'erc-match-message', and 'erc-add-timestamp', which now appear in that order, when present, at depths beginning at 20 and ending below 80. Of most interest to module authors is the new relative positioning of the first two, 'erc-button-add-buttons' and 'erc-fill', which have diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 204bf14a1cf..2b7fff87ff0 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,7 +52,7 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 60) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 50) (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) (unless erc--updating-modules-p (erc-buffer-do #'erc-match--modify-invisibility-spec)) @@ -237,10 +237,7 @@ erc-text-matched-hook 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@HIDDEN 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." +sender, like bob!~bob@HIDDEN" :options '(erc-log-matches erc-hide-fools erc-beep-on-match) :type 'hook) @@ -462,19 +459,8 @@ erc-match-directed-at-fool-p (erc-list-match fools-end msg)))) (defun erc-match-message () - "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) + "Mark certain keywords in a region. +Use this defun with `erc-insert-modify-hook'." ;; This needs some refactoring. (goto-char (point-min)) (let* ((to-match-nick-dep '("pal" "fool" "dangerous-host")) @@ -576,14 +562,12 @@ erc-match--message 'font-lock-face match-face))) ;; Else twiddle your thumbs. (t nil)) - ;; 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))))) + (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/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index aac51135a07..5035e60a87d 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -163,8 +163,8 @@ erc-timestamp-face (define-erc-module stamp timestamp "This mode timestamps messages in the channel buffers." ((add-hook 'erc-mode-hook #'erc-munge-invisibility-spec) - (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 50) - (add-hook 'erc-send-modify-hook #'erc-add-timestamp 50) + (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 60) + (add-hook 'erc-send-modify-hook #'erc-add-timestamp 60) (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) (add-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear) (unless erc--updating-modules-p diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scenarios-match.el index 49e6a3370fc..61368919d31 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -49,8 +49,9 @@ erc-scenarios-match--stamp-left-current-nick :port port :full-name "tester" :nick "tester") - (should (memq 'erc-match-message - (memq 'erc-add-timestamp erc-insert-modify-hook))) + ;; Module `timestamp' precedes `match' in insertion hooks. + (should (memq 'erc-add-timestamp + (memq 'erc-match-message erc-insert-modify-hook))) ;; The "match type" is `current-nick'. (funcall expect 5 "tester") (should (eq (get-text-property (1- (point)) 'font-lock-face) @@ -60,6 +61,7 @@ erc-scenarios-match--stamp-left-current-nick ;; some non-nil invisibility property spans the entire message. (ert-deftest erc-scenarios-match--stamp-left-fools-invisible () :tags '(:expensive-test) + (ert-skip "WIP: fix included in bug#64301") (erc-scenarios-common-with-cleanup ((erc-scenarios-common-dialog "join/legacy") (dumb-server (erc-d-run "localhost" t 'foonet)) @@ -84,8 +86,9 @@ erc-scenarios-match--stamp-left-fools-invisible :full-name "tester" :password "changeme" :nick "tester") - (should (memq 'erc-match-message - (memq 'erc-add-timestamp erc-insert-modify-hook))) + ;; Module `timestamp' precedes `match' in insertion hooks. + (should (memq 'erc-add-timestamp + (memq 'erc-match-message erc-insert-modify-hook))) (funcall expect 5 "This server is in debug mode"))) (ert-info ("Ensure lines featuring \"bob\" are invisible") diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b751ef50520..80c7c708fc5 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1851,8 +1851,8 @@ erc--essential-hook-ordering '( :erc-insert-modify-hook (erc-controls-highlight ; 0 erc-button-add-buttons ; 30 erc-fill ; 40 - erc-add-timestamp ; 50 - erc-match-message) ; 60 + erc-match-message ; 50 + erc-add-timestamp) ; 60 :erc-send-modify-hook ( erc-controls-highlight ; 0 erc-button-add-buttons ; 30 -- 2.41.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Respect-existing-invisibility-props-in-erc-stamp.patch From 2518e294112df689cbcbb3428bd43acc38fd1a5b Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 2 Jul 2023 20:58:37 -0700 Subject: [PATCH 2/2] [5.6] Respect existing invisibility props in erc-stamp * lisp/erc/erc-match.el (erc-hide-fools): change `invisible' property to `erc-match' for all messages, not just those with offset bounds. * lisp/erc/erc-stamp.el (erc-stamp--invisible-property): Add new internal variable to hold existing `invisible' property merged with the one registered by this module. (erc-stamp--skip-when-invisible): Add new internal variable to act as escape hatch for pre ERC-5.6 behavior in which timestamps were not applied at all to invisible messages. This led to strange-looking, uneven logs, and it prevented other modules from offering toggle functionality for invisibility spec members registered to them. (erc-add-timestamp): Merge with existing `invisible' property, when present, instead of clobbering, but only when escape hatch `erc-stamp--skip-when-invisible' is nil. (erc-insert-timestamp-left, erc-format-timestamp): Use possibly merged `invisible' prop value. * test/lisp/erc/erc-scenarios-match.el (erc-scenarios-match--invisible-stamp): Move setup and core assertions for stamp-related tests into fixture. (erc-scenarios-match--stamp-left-fools-invisible): Fix temporarily disabled test and use fixture. (erc-scenarios-match--stamp-right-fools-invisible, erc-scenarios-match--stamp-right-invisible-fill-wrap): New test. --- lisp/erc/erc-match.el | 7 +- lisp/erc/erc-stamp.el | 18 ++- test/lisp/erc/erc-scenarios-match.el | 160 +++++++++++++++++++++++---- 3 files changed, 157 insertions(+), 28 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 2b7fff87ff0..468358536ae 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -669,10 +669,9 @@ erc-hide-fools (save-restriction (widen) (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) - ;; The docs say `intangible' is deprecated, but this has been - ;; like this for ages. Should verify unneeded and remove if so. - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible))))) + ;; Before ERC 5.6, this also used to add an `intangible' + ;; property, but the docs say it's now obsolete. + (put-text-property (point-min) (point-max) 'invisible 'erc-match)))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 5035e60a87d..cc9e0e13083 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -179,6 +179,12 @@ stamp (kill-local-variable 'erc-timestamp-last-inserted-left) (kill-local-variable 'erc-timestamp-last-inserted-right)))) +(defvar erc-stamp--invisible-property nil + "Existing `invisible' property value and/or symbol `timestamp'.") + +(defvar erc-stamp--skip-when-invisible nil + "Escape hatch for omitting stamps when first char is invisible.") + (defun erc-stamp--recover-on-reconnect () (when-let ((priors (or erc--server-reconnecting erc--target-priors))) (dolist (var '(erc-timestamp-last-inserted @@ -209,8 +215,11 @@ erc-add-timestamp (progn ; remove this `progn' on next major refactor (let* ((ct (erc-stamp--current-time)) (invisible (get-text-property (point-min) 'invisible)) + (erc-stamp--invisible-property + ;; FIXME on major version bump, make this `erc-' prefixed. + (if invisible `(timestamp ,@(ensure-list invisible)) 'timestamp)) (erc-stamp--current-time ct)) - (unless invisible + (unless (setq invisible (and erc-stamp--skip-when-invisible invisible)) (funcall erc-insert-timestamp-function (erc-format-timestamp ct erc-timestamp-format))) ;; FIXME this will error when advice has been applied. @@ -380,7 +389,7 @@ erc-insert-timestamp-left (s (if ignore-p (make-string len ? ) string))) (unless ignore-p (setq erc-timestamp-last-inserted string)) (erc-put-text-property 0 len 'field 'erc-timestamp s) - (erc-put-text-property 0 len 'invisible 'timestamp s) + (erc-put-text-property 0 len 'invisible erc-stamp--invisible-property s) (insert s))) (defun erc-insert-aligned (string pos) @@ -477,6 +486,8 @@ erc-insert-timestamp-right (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) + (erc-put-text-property from (point) 'invisible + erc-stamp--invisible-property) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) @@ -520,7 +531,8 @@ erc-format-timestamp (let ((ts (format-time-string format time erc-stamp--tz))) (erc-put-text-property 0 (length ts) 'font-lock-face 'erc-timestamp-face ts) - (erc-put-text-property 0 (length ts) 'invisible 'timestamp ts) + (erc-put-text-property 0 (length ts) 'invisible + erc-stamp--invisible-property ts) (erc-put-text-property 0 (length ts) 'isearch-open-invisible 'timestamp ts) ;; N.B. Later use categories instead of this harmless, but diff --git a/test/lisp/erc/erc-scenarios-match.el b/test/lisp/erc/erc-scenarios-match.el index 61368919d31..9fc744468f3 100644 --- a/test/lisp/erc/erc-scenarios-match.el +++ b/test/lisp/erc/erc-scenarios-match.el @@ -26,6 +26,7 @@ (require 'erc-stamp) (require 'erc-match) +(require 'erc-fill) ;; This defends against a regression in which all matching by the ;; `erc-match-message' fails when `erc-add-timestamp' precedes it in @@ -57,28 +58,20 @@ erc-scenarios-match--stamp-left-current-nick (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) - (ert-skip "WIP: fix included in bug#64301") +;; 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. +(defun erc-scenarios-match--invisible-stamp (hiddenp visiblep) (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)))))) + (expect (erc-d-t-make-expecter))) (ert-info ("Connect") (with-current-buffer (erc :server "127.0.0.1" @@ -94,30 +87,155 @@ erc-scenarios-match--stamp-left-fools-invisible (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)) + (ert-info ("<bob> tester, welcome!") (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)) + (ert-info ("<alice> tester, welcome!") (funcall visiblep)) (should (funcall expect 10 "<bob> alice: But, as it seems")) - (should (funcall hiddenp)) + (ert-info ("<bob> alice: But, as it seems") (funcall hiddenp)) (should (funcall expect 10 "<alice> bob: Well, this is the forest")) - (should (funcall hiddenp)) + (ert-info ("<alice> bob: Well, this is the forest") (funcall hiddenp)) (should (funcall expect 10 "<alice> bob: And will you")) - (should (funcall hiddenp)) + (ert-info ("<alice> bob: And will you") (funcall hiddenp)) (should (funcall expect 10 "<bob> alice: Live, and be prosperous")) - (should (funcall hiddenp)) + (ert-info ("<bob> alice: Live, and be prosperous") (funcall hiddenp)) (should (funcall expect 10 "ERC>")) (should-not (get-text-property (pos-bol) 'invisible)) (should-not (get-text-property (point) 'invisible)))))) +;; This asserts that when stamps appear before a message, registered +;; invisibility properties owned by modules span the entire message. +(ert-deftest erc-scenarios-match--stamp-left-fools-invisible () + :tags '(:expensive-test) + (let ((erc-insert-timestamp-function #'erc-insert-timestamp-left)) + (erc-scenarios-match--invisible-stamp + + (lambda () + ;; This is a time-stamped message. + (should (eq (field-at-pos (pos-bol)) 'erc-timestamp)) + + ;; Leading stamp has combined `invisible' property value. + (should (equal (get-text-property (pos-bol) 'invisible) + '(timestamp erc-match))) + + ;; Message proper has the `invisible' property `erc-match'. + (let ((msg-beg (next-single-property-change (pos-bol) 'invisible))) + (should (eq (get-text-property msg-beg 'invisible) 'erc-match)) + (should (>= (next-single-property-change msg-beg 'invisible nil) + (pos-eol))))) + + (lambda () + ;; This is a time-stamped message. + (should (eq (field-at-pos (pos-bol)) 'erc-timestamp)) + (should (get-text-property (pos-bol) 'invisible)) + + ;; The entire message proper is visible. + (let ((msg-beg (next-single-property-change (pos-bol) 'invisible))) + (should + (= (next-single-property-change msg-beg 'invisible nil (pos-eol)) + (pos-eol)))))))) + +(defun erc-scenarios-match--find-eol () + (save-excursion + (goto-char (next-single-property-change (point) 'erc-command)) + (pos-eol))) + +;; In most cases, `erc-hide-fools' makes line endings invisible. +(ert-deftest erc-scenarios-match--stamp-right-fools-invisible () + :tags '(:expensive-test) + (let ((erc-insert-timestamp-function #'erc-insert-timestamp-right)) + (erc-scenarios-match--invisible-stamp + + (lambda () + (let ((end (erc-scenarios-match--find-eol))) + ;; The end of the message is a newline. + (should (= ?\n (char-after end))) + + ;; Every message has a trailing time stamp. + (should (eq (field-at-pos (1- end)) 'erc-timestamp)) + + ;; Stamps have a combined `invisible' property value. + (should (equal (get-text-property (1- end) 'invisible) + '(timestamp erc-match))) + + ;; The final newline is hidden by `match', not `stamps' + (should (equal (get-text-property end 'invisible) 'erc-match)) + + ;; The message proper has the `invisible' property `erc-match', + ;; and it starts after the preceding newline. + (should (eq (get-text-property (pos-bol) 'invisible) 'erc-match)) + + ;; 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))) + + ;; Stamp's `invisible' property extends throughout the stamp + ;; and ends before the trailing newline. + (should (= (next-single-property-change msg-end 'invisible) end))))) + + (lambda () + (let ((end (erc-scenarios-match--find-eol))) + ;; This message has a time stamp like all the others. + (should (eq (field-at-pos (1- end)) 'erc-timestamp)) + + ;; The entire message proper is visible. + (should-not (get-text-property (pos-bol) 'invisible)) + (let ((inv-beg (next-single-property-change (pos-bol) 'invisible))) + (should (eq (get-text-property inv-beg 'invisible) + 'timestamp)))))))) + +;; This asserts that when `erc-fill-wrap-mode' is enabled, ERC hides +;; the preceding message's line ending. +(ert-deftest erc-scenarios-match--stamp-right-invisible-fill-wrap () + :tags '(:expensive-test) + (let ((erc-insert-timestamp-function #'erc-insert-timestamp-right) + (erc-fill-function #'erc-fill-wrap)) + (erc-scenarios-match--invisible-stamp + + (lambda () + ;; Every message has a trailing time stamp. + (should (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp)) + + ;; Stamps appear in the right margin. + (should (equal (car (get-text-property (1- (pos-eol)) 'display)) + '(margin right-margin))) + + ;; Stamps have a combined `invisible' property value. + (should (equal (get-text-property (1- (pos-eol)) 'invisible) + '(timestamp erc-match))) + + ;; The message proper has the `invisible' property `erc-match', + ;; which starts at the preceding newline... + (should (eq (get-text-property (1- (pos-bol)) 'invisible) 'erc-match)) + + ;; ... 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))) + + ;; The newline before `erc-insert-marker' is still visible. + (should-not (get-text-property (pos-eol) 'invisible)) + (should (= (next-single-property-change msgend 'invisible) + (pos-eol))))) + + (lambda () + ;; This message has a time stamp like all the others. + (should (eq (field-at-pos (1- (pos-eol))) 'erc-timestamp)) + + ;; Unlike hidden messages, the preceding newline is visible. + (should-not (get-text-property (1- (pos-bol)) 'invisible)) + + ;; The entire message proper is visible. + (let ((inv-beg (next-single-property-change (1- (pos-bol)) 'invisible))) + (should (eq (get-text-property inv-beg 'invisible) 'timestamp))))))) + (eval-when-compile (require 'erc-join)) ;;; erc-scenarios-match.el ends here -- 2.41.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 28 Jun 2023 21:02:16 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jun 28 17:02:16 2023 Received: from localhost ([127.0.0.1]:51783 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qEcIp-00027W-V4 for submit <at> debbugs.gnu.org; Wed, 28 Jun 2023 17:02:16 -0400 Received: from mail-108-mta211.mxroute.com ([136.175.108.211]:33141) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qEcIn-00027E-6w for 60936 <at> debbugs.gnu.org; Wed, 28 Jun 2023 17:02:14 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta211.mxroute.com (ZoneMTA) with ESMTPSA id 18903d04d5c000ca8f.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 28 Jun 2023 21:02:10 +0000 X-Zone-Loop: 82e8205038c4e514f28f5717b1e17d9b70b2a9f69f1b 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:To:From:Sender:Reply-To:Cc: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=irI/4V0bVLtKjtNfTK/JR0EkjASI/g16IRVTR9BSE2Q=; b=fM456kZIlkSs89blUfhoZxTS0z YCkBxZKorxfcjTmzAx/g1z0oPbelKtDT4Ejj5kUL0/P94raz5Kju/ox/EomFx8c3YmSrQorT5G0L/ B7XOOFww88+i+WEWAIyA5NF6FSobljZoLoZdg0x3TdKtLckPHnozle/jb6kF3WajBcVfLdk9uRGpk 5VCBOpAfpasNFpe6FTfe0Eblw+OOHujCS/4fBoRi9Lyj9bg9DgDpcbxqqowmGc0e1gDqIZhjiJ+qP gJR3xsJ3s2hn0RD5E/YBT2NhzxCfEjpEIbnFGKdqSm6AiEBmg+LXHFufa9jVSLfS482ST43wbtQaR U9cLfZgg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Wed, 28 Jun 2023 14:02:06 -0700 Message-ID: <878rc3xpv5.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 60936 X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) Another one denied by the archive trap (mere minutes this time): https://lists.gnu.org/archive/html/emacs-erc/2023-06/msg00021.html
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available."J.P." <jp@HIDDEN>
to control <at> debbugs.gnu.org
.
Full text available.Debbugs Internal Request <help-debbugs@HIDDEN>
to internal_control <at> debbugs.gnu.org
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 30 May 2023 14:15:10 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue May 30 10:15:10 2023 Received: from localhost ([127.0.0.1]:33727 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1q407x-0008UK-KP for submit <at> debbugs.gnu.org; Tue, 30 May 2023 10:15:10 -0400 Received: from mail-108-mta86.mxroute.com ([136.175.108.86]:42331) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1q407s-0008TP-12 for 60936 <at> debbugs.gnu.org; Tue, 30 May 2023 10:15:07 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta86.mxroute.com (ZoneMTA) with ESMTPSA id 1886d02fed600074ee.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Tue, 30 May 2023 14:14:52 +0000 X-Zone-Loop: 5fa44a7fcd2c2af48ef7c4123174566b0f4e9d4aa52e 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=XT9uRQ7+Ui4CWVGUIJpU65ydC6qxHeU8Eh4M3/eXgrQ=; b=amXm54BO677XJJmIhtpGVDO4oy s6gWmqzXBHxZ0FpnCMUtP88qE93F4RFXhdhm6RLAskvo0dgVdmr8PItVHI5Qp4Cv0PJUwnURdHAwm JaOmaCnNMfX1LdMJDcGUYj0X+mYM4x+Q/gK/UFlJ1XbofyydZwMHocfbTQdawLAN2uZ7oGbjFpIkE VKKJ/VzCMF4vhP/7+/oPkCWZoKUujsocnLjKOM04ds+cVV/UaGiqofakCHAkG4jktpnpxmbX31MkY QUwz2mL9Z+UgtsZc2ye1M2ytJ++N0LD1yYqn2Z+R/N5RC0ThU3wcfAqc6LsCVzkX+SoB/018p6SJP zIJLvTMg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87fs7p3sk6.fsf@HIDDEN> (J. P.'s message of "Sun, 21 May 2023 21:20:57 -0700") References: <87tu0nao77.fsf@HIDDEN> <87fs7p3sk6.fsf@HIDDEN> Date: Tue, 30 May 2023 07:14:50 -0700 Message-ID: <87pm6h7vol.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > The following commit introduced a regression: > > commit 05f6fdb9e7893329baff675bd31fb36ad64c756d > Author: F. Jason Park <jp@HIDDEN> > > [...] > > The attached patch fixes the regression and changes the behavior to > redraw the prompt on every incoming message as well, but only when > `erc-prompt' is a function. I've added this as commit 4f93c52f7fd1b7c5f75a0d049e5a1015a268265a Recompute erc-prompt when inserting messages lisp/erc/erc.el | 16 ++++++++++-- test/lisp/erc/erc-tests.el | 99 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 2 deletions(-) along with commit 31a80f61ec03bcbb79720c0dc640272aba160865 (origin/master) Preserve prompt in erc-cmd-CLEAR etc/ERC-NEWS | 11 ++++ lisp/erc/erc-log.el | 17 ++++-- lisp/erc/erc-stamp.el | 16 +++++ lisp/erc/erc-truncate.el | 21 +++---- lisp/erc/erc.el | 9 ++- test/lisp/erc/erc-scenarios-log.el | 207 ++++++++++++++++++++++++++++++ 6 files changed, 264 insertions(+), 17 deletions(-) which fixes a bug affecting the /CLEAR command. It was introduced by 05f6fdb9e78 "Preserve ERC prompt and its bounding markers" and pointed out by incal on IRC. Some background: For almost two decades, `erc-cmd-CLEAR' was simply defined as (recenter 0) However, in 2019, it was changed to destructively truncate the current buffer, something traditionally (though perhaps inadequately) provided by the command `erc-save-buffer-in-logs' in concert with the option `erc-truncate-buffer-on-save'. It happens that 05f6fdb9e78 "Preserve" also introduced a regression affecting the latter option, which has always suffered from an awkward implementation and insufficient documentation (and, consequently, poor discoverability). In addition to restoring its functionality, I've also deprecated it because of the inherent confusion surrounding its usage and, to a lesser degree, because it's redundant (/CLEAR now does the exact same thing). If anyone thinks this rash or unwarranted, please say so. Thanks.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 22 May 2023 04:21:14 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon May 22 00:21:14 2023 Received: from localhost ([127.0.0.1]:33156 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1q0x2n-0001bE-Jq for submit <at> debbugs.gnu.org; Mon, 22 May 2023 00:21:14 -0400 Received: from mail-108-mta233.mxroute.com ([136.175.108.233]:38393) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1q0x2l-0001az-2l for 60936 <at> debbugs.gnu.org; Mon, 22 May 2023 00:21:12 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta233.mxroute.com (ZoneMTA) with ESMTPSA id 18841b07b1700074ee.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Mon, 22 May 2023 04:21:04 +0000 X-Zone-Loop: 61b6e08a59b3bcbb263a8a2a66c668e4ab31d0a0950f 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=J2XNE/f5ZyAJrEvzug4AiF7mE1//Fn9rKBxf6GE8+cw=; b=GRMaAQrjaOarcBoTZnBF0bBLyb mLQrHMfnxkHCXbJb0y3UG46EUBRg1SwfQZxUXIhUHxezgyk+WFJxDsgoLZhD1+yduepDmvIOXg3Va Y8pp/oF8A0/hG4pg4G2m3408sp0K8u5/ZNOVKaqRJ1OTXXxDj5Ymvo3PNc63EHt+8E4KVD+LL0u8y 6B1CD/QqEsUa6MX4MfjpVFNXhvzXEPQepjh+lY5mxlaCWhltTZjXPlU7CExJWw4MTSsEppyC0J9nc eEpQBW4cZik6oVuJ/gxAz6mbt+GC6D38vGX83gVuOZ+HHC4ox40wymxU52l3dSiNwkV8xFFtt0vYa N8EXrKIw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Sun, 21 May 2023 21:20:57 -0700 Message-ID: <87fs7p3sk6.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain The following commit introduced a regression: commit 05f6fdb9e7893329baff675bd31fb36ad64c756d Author: F. Jason Park <jp@HIDDEN> Preserve ERC prompt and its bounding markers 1 file changed, 27 insertions(+), 22 deletions(-) lisp/erc/erc.el | 49 +++++++++++++++++++++++++++---------------------- To reproduce from emacs -Q: 1. Eval: (require 'erc) (setq erc-prompt (lambda () (format-time-string "%T>")) erc-autojoin-channels-alist '((ErgoTestnet "#test"))) (erc-tls :server "testnet.ergo.chat") 2. In #test, note the timestamp in the prompt 3. Say "something" RET 4. Notice that the prompt doesn't change, whereas in ERC 5.5 and earlier, it would change on every outgoing message The attached patch fixes the regression and changes the behavior to redraw the prompt on every incoming message as well, but only when `erc-prompt' is a function. Doing this should bring us one step closer to being able to look at bug#51082 erc-prompt: support substitution patterns "%target" and "%network" However, we'd still be missing user-mode tracking, which seems fairly trivial to add. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Recompute-erc-prompt-when-inserting-messages.patch From 292f741020f6dc39103803d6ca0cb8b7fb9e2b61 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 18 May 2023 23:47:27 -0700 Subject: [PATCH] [5.6] Recompute erc-prompt when inserting messages * lisp/erc/erc.el (erc--refresh-prompt): New function for redrawing the prompt in a couple select places. (erc-display-line-1, erc-display-msg): Replace the prompt after inserting messages. * test/lisp/erc/erc-tests.el (erc--refresh-prompt): New test. (Bug#60936) --- lisp/erc/erc.el | 16 +++++- test/lisp/erc/erc-tests.el | 99 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 495e25212ce..16bb2c38b1b 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2787,6 +2787,18 @@ erc--assert-input-bounds (cl-assert (< erc-insert-marker erc-input-marker)) (cl-assert (= (field-end erc-insert-marker) erc-input-marker))))) +(defun erc--refresh-prompt () + "Re-render ERC's prompt when the option `erc-prompt' is a function." + (erc--assert-input-bounds) + (when (functionp erc-prompt) + (save-excursion + (goto-char erc-insert-marker) + ;; Avoid `erc-prompt' (the named function), which appends a + ;; space, and `erc-display-prompt', which propertizes all but + ;; that space. + (insert-and-inherit (funcall erc-prompt)) + (delete-region (point) (1- erc-input-marker))))) + (defun erc-display-line-1 (string buffer) "Display STRING in `erc-mode' BUFFER. Auxiliary function used in `erc-display-line'. The line gets filtered to @@ -2830,7 +2842,7 @@ erc-display-line-1 (when erc-remove-parsed-property (remove-text-properties (point-min) (point-max) '(erc-parsed nil)))) - (erc--assert-input-bounds))))) + (erc--refresh-prompt))))) (run-hooks 'erc-insert-done-hook) (erc-update-undo-list (- (or (marker-position erc-insert-marker) (point-max)) @@ -6452,7 +6464,7 @@ erc-display-msg (narrow-to-region insert-position (point)) (run-hooks 'erc-send-modify-hook) (run-hooks 'erc-send-post-hook)) - (erc--assert-input-bounds))))) + (erc--refresh-prompt))))) (defun erc-command-symbol (command) "Return the ERC command symbol for COMMAND if it exists and is bound." diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index b624186d88d..1c75f35e1b5 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -269,6 +269,105 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--refresh-prompt () + (let* ((counter 0) + (erc-prompt (lambda () + (format "%s %d>" + (erc-format-target-and/or-network) + (cl-incf counter)))) + erc-accidental-paste-threshold-seconds + erc-insert-modify-hook + erc--input-review-functions + erc-send-completed-hook) + + (ert-info ("Server buffer") + (with-current-buffer (get-buffer-create "ServNet") + (erc-tests--send-prep) + (goto-char erc-insert-marker) + (should (looking-at-p "ServNet 3>")) + (erc-tests--set-fake-server-process "sleep" "1") + (set-process-sentinel erc-server-process #'ignore) + (setq erc-network 'ServNet + erc-server-current-nick "tester" + erc-networks--id (erc-networks--id-create nil) + erc-server-users (make-hash-table :test 'equal)) + (set-process-query-on-exit-flag erc-server-process nil) + ;; Incoming message redraws prompt + (erc-display-message nil 'notice nil "Welcome") + (should (looking-at-p "ServNet 4>")) + ;; Say something + (save-excursion (goto-char erc-input-marker) + (insert "Howdy") + (erc-send-current-line) + (forward-line -1) + (should (looking-at "No target")) + (forward-line -1) + (should (looking-at "<tester> Howdy"))) + (should (looking-at-p "ServNet 6>")) + ;; Space after prompt is unpropertized + (should (get-text-property (1- erc-input-marker) 'erc-prompt)) + (should-not (get-text-property erc-input-marker 'erc-prompt)) + ;; No sign of old prompts + (save-excursion + (goto-char (point-min)) + (should-not (search-forward (rx (any "3-5") ">") nil t))))) + + (ert-info ("Channel buffer") + (with-current-buffer (get-buffer-create "#chan") + (erc-tests--send-prep) + (goto-char erc-insert-marker) + (should (looking-at-p "#chan 9>")) + (setq erc-server-process (buffer-local-value 'erc-server-process + (get-buffer "ServNet")) + erc-networks--id (erc-with-server-buffer erc-networks--id) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan") + erc-channel-users (make-hash-table :test 'equal)) + (erc-update-current-channel-member "alice" "alice") + (erc-update-current-channel-member "bob" "bob") + (erc-update-current-channel-member "tester" "tester") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" "Hi" nil t)) + (should (looking-at-p "#chan@ServNet 10>")) + (save-excursion (goto-char erc-input-marker) + (insert "Howdy") + (erc-send-current-line) + (forward-line -1) + (should (looking-at "<tester> Howdy"))) + (should (looking-at-p "#chan@ServNet 11>")) + (save-excursion (goto-char erc-input-marker) + (insert "/query bob") + (erc-send-current-line)) + ;; Query does not redraw (nor /help, only message input) + (should (looking-at-p "#chan@ServNet 11>")) + ;; No sign of old prompts + (save-excursion + (goto-char (point-min)) + (should-not (search-forward (rx (or "9" "10") ">") nil t))))) + + (ert-info ("Query buffer") + (with-current-buffer (get-buffer "bob") + (goto-char erc-insert-marker) + (should (looking-at-p "bob@ServNet 14>")) + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" "Hi" nil t)) + (should (looking-at-p "bob@ServNet 15>")) + (save-excursion (goto-char erc-input-marker) + (insert "Howdy") + (erc-send-current-line) + (forward-line -1) + (should (looking-at "<tester> Howdy"))) + (should (looking-at-p "bob@ServNet 16>")) + ;; No sign of old prompts + (save-excursion + (goto-char (point-min)) + (should-not (search-forward (rx (or "14" "15") ">") nil t))))) + + (when noninteractive + (kill-buffer "#chan") + (kill-buffer "bob") + (kill-buffer "ServNet")))) + (ert-deftest erc--initialize-markers () (let ((proc (start-process "true" (current-buffer) "true")) erc-modules -- 2.40.0 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 9 May 2023 20:46:44 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue May 09 16:46:44 2023 Received: from localhost ([127.0.0.1]:44600 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pwUEO-0007G5-AL for submit <at> debbugs.gnu.org; Tue, 09 May 2023 16:46:44 -0400 Received: from mail-108-mta38.mxroute.com ([136.175.108.38]:42489) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pwUEM-0007Fq-LU for 60936 <at> debbugs.gnu.org; Tue, 09 May 2023 16:46:43 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta38.mxroute.com (ZoneMTA) with ESMTPSA id 18802441067000becb.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Tue, 09 May 2023 20:46:35 +0000 X-Zone-Loop: 8a45dc46dd670c4a134dba0cc49c20d41a80928d615c 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:To:From:Sender:Reply-To:Cc: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=wvKktbs2pQnfyobKw7nA4sawSHaItUZPGm4wZOuYWr4=; b=QODihJM03SGbHRdrJPb9Ap0MPB MM3iWhyMEO3CuREG8+gKI5guQKAr4gKJ2fFVYArBOAveHBxLRTo3905c3NGJfqvHwvGaFGDxFVeLs 2mTN7Q2P3VwSC/v72HqILz4LLX2QbQVEbwcctMDV5NVZw0mwLAueA8ImM0y7/4cZbZKAS60DNcTOL XTCAehjm5o5oMglD5//nQMDlo/hSnkswz5ZqUI/UISUHMpSPQWg4J49ov0dC7FpZe6Fl8adzpaQIb JoWtVdK5KbE0Pufxh2bWRzlprAJT0A32E/5jKOl3AE8Ch50f6mMyS3dvNKgzgCe6g+X80eBsQd/4Y 2yQgn52w==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Tue, 09 May 2023 13:46:32 -0700 Message-ID: <87mt2ds05z.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) Related followup (caught by the archive filter): https://lists.gnu.org/archive/html/emacs-erc/2023-05/msg00004.html
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available."J.P." <jp@HIDDEN>
to control <at> debbugs.gnu.org
.
Full text available.Debbugs Internal Request <help-debbugs@HIDDEN>
to internal_control <at> debbugs.gnu.org
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 10 Apr 2023 20:49:45 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon Apr 10 16:49:45 2023 Received: from localhost ([127.0.0.1]:36040 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1plySP-0004wD-6E for submit <at> debbugs.gnu.org; Mon, 10 Apr 2023 16:49:45 -0400 Received: from mail-108-mta17.mxroute.com ([136.175.108.17]:45585) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1plySN-0004w0-HZ for 60936 <at> debbugs.gnu.org; Mon, 10 Apr 2023 16:49:43 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta17.mxroute.com (ZoneMTA) with ESMTPSA id 1876cee66a8000edb4.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Mon, 10 Apr 2023 20:49:35 +0000 X-Zone-Loop: 56eb27dd136e223ab5d1d626be05307898969326019b 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=6OFTtTEOXRnHnHSbZ/9c1kI9AMAQRp6nXLdcsLCj9iQ=; b=CfZdRF41wT65XhvsXTz/9vv8BM 0NQYY1utzihjwS0lnHgJjvSvMpqjBfawbcxeqLaql2rgyNAAdFWW086emUlLm9AXDLeJmaUK2gYGf dc2QKW7N9j2Vg2QI4Vr8B1bE+zRf32fZJYIFjmbY0hor4j4lnOLDdOWqWRcxoxGj3bdhf3qiEBJGs rYckw1+EgpQ27XbynKliVvNPGQBaegwf2kPpzhwqfXAbtRwR3yjXzusTnf2GfoCOsIvkef6An5QbM ITm1RlIbnj3BwzS94w7JSOoheHy2gVAb6K6bAPXj6rDqSmMgdZ1RT/1KQj150e+wLgBc76mYw8FeN 1oH23o2A==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87edpykmud.fsf@HIDDEN> (J. P.'s message of "Thu, 09 Mar 2023 06:42:34 -0800") References: <87tu0nao77.fsf@HIDDEN> <87edpykmud.fsf@HIDDEN> Date: Mon, 10 Apr 2023 13:49:31 -0700 Message-ID: <87pm8btqck.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) "J.P." <jp@HIDDEN> writes: > v10. Redo some key bindings. Remove unneeded Compat functions. Rename > `erc-message' text prop to `erc-command'. Revive mistakenly deleted hunk > in erc-match. This module probably shouldn't be hiding fringes without good reason or calling `set-window-margins' on whatever window happens to be selected. The current behavior also carries the potential to pollute the test suite. I've gone ahead and installed a small fix that hopefully addresses these concerns. Thanks.
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available."J.P." <jp@HIDDEN>
to control <at> debbugs.gnu.org
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 9 Mar 2023 14:42:54 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Thu Mar 09 09:42:54 2023 Received: from localhost ([127.0.0.1]:51267 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1paHTq-0003V6-O3 for submit <at> debbugs.gnu.org; Thu, 09 Mar 2023 09:42:54 -0500 Received: from mail-108-mta30.mxroute.com ([136.175.108.30]:43071) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1paHTp-0003Ut-6d for 60936 <at> debbugs.gnu.org; Thu, 09 Mar 2023 09:42:53 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta30.mxroute.com (ZoneMTA) with ESMTPSA id 186c6d307fa000edb4.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Thu, 09 Mar 2023 14:42:44 +0000 X-Zone-Loop: cbdcebc7d2ddb6f0a6c9872868e86e6a9bc43c680daf 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=FZdmahDIBrFPrNv0iFQlWyC5n+UToOzDPYy+wXPwHiY=; b=VW7Fas6RW6eprQnzhwL4BwqHTi 0l3uAXqLssD6YiHqwCZZ6pVpUkM/thb1dA/3/U7eVLv/RxnwsIrRseLkQd/7SNgy6dPH5+NNLxsSs bVKqUcXE5SWndGFaTPKBZDh4x62UALyDZkjO03dmByGw9N333AEyJlwoW+plQgpfWosvpBLBfWDVS VVhzeuimSMoveo2XBKjobrcGA2sVH2Hpxn0zSLzy4h3TOzsZJyPwZMniqQtoLeKlbKd+GTsjCoiDb BRXqfAET6eRB0/TIZ3sOWyZNtWb+wfW/yZalgtPvPKHOyVLke+8/AUIGu5/k12nfzzm5gexDmnOQy EJFRdaJQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Thu, 09 Mar 2023 06:42:34 -0800 Message-ID: <87edpykmud.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v10. Redo some key bindings. Remove unneeded Compat functions. Rename `erc-message' text prop to `erc-command'. Revive mistakenly deleted hunk in erc-match. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v9-v10.diff From f87741ad52ffebe378200ffcd74ad75be680d9a2 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 9 Mar 2023 06:25:15 -0800 Subject: [PATCH 0/8] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (8): [5.6] Refactor marker initialization in erc-open [5.6] Adjust some old text properties in ERC buffers [5.6] Expose insertion time as text prop in erc-stamp [5.6] Make some erc-stamp functions more limber [5.6] Put display properties to better use in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add variant for erc-match invisibility spec [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-fill.el | 311 +++++++++++++++-- lisp/erc/erc-match.el | 31 +- lisp/erc/erc-stamp.el | 210 ++++++++++-- lisp/erc/erc.el | 127 ++++--- test/lisp/erc/erc-fill-tests.el | 324 ++++++++++++++++++ .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 ------ test/lisp/erc/erc-stamp-tests.el | 265 ++++++++++++++ test/lisp/erc/erc-tests.el | 79 ++++- .../fill/snapshots/monospace-01-start.eld | 1 + .../fill/snapshots/monospace-02-right.eld | 1 + .../fill/snapshots/monospace-03-left.eld | 1 + .../fill/snapshots/monospace-04-reset.eld | 1 + 13 files changed, 1445 insertions(+), 216 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el create mode 100644 test/lisp/erc/erc-stamp-tests.el create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld Interdiff: diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 7d635e5b1af..5601ede27a5 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,63 +409,6 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) -;; FIXME remove these after bumping Compat version to 29 -(defvar erc-compat--29-set-transient-map-timer nil) - -(defun erc-compat--29-set-transient-map - (map &optional keep-pred on-exit message timeout) - (let* ((message - (when message - (let (keys) - (map-keymap (lambda (key cmd) (and cmd (push key keys))) map) - (format-spec - (if (stringp message) message "Repeat with %k") - `((?k . ,(mapconcat - (lambda (key) - (substitute-command-keys - (format "\\`%s'" (key-description (vector key))))) - keys ", "))))))) - (clearfun (make-symbol "clear-transient-map")) - (exitfun (lambda () - (internal-pop-keymap map 'overriding-terminal-local-map) - (remove-hook 'pre-command-hook clearfun) - (when message (message "")) - (when erc-compat--29-set-transient-map-timer - (cancel-timer erc-compat--29-set-transient-map-timer)) - (when on-exit (funcall on-exit))))) - (fset clearfun - (lambda () - (with-demoted-errors "set-transient-map PCH: %S" - (if (cond - ((null keep-pred) nil) - ((and (not (eq map (cadr overriding-terminal-local-map))) - (memq map (cddr overriding-terminal-local-map))) - t) - ((eq t keep-pred) - (let ((mc (lookup-key map (this-command-keys-vector)))) - (when (and mc (symbolp mc)) - (setq mc (or (command-remapping mc) mc))) - (and mc (eq this-command mc)))) - (t (funcall keep-pred))) - (when message (message "%s" message)) - (funcall exitfun))))) - (add-hook 'pre-command-hook clearfun) - (internal-push-keymap map 'overriding-terminal-local-map) - (when timeout - (when erc-compat--29-set-transient-map-timer - (cancel-timer erc-compat--29-set-transient-map-timer)) - (setq erc-compat--29-set-transient-map-timer - (run-with-idle-timer timeout nil exitfun))) - (when message (message "%s" message)) - exitfun)) - -(defmacro erc-compat--set-transient-map (&rest args) - (cons (if (>= emacs-major-version 29) - 'set-transient-map - 'erc-compat--29-set-transient-map) - args)) - - (provide 'erc-compat) ;;; erc-compat.el ends here diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 032206b514a..16791277723 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -369,14 +369,12 @@ erc-fill-wrap-nudge Offer to repeat command in a manner similar to `text-scale-adjust'. - \\`+', \\`=' Increase indentation by one column - \\`-' Decrease indentation by one column - \\`0' Reset indentation to the default - \\`C-+', \\`C-=' Shift right margin rightward (shrink it) - by one column - \\`C--' Shift right margin leftward (grow it) by one - column - \\`C-0' Reset the right margin to the default + \\`=' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`+' Shift right margin rightward (shrink) by one column + \\`_' Shift right margin leftward (grow) by one column + \\`)' Reset the right margin to the default Note that misalignment may occur when messages contain decorations applied by third-party modules. See @@ -392,9 +390,10 @@ erc-fill-wrap-nudge (- (window-end nil t) (window-start))))) (when (zerop arg) (setq arg 1)) - (erc-compat--set-transient-map + (erc-compat-call + set-transient-map (let ((map (make-sparse-keymap))) - (dolist (key '(?+ ?= ?- ?0)) + (dolist (key '(?= ?- ?0)) (let ((a (pcase key (?0 0) (?- (- (abs arg))) @@ -403,8 +402,13 @@ erc-fill-wrap-nudge (lambda () (interactive) (cl-incf total (erc-fill--wrap-nudge a)) - (recenter (round (* win-ratio (window-height)))))) - (define-key map (vector (list 'control key)) + (recenter (round (* win-ratio (window-height)))))))) + (dolist (key '(?\) ?_ ?+)) + (let ((a (pcase key + (?\) 0) + (?_ (- (abs arg))) + (?+ (abs arg))))) + (define-key map (vector (list key)) (lambda () (interactive) (erc-stamp--adjust-right-margin (- a)) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index a5e9720bad4..c8f6e7c195c 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -650,6 +650,8 @@ erc-go-to-log-matches-buffer (get-buffer (car buffer-cons)))))) (switch-to-buffer buffer-name))) +(define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) + (defvar-local erc-match--hide-fools-offset-bounds nil) (defun erc-hide-fools (match-type _nickuserhost _message) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index f47cca3f109..3d63c927df3 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2873,7 +2873,7 @@ erc-display-message (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) (put-text-property - 0 (length string) 'erc-message + 0 (length string) 'erc-command (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index a254d5bbc73..2a0abf5dc32 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -182,7 +182,7 @@ erc-fill-wrap--monospace (ert-info ("Shift right by one (plus)") (ert-with-message-capture messages - (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET =")) (should (string-match (rx "for further adjustment") messages))) (should (= erc-fill--wrap-value 29)) (erc-fill-tests--wrap-check-prefixes) -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Refactor-marker-initialization-in-erc-open.patch From c84d3c5e6886722d975978cea93a893220be98c6 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Jan 2023 20:48:24 -0800 Subject: [PATCH 1/8] [5.6] Refactor marker initialization in erc-open * lisp/erc/erc.el (erc--initialize-markers): New helper to ensure prompt and its associated markers are set up correctly. (erc-open): When determining whether a session is a logical continuation, leverage the work already performed by the `erc-networks' library to that effect. Its verdicts are based on network context and thus reliable even when a user dials anew from an entry-point, which is not a simple reconnection because the user expects a clean slate for everything except an existing buffer's messages, meaning `erc--server-reconnecting' will be nil and local-module state variables need resetting. Also remove the check for `erc-reuse-buffers' and instead trust that `erc-get-buffer-create' always does the right thing in. Replace all code involving marker and prompt setup by deferring to a new helper, `erc--initialize markers'. * test/lisp/erc/erc-tests.el (erc--initialize-markers): New test. * test/lisp/erc/erc-scenarios-base-local-module-modes.el: New file. * test/lisp/erc/erc-scenarios-base-local-modules.el (erc-scenarios-base-local-modules--mode-persistence): Move test to separate file to help with parallel "-j" runs. (Bug#60936.) --- lisp/erc/erc.el | 70 +++--- .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 -------- test/lisp/erc/erc-tests.el | 79 ++++++- 4 files changed, 322 insertions(+), 137 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 69bdb5d71b1..5a85c5ad396 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1967,6 +1967,35 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Trust existing markers. + (set-marker erc-insert-marker + (alist-get 'erc-insert-marker continued-session)) + (set-marker erc-input-marker + (alist-get 'erc-input-marker continued-session)) + (goto-char erc-insert-marker) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -2000,10 +2029,13 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))) + (buffer-local-variables buffer))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2021,21 +2053,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2082,20 +2099,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 1318207a3bf..d6dbd87c8cc 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -82,105 +82,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index d6c63934163..f7e90ec9082 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From 11684dc5ac17b75d7be31b2d945e47da54283fa0 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 2/8] [5.6] Adjust some old text properties in ERC buffers * lisp/erc/erc.el (erc-display-message): Replace `rear-sticky' text property, which has been around since 2002, with more useful `erc-command' property, which contains the IRC command as a symbol or a number, in the case of numerics. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. (erc-put-text-property, erc-list): Alias these to built-in functions. (erc--own-property-names, erc--remove-text-properties) Add internal variable and helper function for filtering values returned by `filter-buffer-substring-function'. (erc-restore-text-properties): Don't forget tags when restoring. (erc--get-eq-comparable-cmd): New function to extract commands for use as easily searchable text-property values. (Bug#60936.) --- lisp/erc/erc.el | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 5a85c5ad396..3d63c927df3 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2872,7 +2872,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) + (put-text-property + 0 (length string) 'erc-command + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4250,6 +4252,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -4301,7 +4327,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) @@ -5673,7 +5699,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5683,14 +5709,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7284,10 +7305,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7307,6 +7329,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Expose-insertion-time-as-text-prop-in-erc-stamp.patch From c49fb6ff6c81105b2049980e6648251e3d603348 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 03:10:20 -0800 Subject: [PATCH 3/8] [5.6] Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property `erc-timestamp' to store lisp time object formerly ensconced in a closure. Instead of creating a new lambda for the cursor-sensor function of each message in a buffer, leave a gap between messages to trip the sensor function. The motivation behind this change is to allow third parties access to valuable timestamp data already stored by ERC anyway. Of secondary importance is discouraging the reliance on those lambdas as a means of detecting message bounds. The gap now serves a similar purpose. Basically, the final character in a message, a newline, will not have a timestamp or a sensor function. When the stamps module isn't loaded, the `erc-message' property can be used instead. Also, instead of looking for the `invisible' text property at point, which is normally `point-max' and thus outside the accessible portion of the buffer, look at the beginning of the inserted message. This allows hook members running before this function to opt out of timestamps by marking a message as invisible. (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-stamp.el | 15 ++- test/lisp/erc/erc-stamp-tests.el | 207 +++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..051d0702f06 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -162,7 +162,7 @@ erc-add-timestamp This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) + (unless (get-text-property (point-min) 'invisible) (let ((ct (current-time))) (if (fboundp erc-insert-timestamp-function) (funcall erc-insert-timestamp-function @@ -174,12 +174,12 @@ erc-add-timestamp (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -400,11 +400,16 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + ;; Could also pass an &optional `zone' arg to `format-time-string'. + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..935b9e650b3 --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,207 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\s (char-after (field-beginning (point))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;; This concerns a proposed partial reversal of the changes resulting +;; from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also a lasting commitment. The docs mention that it's +;; pointless to pair the old `intangible' property with `invisible' +;; and suggest users look at `cursor-intangible-mode'. Turning off +;; the latter does indeed do the trick as does decrementing the end of +;; the `cursor-intangible' interval so that, in addition to C-n +;; working, a C-f from before the timestamp doesn't overshoot. This +;; appears to be the case whether `erc-hide-timestamps' is enabled or +;; not, but it may be inadvisable for some reason (a hack) and +;; therefore warrants further investigation. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + +;;; erc-stamp-tests.el ends here -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Make-some-erc-stamp-functions-more-limber.patch From dd8c274ac4e526247df7df6ec9b9b223c6fa9d6d Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 4/8] [5.6] Make some erc-stamp functions more limber TODO: update ERC-NEWS announcing deprecation. * lisp/erc/erc-stamp.el (erc-timestamp-format-right): Deprecate option and change meaning of its nil value to fall through to `erc-timestamp-format'. Do this to allow modules to predict what the right-hand stamp's final width will be. This also saves `erc-insert-timestamp-left-and-right' from calling `erc-format-timestamp' again for no reason. (erc-stamp--current-time): Add new generic function and method to return current time. Default to calling `current-time'. (erc-stamp--current-time): New internal variable to hold time value used to construct time formatted stamp passed to `erc-insert-timestamp-function'. (erc-add-timestamp): Bind `erc-stamp--current-time' when calling `erc-insert-timestamp-function'. (erc-insert-timestamp-left-and-right): Use STRING parameter and favor it over the now deprecated `erc-timestamp-format-right' to avoid formatting twice. Also extract current time from the variable `erc-stamp--current-time' for similar reasons. (Bug#60936.) (erc-stamp--tz): New internal variable. (erc-format-timestamp): Pass `erc-stamp--tz' as time-zone to `format-time-string'. --- lisp/erc/erc-stamp.el | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 051d0702f06..736aa498803 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,17 +165,31 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." (unless (get-text-property (point-min) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) @@ -336,12 +358,13 @@ erc-insert-timestamp-left-and-right (setq erc-timestamp-last-inserted-right ts-right)))) ;; for testing: (setq erc-timestamp-only-if-changed-flag nil) +(defvar erc-stamp--tz nil) (defun erc-format-timestamp (time format) "Return TIME formatted as string according to FORMAT. Return the empty string if FORMAT is nil." (if format - (let ((ts (format-time-string format time))) + (let ((ts (format-time-string format time erc-stamp--tz))) (erc-put-text-property 0 (length ts) 'font-lock-face 'erc-timestamp-face ts) (erc-put-text-property 0 (length ts) 'invisible 'timestamp ts) -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Put-display-properties-to-better-use-in-erc-stam.patch From e34189bd4f488cb36aac71f8748761d7054db652 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 5/8] [5.6] Put display properties to better use in erc-stamp * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-stamp-right-margin-width): New option to determine width of right margin when `erc-stamp--display-margin-mode' is active or `erc-timestamp-use-align-to' is set to `margin'. (erc-stamp--display-margin-force): Add new helper function for `erc-stamp--display-margin-mode'. (erc-stamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--nil, erc-timestamp-use-align-to--t): Adjust spacing for new default right-hand stamp, `erc-format-timestamp', which lacks a leading space. (erc-timestamp-use-align-to--integer, erc-timestamp-use-align-to--margin): New tests. (Bug#60936.) --- lisp/erc/erc-stamp.el | 156 +++++++++++++++++++++++++++---- test/lisp/erc/erc-stamp-tests.el | 70 ++++++++++++-- 2 files changed, 202 insertions(+), 24 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 736aa498803..e689caf7b61 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -239,14 +239,109 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. -A side effect of enabling this is that there will only be one -space before a right timestamp in any saved logs." - :type 'boolean) +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + +Enabling this option produces a side effect in that stamps aren't +indented in saved logs. When its value is an integer, this +option adds a space after the end of a message if the stamp +doesn't already start with one. And when its value is t, it adds +a single space, unconditionally. And while this option never +adds a space when its value is `margin', ERC does offer a +workaround in `erc-stamp-prefix-log-filter', which strips +trailing stamps from messages and puts them before every line." + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.6")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +(defun erc-stamp--adjust-right-margin (cols) + "Adjust right margin by COLS. +When COLS is zero, reset width to `erc-stamp-right-margin-width' +or one col more than the `string-width' of +`erc-timestamp-format'." + (let ((width + (if (zerop cols) + (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))) + (+ right-margin-width cols)))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + +(defun erc-stamp-prefix-log-filter (text) + "Prefix every message in the buffer with a stamp. +Remove trailing stamps as well. For now, hard code the format to +\"ZNC\"-log style, which is [HH:MM:SS]. Expect to be used as a +`erc-log-filter-function' when `erc-timestamp-use-align-to' is +non-nil." + (insert text) + (goto-char (point-min)) + (while + (progn + (when-let* (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) + (delete-region beg (1+ end))) + (when-let (time (get-text-property (point) 'erc-timestamp)) + (insert (format-time-string "[%H:%M:%S] " time))) + (zerop (forward-line)))) + "") + +(declare-function erc--remove-text-properties "erc" (string)) + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." + :interactive nil + (if erc-stamp--display-margin-mode + (progn + (erc-stamp--adjust-right-margin 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) + (kill-local-variable 'right-margin-width) + (kill-local-variable 'right-fringe-width) + (set-window-margins nil left-margin-width nil) + (set-window-fringes nil left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -265,6 +360,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -275,6 +371,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -326,25 +424,47 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 935b9e650b3..01e71e348e0 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,67 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-stamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one[" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo[" nil t)) + ;; Field starts at format string (right bracket) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns a proposed partial reversal of the changes resulting -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From aa4edc2f4b711ccc898073c65d76941188183cc8 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 6/8] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. (Bug#60936.) --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-variant-for-erc-match-invisibility-spec.patch From 93c5911b8c61e919bd90213dc04b6722c9505113 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 05:34:56 -0800 Subject: [PATCH 7/8] [5.6] Add variant for erc-match invisibility spec * lisp/erc/erc-match.el (erc-match-enable, erc-match-disable): Arrange for possibly adding or removing `erc-match' from `buffer-invisibility-spec'. (erc-match--hide-fools-offset-bounds): Add new variable to serve as switch for activating invisibility on a modified interval that's offset toward `point-min' by one character. (erc-hide-fools): Optionally offset start and end of invisible region by minus one. (erc-match--modify-invisibility-spec): New housekeeping function to set up and tear down offset spec. (Bug#60936.) --- lisp/erc/erc-match.el | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 52ee5c855f3..c8f6e7c195c 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -649,13 +652,22 @@ erc-go-to-log-matches-buffer (define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) + (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +675,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch Content-Transfer-Encoding: quoted-printable From f87741ad52ffebe378200ffcd74ad75be680d9a2 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 8/8] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill--wrap-value, erc-fill--wrap-movement): New variables to support new local module. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap-mode, erc-fill-wrap-enable, erc-fill-wrap-disable): New local module. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-fill.el | 277 ++++++++++++++- test/lisp/erc/erc-fill-tests.el | 324 ++++++++++++++++++ .../fill/snapshots/monospace-01-start.eld | 1 + .../fill/snapshots/monospace-02-right.eld | 1 + .../fill/snapshots/monospace-03-left.eld | 1 + .../fill/snapshots/monospace-04-reset.eld | 1 + 6 files changed, 600 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-01-sta= rt.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-02-rig= ht.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-03-lef= t.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-04-res= et.eld diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..16791277723 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. =20 +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: =20 (require 'erc) @@ -79,16 +82,29 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) =20 (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) =20 (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +171,257 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) =20 +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-visual-keys nil) + +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall (pcase erc-fill--wrap-visual-keys + ('non-input + (if (>=3D (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "Defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c a" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + +;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + ;; FIXME use `erc-button--display-error-notice-with-keys' + ;; when bug#60933 is ready. + (concat "Enabling default global module `fill' needed by lo= cal" + " module `fill-wrap'. This will impact \C-]all\C-]= ERC" + " sessions. Add `fill' to `erc-modules' to avoid t= his" + " warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-= keys + vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center)) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-visual-keys) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the Info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill-wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- erc-fill--wrap-value ,le= n)) + (space :width erc-fill--wrap-value)))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. Another use +;; case would be to fix lines affected by toggling a display-oriented +;; mode, like `display-line-numbers-mode'. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +That is, recalculate the width of all accessible lines and reset +local prefix VALUE when non-nil." + (save-excursion + (when value + (setq erc-fill--wrap-value value)) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (line-beginning-position) (line-end-position)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf erc-fill--wrap-value arg) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. + + \\`=3D' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`+' Shift right margin rightward (shrink) by one column + \\`_' Shift right margin leftward (grow) by one column + \\`)' Reset the right margin to the default + +Note that misalignment may occur when messages contain +decorations applied by third-party modules. See +`erc-fill--wrap-fix' for a temporary workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (unless (get-buffer-window) + (user-error "Command called in an undisplayed buffer")) + (let* ((total (erc-fill--wrap-nudge arg)) + (win-ratio (/ (float (- (window-point) (window-start))) + (- (window-end nil t) (window-start))))) + (when (zerop arg) + (setq arg 1)) + (erc-compat-call + set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?=3D ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (recenter (round (* win-ratio (window-height)))))= ))) + (dolist (key '(?\) ?_ ?+)) + (let ((a (pcase key + (?\) 0) + (?_ (- (abs arg))) + (?+ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (erc-stamp--adjust-right-margin (- a)) + (recenter (round (* win-ratio (window-height)))))= ))) + map) + t + (lambda () + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (recenter (round (* win-ratio (window-height)))))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center= '." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el new file mode 100644 index 00000000000..2a0abf5dc32 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,324 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;; FIXME these fixtures (and tests) are now largely useless. Due to +;; the author's ignorance regarding display properties, the "space" +;; specs of prefix props on different lines didn't initially leverage +;; a common variable (`erc-fill--wrap-value'), so the column twiddling +;; was more laborious. See decades-old comment above +;; calc_pixel_width_or_height in in xdisp.c for examples. +;; +;; TODO maybe use erts files instead of own snapshots. + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defvar erc-fill-tests--buffers nil) + +(defun erc-fill-tests--wrap-populate (test) + (cl-letf (((symbol-function 'erc-stamp--current-time) + (lambda () '(0 1)))) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (erc-stamp--tz t) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) + (erc-modules '(fill stamp)) + (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil= t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + + (setq msg "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.") + (erc-display-message nil 'notice (current-buffer) msg) + + (setq msg "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.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) + + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (while-let ((buf (pop erc-fill-tests--buffers))) + (kill-buffer buf)) + (kill-buffer)))))))) + +(defun erc-fill-tests--wrap-check-props (speaker) + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward speaker nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- erc-fill--wrap-value (,w)))) + (=3D w (string-pixel-width speaker))) + (`(space :width (- erc-fill--wrap-value ,w)) + (=3D w (length speaker)))))) + +(defun erc-fill-tests--wrap-check-prefixes () + (save-excursion + (goto-char (point-min)) + (erc-fill-tests--wrap-check-props "*** ") + (erc-fill-tests--wrap-check-props "<alice> ") + ;; Ensure the loop is not visited twice due to the gap. + (erc-fill-tests--wrap-check-props "<bob> "))) + +;; Set this variable to t to generate new snapshots after carefully +;; reviewing the output of each. +(defvar erc-fill-tests--save-p nil) + +(defun erc-fill-tests--compare (name) + (let* ((dir (expand-file-name "fill/snapshots/" (ert-resource-directory)= )) + (expect-file (file-name-with-extension (expand-file-name name dir) + "eld")) + (erc--own-property-names + (seq-difference `(erc-timestamp font-lock-face + ,@erc--own-property-names) + '(display wrap-prefix line-prefix) + #'eq)) + (print-circle t) + (print-escape-newlines t) + (print-escape-nonascii t) + (got (erc--remove-text-properties + (buffer-substring (point-min) erc-insert-marker))) + (repr (string-replace "erc-fill--wrap-value" + (number-to-string erc-fill--wrap-value) + (prin1-to-string got)))) + (with-current-buffer (generate-new-buffer name) + (push name erc-fill-tests--buffers) + (with-silent-modifications + (insert (setq got (read repr)))) + (erc-mode)) + (if erc-fill-tests--save-p + (with-temp-file expect-file + (insert repr)) + (with-temp-buffer + (insert-file-contents-literally expect-file) + (should (equal got (read (current-buffer)))))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-01-start") + + (ert-info ("Shift right by one (plus)") + (ert-with-message-capture messages + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET =3D")) + (should (string-match (rx "for further adjustment") messages))) + (should (=3D erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-02-right")) + + (ert-info ("Shift left by five") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) + (should (=3D erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-03-left")) + + (ert-info ("Reset") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-04-reset"))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + (lambda () + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 2) + (should (=3D erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge -6) + (should (=3D erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 0) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + + ;; FIXME get rid of this "void variable `erc--results-ewoc'" + ;; error, which seems related to operating in a non-default + ;; frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +(ert-deftest erc-fill-wrap-visual-keys--body () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (execute-kbd-macro "\C-e") + (should (search-backward "tedious fool" nil t)) + (should-not (looking-back "done to her\\.")) + (forward-char) + (execute-kbd-macro "\C-e") + (should (search-forward "done to her." nil t))) + + (ert-info ("Value: nil") + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (goto-char (point-min)) + (should (search-forward "in debug mode" nil t)) + (execute-kbd-macro "\C-a") + (should (looking-at (rx "*** "))) + (execute-kbd-macro "\C-e") + (should (eql ?\] (char-before (point))))) + + (ert-info ("Value: t") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (should (search-backward "tedious fool" nil t)) + (execute-kbd-macro "\C-e") + (should-not (looking-back (rx "done to her\\."))) + (should (search-forward "done to her." nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))))))) + +(ert-deftest erc-fill-wrap-visual-keys--prompt () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (goto-char erc-input-marker) + (insert "This buffer is for text that is not saved, and for Lisp " + "evaluation. To create a file, visit it with C-x C-f and " + "enter text in its buffer.") + + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-e") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: nil") ; same + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (execute-kbd-macro "\C-y") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: non-input") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (execute-kbd-macro "\C-y") + (execute-kbd-macro "\C-a") + (should-not (looking-at "This buffer")) + (execute-kbd-macro "\C-p") + (should-not (looking-back "its buffer\\.")) + (should (search-forward "its buffer." nil t)) + (should (search-backward "ERC> " nil t)) + (execute-kbd-macro "\C-a"))))) + +;;; erc-fill-tests.el ends here diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld new file mode 100644 index 00000000000..3f5f344cc64 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 29) line-prefix #3=3D(space :width (-= 29 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 29 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 29 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld new file mode 100644 index 00000000000..3b215936c39 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 25) line-prefix #3=3D(space :width (-= 25 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 25 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 25 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file --=20 2.39.2 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 20 Feb 2023 15:31:26 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Mon Feb 20 10:31:26 2023 Received: from localhost ([127.0.0.1]:53272 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pU88U-0000VE-KJ for submit <at> debbugs.gnu.org; Mon, 20 Feb 2023 10:31:26 -0500 Received: from mail-108-mta54.mxroute.com ([136.175.108.54]:43893) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pU88S-0000Uv-CN for 60936 <at> debbugs.gnu.org; Mon, 20 Feb 2023 10:31:24 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta54.mxroute.com (ZoneMTA) with ESMTPSA id 1866f73596f000edb4.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Mon, 20 Feb 2023 15:31:15 +0000 X-Zone-Loop: b3f4b28a13a6d2c0068c148067353953521d76507bb3 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=udjvRtBLk8abNCDOf34t/3/XfOwrKKWn1na1uO9YSYo=; b=OWj0z9A+OCGtNUIfsdFNg6QcsU AgEpe+lNm3Xyqdu/JWVTe5BD55NWMB3UOy0nyubPgFDzbw27FXpK9RUebxYKkXpxc/jr/NrJu4obF j3rkNE+np+3kx5KBGDGbO5/C8NT+yXnyMPbr01RiTlSqxTNAxOWT9+cIm/2ElkpINzQ+SvS0eXCx5 +xqFZOgs9VHrFzHVp3wtH4/iP86zfq8MRB4fFDt6FL0k5wblc2PqYooo6Eal9UvZsYvyI63H9eO5R /fyhoIFQJvq2Q+2TdvdjgP9Nix2uXf686MBzsF3nG8lv1L5OjH/Twgo5iFf77xWzUC+Ew7jx4BhEx 58OJME4A==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Mon, 20 Feb 2023 07:31:12 -0800 Message-ID: <87lekstku7.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v9. Trust previous values when initializing markers. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v8-v9.diff From f2613f703f3e4fa49a0efb3e120b493bb0731c53 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 20 Feb 2023 00:05:34 -0800 Subject: [PATCH 0/8] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (8): [5.6] Refactor marker initialization in erc-open [5.6] Adjust some old text properties in ERC buffers [5.6] Expose insertion time as text prop in erc-stamp [5.6] Make some erc-stamp functions more limber [5.6] Put display properties to better use in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add variant for erc-match invisibility spec [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-compat.el | 57 +++ lisp/erc/erc-fill.el | 307 +++++++++++++++-- lisp/erc/erc-match.el | 31 +- lisp/erc/erc-stamp.el | 210 ++++++++++-- lisp/erc/erc.el | 127 ++++--- test/lisp/erc/erc-fill-tests.el | 324 ++++++++++++++++++ .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 ------ test/lisp/erc/erc-stamp-tests.el | 265 ++++++++++++++ test/lisp/erc/erc-tests.el | 79 ++++- .../fill/snapshots/monospace-01-start.eld | 1 + .../fill/snapshots/monospace-02-right.eld | 1 + .../fill/snapshots/monospace-03-left.eld | 1 + .../fill/snapshots/monospace-04-reset.eld | 1 + 14 files changed, 1497 insertions(+), 217 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el create mode 100644 test/lisp/erc/erc-stamp-tests.el create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld Interdiff: diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 95d374b121e..b04386c6a3b 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1976,22 +1976,12 @@ erc--initialize-markers erc-input-marker (make-marker)) (if continued-session (progn - ;; Respect existing multiline input after prompt. Expect any - ;; text preceding it on the same line, including whitespace, - ;; to be part of the prompt itself. - (goto-char (point-max)) - (forward-line 0) - (while (and (not (get-text-property (point) 'erc-prompt)) - (zerop (forward-line -1)))) - (cl-assert (not (= (point) (point-min)))) - (set-marker erc-insert-marker (point)) - ;; If the input area is clean, this search should fail and - ;; return point max. Otherwise, it should return the position - ;; after the last char with the `erc-prompt' property, as per - ;; the doc string for `next-single-property-change'. + ;; Trust existing markers. + (set-marker erc-insert-marker + (alist-get 'erc-insert-marker continued-session)) (set-marker erc-input-marker - (next-single-property-change (point) 'erc-prompt nil - (point-max))) + (alist-get 'erc-input-marker continued-session)) + (goto-char erc-insert-marker) (cl-assert (= (field-end) erc-input-marker)) (goto-char old-point) (erc--unhide-prompt)) @@ -2043,7 +2033,8 @@ erc-open (and-let* (((not target)) (m (buffer-local-value 'erc-input-marker buffer)) - ((marker-position m))))))) + ((marker-position m))) + (buffer-local-variables buffer))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Refactor-marker-initialization-in-erc-open.patch From 342d6959d68015d596ffc12a65bb57bff942d6ec Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Jan 2023 20:48:24 -0800 Subject: [PATCH 1/8] [5.6] Refactor marker initialization in erc-open * lisp/erc/erc.el (erc--initialize-markers): New helper to ensure prompt and its associated markers are set up correctly. (erc-open): When determining whether a session is a logical continuation, leverage the work already performed by the `erc-networks' library to that effect. Its verdicts are based on network context and thus reliable even when a user dials anew from an entry-point, which is not a simple reconnection because the user expects a clean slate for everything except an existing buffer's messages, meaning `erc--server-reconnecting' will be nil and local-module state variables need resetting. Also remove the check for `erc-reuse-buffers' and instead trust that `erc-get-buffer-create' always does the right thing in. Replace all code involving marker and prompt setup by deferring to a new helper, `erc--initialize markers'. * test/lisp/erc/erc-tests.el (erc--initialize-markers): New test. * test/lisp/erc/erc-scenarios-base-local-module-modes.el: New file. * test/lisp/erc/erc-scenarios-base-local-modules.el (erc-scenarios-base-local-modules--mode-persistence): Move test to separate file to help with parallel "-j" runs. (Bug#60936.) --- lisp/erc/erc.el | 70 +++--- .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 -------- test/lisp/erc/erc-tests.el | 79 ++++++- 4 files changed, 322 insertions(+), 137 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index d35907a1677..27e46e6681b 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1966,6 +1966,35 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Trust existing markers. + (set-marker erc-insert-marker + (alist-get 'erc-insert-marker continued-session)) + (set-marker erc-input-marker + (alist-get 'erc-input-marker continued-session)) + (goto-char erc-insert-marker) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -1999,10 +2028,13 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))) + (buffer-local-variables buffer))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2020,21 +2052,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2081,20 +2098,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 1318207a3bf..d6dbd87c8cc 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -82,105 +82,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..c5a40d9bc72 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From b38279a2e792015065bbf142a5a57e3539416763 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 2/8] [5.6] Adjust some old text properties in ERC buffers * lisp/erc/erc.el (erc-display-message): Replace `rear-sticky' text property, which has been around since 2002, with more useful `erc-message' property. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. (erc-put-text-property, erc-list): Alias these to built-in functions. (erc--own-property-names, erc--remove-text-properties) Add internal variable and helper function for filtering values returned by `filter-buffer-substring-function'. (erc-restore-text-properties): Don't forget tags when restoring. (erc--get-eq-comparable-cmd): New function to extract commands for use as easily searchable text-property values. (Bug#60936.) --- lisp/erc/erc.el | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 27e46e6681b..b04386c6a3b 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2871,7 +2871,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) + (put-text-property + 0 (length string) 'erc-message + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4249,6 +4251,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -4300,7 +4326,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) @@ -5672,7 +5698,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5682,14 +5708,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7283,10 +7304,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7306,6 +7328,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Expose-insertion-time-as-text-prop-in-erc-stamp.patch From 52e83b811bfa55ae1c4b46728e6724ab8573ba04 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 03:10:20 -0800 Subject: [PATCH 3/8] [5.6] Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property `erc-timestamp' to store lisp time object formerly ensconced in a closure. Instead of creating a new lambda for the cursor-sensor function of each message in a buffer, leave a gap between messages to trip the sensor function. The motivation behind this change is to allow third parties access to valuable timestamp data already stored by ERC anyway. Of secondary importance is discouraging the reliance on those lambdas as a means of detecting message bounds. The gap now serves a similar purpose. Basically, the final character in a message, a newline, will not have a timestamp or a sensor function. When the stamps module isn't loaded, the `erc-message' property can be used instead. Also, instead of looking for the `invisible' text property at point, which is normally `point-max' and thus outside the accessible portion of the buffer, look at the beginning of the inserted message. This allows hook members running before this function to opt out of timestamps by marking a message as invisible. (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-stamp.el | 15 ++- test/lisp/erc/erc-stamp-tests.el | 207 +++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..051d0702f06 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -162,7 +162,7 @@ erc-add-timestamp This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) + (unless (get-text-property (point-min) 'invisible) (let ((ct (current-time))) (if (fboundp erc-insert-timestamp-function) (funcall erc-insert-timestamp-function @@ -174,12 +174,12 @@ erc-add-timestamp (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -400,11 +400,16 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + ;; Could also pass an &optional `zone' arg to `format-time-string'. + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..935b9e650b3 --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,207 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\s (char-after (field-beginning (point))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;; This concerns a proposed partial reversal of the changes resulting +;; from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also a lasting commitment. The docs mention that it's +;; pointless to pair the old `intangible' property with `invisible' +;; and suggest users look at `cursor-intangible-mode'. Turning off +;; the latter does indeed do the trick as does decrementing the end of +;; the `cursor-intangible' interval so that, in addition to C-n +;; working, a C-f from before the timestamp doesn't overshoot. This +;; appears to be the case whether `erc-hide-timestamps' is enabled or +;; not, but it may be inadvisable for some reason (a hack) and +;; therefore warrants further investigation. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + +;;; erc-stamp-tests.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Make-some-erc-stamp-functions-more-limber.patch From 984bd396d31dbf1652e8230d03886614b6cde1b5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 4/8] [5.6] Make some erc-stamp functions more limber TODO: update ERC-NEWS announcing deprecation. * lisp/erc/erc-stamp.el (erc-timestamp-format-right): Deprecate option and change meaning of its nil value to fall through to `erc-timestamp-format'. Do this to allow modules to predict what the right-hand stamp's final width will be. This also saves `erc-insert-timestamp-left-and-right' from calling `erc-format-timestamp' again for no reason. (erc-stamp--current-time): Add new generic function and method to return current time. Default to calling `current-time'. (erc-stamp--current-time): New internal variable to hold time value used to construct time formatted stamp passed to `erc-insert-timestamp-function'. (erc-add-timestamp): Bind `erc-stamp--current-time' when calling `erc-insert-timestamp-function'. (erc-insert-timestamp-left-and-right): Use STRING parameter and favor it over the now deprecated `erc-timestamp-format-right' to avoid formatting twice. Also extract current time from the variable `erc-stamp--current-time' for similar reasons. (Bug#60936.) (erc-stamp--tz): New internal variable. (erc-format-timestamp): Pass `erc-stamp--tz' as time-zone to `format-time-string'. --- lisp/erc/erc-stamp.el | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 051d0702f06..736aa498803 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,17 +165,31 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." (unless (get-text-property (point-min) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) @@ -336,12 +358,13 @@ erc-insert-timestamp-left-and-right (setq erc-timestamp-last-inserted-right ts-right)))) ;; for testing: (setq erc-timestamp-only-if-changed-flag nil) +(defvar erc-stamp--tz nil) (defun erc-format-timestamp (time format) "Return TIME formatted as string according to FORMAT. Return the empty string if FORMAT is nil." (if format - (let ((ts (format-time-string format time))) + (let ((ts (format-time-string format time erc-stamp--tz))) (erc-put-text-property 0 (length ts) 'font-lock-face 'erc-timestamp-face ts) (erc-put-text-property 0 (length ts) 'invisible 'timestamp ts) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Put-display-properties-to-better-use-in-erc-stam.patch From e68de4d0069a9a12f4884a93678e2e55fed9efbf Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 5/8] [5.6] Put display properties to better use in erc-stamp * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-stamp-right-margin-width): New option to determine width of right margin when `erc-stamp--display-margin-mode' is active or `erc-timestamp-use-align-to' is set to `margin'. (erc-stamp--display-margin-force): Add new helper function for `erc-stamp--display-margin-mode'. (erc-stamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--nil, erc-timestamp-use-align-to--t): Adjust spacing for new default right-hand stamp, `erc-format-timestamp', which lacks a leading space. (erc-timestamp-use-align-to--integer, erc-timestamp-use-align-to--margin): New tests. (Bug#60936.) --- lisp/erc/erc-stamp.el | 156 +++++++++++++++++++++++++++---- test/lisp/erc/erc-stamp-tests.el | 70 ++++++++++++-- 2 files changed, 202 insertions(+), 24 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 736aa498803..e689caf7b61 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -239,14 +239,109 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. -A side effect of enabling this is that there will only be one -space before a right timestamp in any saved logs." - :type 'boolean) +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + +Enabling this option produces a side effect in that stamps aren't +indented in saved logs. When its value is an integer, this +option adds a space after the end of a message if the stamp +doesn't already start with one. And when its value is t, it adds +a single space, unconditionally. And while this option never +adds a space when its value is `margin', ERC does offer a +workaround in `erc-stamp-prefix-log-filter', which strips +trailing stamps from messages and puts them before every line." + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.6")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +(defun erc-stamp--adjust-right-margin (cols) + "Adjust right margin by COLS. +When COLS is zero, reset width to `erc-stamp-right-margin-width' +or one col more than the `string-width' of +`erc-timestamp-format'." + (let ((width + (if (zerop cols) + (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))) + (+ right-margin-width cols)))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + +(defun erc-stamp-prefix-log-filter (text) + "Prefix every message in the buffer with a stamp. +Remove trailing stamps as well. For now, hard code the format to +\"ZNC\"-log style, which is [HH:MM:SS]. Expect to be used as a +`erc-log-filter-function' when `erc-timestamp-use-align-to' is +non-nil." + (insert text) + (goto-char (point-min)) + (while + (progn + (when-let* (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) + (delete-region beg (1+ end))) + (when-let (time (get-text-property (point) 'erc-timestamp)) + (insert (format-time-string "[%H:%M:%S] " time))) + (zerop (forward-line)))) + "") + +(declare-function erc--remove-text-properties "erc" (string)) + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." + :interactive nil + (if erc-stamp--display-margin-mode + (progn + (erc-stamp--adjust-right-margin 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) + (kill-local-variable 'right-margin-width) + (kill-local-variable 'right-fringe-width) + (set-window-margins nil left-margin-width nil) + (set-window-fringes nil left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -265,6 +360,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -275,6 +371,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -326,25 +424,47 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 935b9e650b3..01e71e348e0 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,67 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-stamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one[" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo[" nil t)) + ;; Field starts at format string (right bracket) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns a proposed partial reversal of the changes resulting -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From c7bdb4ff5f91e5abeb324b28d0bebade0ed3589d Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 6/8] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. (Bug#60936.) --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-variant-for-erc-match-invisibility-spec.patch From 64fa7a93cd5bb249104180a9a6bea93a8fc5d956 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 05:34:56 -0800 Subject: [PATCH 7/8] [5.6] Add variant for erc-match invisibility spec * lisp/erc/erc-match.el (erc-match-enable, erc-match-disable): Arrange for possibly adding or removing `erc-match' from `buffer-invisibility-spec'. (erc-match--hide-fools-offset-bounds): Add new variable to serve as switch for activating invisibility on a modified interval that's offset toward `point-min' by one character. (erc-hide-fools): Optionally offset start and end of invisible region by minus one. (erc-match--modify-invisibility-spec): New housekeeping function to set up and tear down offset spec. (Bug#60936.) --- lisp/erc/erc-match.el | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 52ee5c855f3..a5e9720bad4 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -647,15 +650,22 @@ erc-go-to-log-matches-buffer (get-buffer (car buffer-cons)))))) (switch-to-buffer buffer-name))) -(define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +673,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch Content-Transfer-Encoding: quoted-printable From f2613f703f3e4fa49a0efb3e120b493bb0731c53 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 8/8] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-compat.el (erc-compat--29-set-transient-map-timer, erc-compat--29-set-transient-map, erc-compat--set-transient-map): Backport `set-transient-map' definition from Emacs 29. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill--wrap-value, erc-fill--wrap-movement): New variables to support new local module. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap-mode, erc-fill-wrap-enable, erc-fill-wrap-disable): New local module. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-compat.el | 57 +++ lisp/erc/erc-fill.el | 273 ++++++++++++++- test/lisp/erc/erc-fill-tests.el | 324 ++++++++++++++++++ .../fill/snapshots/monospace-01-start.eld | 1 + .../fill/snapshots/monospace-02-right.eld | 1 + .../fill/snapshots/monospace-03-left.eld | 1 + .../fill/snapshots/monospace-04-reset.eld | 1 + 7 files changed, 653 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-01-sta= rt.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-02-rig= ht.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-03-lef= t.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-04-res= et.eld diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 5601ede27a5..7d635e5b1af 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,6 +409,63 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) =20 +;; FIXME remove these after bumping Compat version to 29 +(defvar erc-compat--29-set-transient-map-timer nil) + +(defun erc-compat--29-set-transient-map + (map &optional keep-pred on-exit message timeout) + (let* ((message + (when message + (let (keys) + (map-keymap (lambda (key cmd) (and cmd (push key keys))) map) + (format-spec + (if (stringp message) message "Repeat with %k") + `((?k . ,(mapconcat + (lambda (key) + (substitute-command-keys + (format "\\`%s'" (key-description (vector key)= )))) + keys ", "))))))) + (clearfun (make-symbol "clear-transient-map")) + (exitfun (lambda () + (internal-pop-keymap map 'overriding-terminal-local-ma= p) + (remove-hook 'pre-command-hook clearfun) + (when message (message "")) + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer= )) + (when on-exit (funcall on-exit))))) + (fset clearfun + (lambda () + (with-demoted-errors "set-transient-map PCH: %S" + (if (cond + ((null keep-pred) nil) + ((and (not (eq map (cadr overriding-terminal-local-map)= )) + (memq map (cddr overriding-terminal-local-map))) + t) + ((eq t keep-pred) + (let ((mc (lookup-key map (this-command-keys-vector)))) + (when (and mc (symbolp mc)) + (setq mc (or (command-remapping mc) mc))) + (and mc (eq this-command mc)))) + (t (funcall keep-pred))) + (when message (message "%s" message)) + (funcall exitfun))))) + (add-hook 'pre-command-hook clearfun) + (internal-push-keymap map 'overriding-terminal-local-map) + (when timeout + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (setq erc-compat--29-set-transient-map-timer + (run-with-idle-timer timeout nil exitfun))) + (when message (message "%s" message)) + exitfun)) + +(defmacro erc-compat--set-transient-map (&rest args) + (cons (if (>=3D emacs-major-version 29) + 'set-transient-map + 'erc-compat--29-set-transient-map) + args)) + + (provide 'erc-compat) =20 ;;; erc-compat.el ends here diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..032206b514a 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. =20 +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: =20 (require 'erc) @@ -79,16 +82,29 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) =20 (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) =20 (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +171,253 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) =20 +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-visual-keys nil) + +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall (pcase erc-fill--wrap-visual-keys + ('non-input + (if (>=3D (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "Defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c a" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + +;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + ;; FIXME use `erc-button--display-error-notice-with-keys' + ;; when bug#60933 is ready. + (concat "Enabling default global module `fill' needed by lo= cal" + " module `fill-wrap'. This will impact \C-]all\C-]= ERC" + " sessions. Add `fill' to `erc-modules' to avoid t= his" + " warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-= keys + vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center)) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-visual-keys) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the Info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill-wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- erc-fill--wrap-value ,le= n)) + (space :width erc-fill--wrap-value)))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. Another use +;; case would be to fix lines affected by toggling a display-oriented +;; mode, like `display-line-numbers-mode'. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +That is, recalculate the width of all accessible lines and reset +local prefix VALUE when non-nil." + (save-excursion + (when value + (setq erc-fill--wrap-value value)) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (line-beginning-position) (line-end-position)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf erc-fill--wrap-value arg) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. + + \\`+', \\`=3D' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`C-+', \\`C-=3D' Shift right margin rightward (shrink it) + by one column + \\`C--' Shift right margin leftward (grow it) by one + column + \\`C-0' Reset the right margin to the default + +Note that misalignment may occur when messages contain +decorations applied by third-party modules. See +`erc-fill--wrap-fix' for a temporary workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (unless (get-buffer-window) + (user-error "Command called in an undisplayed buffer")) + (let* ((total (erc-fill--wrap-nudge arg)) + (win-ratio (/ (float (- (window-point) (window-start))) + (- (window-end nil t) (window-start))))) + (when (zerop arg) + (setq arg 1)) + (erc-compat--set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?=3D ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (recenter (round (* win-ratio (window-height)))))) + (define-key map (vector (list 'control key)) + (lambda () + (interactive) + (erc-stamp--adjust-right-margin (- a)) + (recenter (round (* win-ratio (window-height)))))= ))) + map) + t + (lambda () + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (recenter (round (* win-ratio (window-height)))))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center= '." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el new file mode 100644 index 00000000000..a254d5bbc73 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,324 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;; FIXME these fixtures (and tests) are now largely useless. Due to +;; the author's ignorance regarding display properties, the "space" +;; specs of prefix props on different lines didn't initially leverage +;; a common variable (`erc-fill--wrap-value'), so the column twiddling +;; was more laborious. See decades-old comment above +;; calc_pixel_width_or_height in in xdisp.c for examples. +;; +;; TODO maybe use erts files instead of own snapshots. + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defvar erc-fill-tests--buffers nil) + +(defun erc-fill-tests--wrap-populate (test) + (cl-letf (((symbol-function 'erc-stamp--current-time) + (lambda () '(0 1)))) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (erc-stamp--tz t) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) + (erc-modules '(fill stamp)) + (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil= t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + + (setq msg "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.") + (erc-display-message nil 'notice (current-buffer) msg) + + (setq msg "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.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) + + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (while-let ((buf (pop erc-fill-tests--buffers))) + (kill-buffer buf)) + (kill-buffer)))))))) + +(defun erc-fill-tests--wrap-check-props (speaker) + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward speaker nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- erc-fill--wrap-value (,w)))) + (=3D w (string-pixel-width speaker))) + (`(space :width (- erc-fill--wrap-value ,w)) + (=3D w (length speaker)))))) + +(defun erc-fill-tests--wrap-check-prefixes () + (save-excursion + (goto-char (point-min)) + (erc-fill-tests--wrap-check-props "*** ") + (erc-fill-tests--wrap-check-props "<alice> ") + ;; Ensure the loop is not visited twice due to the gap. + (erc-fill-tests--wrap-check-props "<bob> "))) + +;; Set this variable to t to generate new snapshots after carefully +;; reviewing the output of each. +(defvar erc-fill-tests--save-p nil) + +(defun erc-fill-tests--compare (name) + (let* ((dir (expand-file-name "fill/snapshots/" (ert-resource-directory)= )) + (expect-file (file-name-with-extension (expand-file-name name dir) + "eld")) + (erc--own-property-names + (seq-difference `(erc-timestamp font-lock-face + ,@erc--own-property-names) + '(display wrap-prefix line-prefix) + #'eq)) + (print-circle t) + (print-escape-newlines t) + (print-escape-nonascii t) + (got (erc--remove-text-properties + (buffer-substring (point-min) erc-insert-marker))) + (repr (string-replace "erc-fill--wrap-value" + (number-to-string erc-fill--wrap-value) + (prin1-to-string got)))) + (with-current-buffer (generate-new-buffer name) + (push name erc-fill-tests--buffers) + (with-silent-modifications + (insert (setq got (read repr)))) + (erc-mode)) + (if erc-fill-tests--save-p + (with-temp-file expect-file + (insert repr)) + (with-temp-buffer + (insert-file-contents-literally expect-file) + (should (equal got (read (current-buffer)))))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-01-start") + + (ert-info ("Shift right by one (plus)") + (ert-with-message-capture messages + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) + (should (string-match (rx "for further adjustment") messages))) + (should (=3D erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-02-right")) + + (ert-info ("Shift left by five") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) + (should (=3D erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-03-left")) + + (ert-info ("Reset") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-04-reset"))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + (lambda () + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 2) + (should (=3D erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge -6) + (should (=3D erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 0) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + + ;; FIXME get rid of this "void variable `erc--results-ewoc'" + ;; error, which seems related to operating in a non-default + ;; frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +(ert-deftest erc-fill-wrap-visual-keys--body () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (execute-kbd-macro "\C-e") + (should (search-backward "tedious fool" nil t)) + (should-not (looking-back "done to her\\.")) + (forward-char) + (execute-kbd-macro "\C-e") + (should (search-forward "done to her." nil t))) + + (ert-info ("Value: nil") + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (goto-char (point-min)) + (should (search-forward "in debug mode" nil t)) + (execute-kbd-macro "\C-a") + (should (looking-at (rx "*** "))) + (execute-kbd-macro "\C-e") + (should (eql ?\] (char-before (point))))) + + (ert-info ("Value: t") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (should (search-backward "tedious fool" nil t)) + (execute-kbd-macro "\C-e") + (should-not (looking-back (rx "done to her\\."))) + (should (search-forward "done to her." nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))))))) + +(ert-deftest erc-fill-wrap-visual-keys--prompt () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (goto-char erc-input-marker) + (insert "This buffer is for text that is not saved, and for Lisp " + "evaluation. To create a file, visit it with C-x C-f and " + "enter text in its buffer.") + + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-e") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: nil") ; same + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (execute-kbd-macro "\C-y") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: non-input") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (execute-kbd-macro "\C-y") + (execute-kbd-macro "\C-a") + (should-not (looking-at "This buffer")) + (execute-kbd-macro "\C-p") + (should-not (looking-back "its buffer\\.")) + (should (search-forward "its buffer." nil t)) + (should (search-backward "ERC> " nil t)) + (execute-kbd-macro "\C-a"))))) + +;;; erc-fill-tests.el ends here diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld new file mode 100644 index 00000000000..3f5f344cc64 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 29) line-prefix #3=3D(space :width (-= 29 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 29 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 29 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld new file mode 100644 index 00000000000..3b215936c39 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 25) line-prefix #3=3D(space :width (-= 25 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 25 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 25 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file --=20 2.39.1 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 19 Feb 2023 15:06:04 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Sun Feb 19 10:06:04 2023 Received: from localhost ([127.0.0.1]:49468 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pTlGO-0001xo-M8 for submit <at> debbugs.gnu.org; Sun, 19 Feb 2023 10:06:04 -0500 Received: from mail-108-mta102.mxroute.com ([136.175.108.102]:36755) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pTlGM-0001x9-UL for 60936 <at> debbugs.gnu.org; Sun, 19 Feb 2023 10:06:03 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta102.mxroute.com (ZoneMTA) with ESMTPSA id 1866a35c017000edb4.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Sun, 19 Feb 2023 15:05:52 +0000 X-Zone-Loop: d3f9be701db3d173cb4d1b60097e7f1853b71b32477b 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=/PBUqsTv6dUYSW5yJTL4JC2jlOs70jrdFP9aGehnCW8=; b=i+3hJVdlpgmg9Kq+NqzJDnnvnw 5s/kqCgCwiFPZ85aYjyv74nAp8npum9RAcy2elsGVrGpRvRO8H9roUjbK4EyT4hX2Qfc0/B12A6q3 EUdRAxG2laORVBuPvejmtbqasvjCk08Se535TWoWLNkf+vTroXhtsZymrLFVrlgt87Nm9xdBCHz3l 6LXI+ByF4hcLp0BkHedBvdRd+TGVH/eC6zvxayYXGbp3e9cWEXDziBSaW29ZNaYDbf/EZblQmw0AK stKrr5AgZVmZ+bDF7MiB/7ftWtZVdcfzkyGQQlhrvK+ZOgTcIV0U4bDyhgmU+MVWNBYI3fqrrPxyr Ft39nAsQ==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Sun, 19 Feb 2023 07:05:49 -0800 Message-ID: <87edqlwv8y.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v8. Fix minor-mode teardown in erc-stamp. Improve tests. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v7-v8.diff Content-Transfer-Encoding: quoted-printable From 1162cf9dc8e1d6f6a99d99c4c49cae949d2d04d3 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Feb 2023 22:34:26 -0800 Subject: [PATCH 0/8] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (8): [5.6] Refactor marker initialization in erc-open [5.6] Adjust some old text properties in ERC buffers [5.6] Expose insertion time as text prop in erc-stamp [5.6] Make some erc-stamp functions more limber [5.6] Put display properties to better use in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add variant for erc-match invisibility spec [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-compat.el | 57 +++ lisp/erc/erc-fill.el | 307 +++++++++++++++-- lisp/erc/erc-match.el | 31 +- lisp/erc/erc-stamp.el | 210 ++++++++++-- lisp/erc/erc.el | 136 +++++--- test/lisp/erc/erc-fill-tests.el | 324 ++++++++++++++++++ .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 ------ test/lisp/erc/erc-stamp-tests.el | 265 ++++++++++++++ test/lisp/erc/erc-tests.el | 79 ++++- .../fill/snapshots/monospace-01-start.eld | 1 + .../fill/snapshots/monospace-02-right.eld | 1 + .../fill/snapshots/monospace-03-left.eld | 1 + .../fill/snapshots/monospace-04-reset.eld | 1 + 14 files changed, 1506 insertions(+), 217 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el create mode 100644 test/lisp/erc/erc-stamp-tests.el create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-01-sta= rt.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-02-rig= ht.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-03-lef= t.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-04-res= et.eld Interdiff: diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index a4367fe4ba5..7d635e5b1af 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,6 +409,7 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) =20 +;; FIXME remove these after bumping Compat version to 29 (defvar erc-compat--29-set-transient-map-timer nil) =20 (defun erc-compat--29-set-transient-map diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index ba538a7c152..032206b514a 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -179,7 +179,7 @@ erc-fill-wrap-use-pixels A value of nil means ERC should use columns, which may happen regardless, depending on the Emacs version. This option only matters when `erc-fill-wrap-mode' is enabled." - :package-version '(ERC . "5.5") ; FIXME sync on release + :package-version '(ERC . "5.6") ; FIXME sync on release :type 'boolean) =20 (defcustom erc-fill-wrap-visual-keys 'non-input @@ -190,7 +190,7 @@ erc-fill-wrap-visual-keys never do so. A value of `non-input' tells ERC to act like the value is nil in the input area and t elsewhere. This option only plays a role when `erc-fill-wrap-mode' is enabled." - :package-version '(ERC . "5.5") ; FIXME sync on release + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (const t) (const non-input))) =20 (defun erc-fill--wrap-move (normal-cmd visual-cmd arg) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index c8f6e7c195c..a5e9720bad4 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -650,8 +650,6 @@ erc-go-to-log-matches-buffer (get-buffer (car buffer-cons)))))) (switch-to-buffer buffer-name))) =20 -(define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) - (defvar-local erc-match--hide-fools-offset-bounds nil) =20 (defun erc-hide-fools (match-type _nickuserhost _message) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index d1c2f790bc8..e689caf7b61 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -260,7 +260,7 @@ erc-timestamp-use-align-to workaround in `erc-stamp-prefix-log-filter', which strips trailing stamps from messages and puts them before every line." :type '(choice boolean integer (const margin)) - :package-version '(ERC . "5.5")) ; FIXME sync on release + :package-version '(ERC . "5.6")) ; FIXME sync on release =20 (defcustom erc-stamp-right-margin-width nil "Width in columns of the right margin. @@ -268,7 +268,7 @@ erc-stamp-right-margin-width than the `string-width' of the formatted `erc-timestamp-format'. This option only matters when `erc-timestamp-use-align-to' is set to `margin'." - :package-version '(ERC . "5.5") ; FIXME sync on release + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) integer)) =20 (defun erc-stamp--display-margin-force (orig &rest r) @@ -315,6 +315,8 @@ erc-stamp-prefix-log-filter (zerop (forward-line)))) "") =20 +(declare-function erc--remove-text-properties "erc" (string)) + ;; If people want to use this directly, we can convert it into ;; a local module. (define-minor-mode erc-stamp--display-margin-mode @@ -338,8 +340,8 @@ erc-stamp--display-margin-mode #'erc-stamp--display-margin-force) (kill-local-variable 'right-margin-width) (kill-local-variable 'right-fringe-width) - (set-window-margins left-margin-width nil) - (set-window-fringes left-fringe-width nil))) + (set-window-margins nil left-margin-width nil) + (set-window-fringes nil left-fringe-width nil))) =20 (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -476,12 +478,13 @@ erc-insert-timestamp-left-and-right (setq erc-timestamp-last-inserted-right ts-right)))) =20 ;; for testing: (setq erc-timestamp-only-if-changed-flag nil) +(defvar erc-stamp--tz nil) =20 (defun erc-format-timestamp (time format) "Return TIME formatted as string according to FORMAT. Return the empty string if FORMAT is nil." (if format - (let ((ts (format-time-string format time))) + (let ((ts (format-time-string format time erc-stamp--tz))) (erc-put-text-property 0 (length ts) 'font-lock-face 'erc-timestamp-face ts) (erc-put-text-property 0 (length ts) 'invisible 'timestamp ts) @@ -540,6 +543,7 @@ erc-toggle-timestamps =20 (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." + ;; Could also pass an &optional `zone' arg to `format-time-string'. (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) (when (eq 'entered dir) (when stamp diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el index 8e8d585617a..a254d5bbc73 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -25,78 +25,87 @@ ;; a common variable (`erc-fill--wrap-value'), so the column twiddling ;; was more laborious. See decades-old comment above ;; calc_pixel_width_or_height in in xdisp.c for examples. +;; +;; TODO maybe use erts files instead of own snapshots. =20 ;;; Code: (require 'ert-x) (require 'erc-fill) =20 +(defvar erc-fill-tests--buffers nil) + (defun erc-fill-tests--wrap-populate (test) - (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) - (id (erc-networks--id-create 'foonet)) - (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) - (erc-server-users (make-hash-table :test 'equal)) - (erc-fill-function 'erc-fill-wrap) - (pre-command-hook pre-command-hook) - (erc-modules '(fill stamp)) - (msg "Hello World") - (inhibit-message noninteractive) - erc-insert-post-hook - extended-command-history - erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) - (when (bound-and-true-p erc-button-mode) - (push 'erc-button-add-buttons erc-insert-modify-hook)) - (erc-mode) - (setq erc-server-process proc erc-networks--id id) - (set-process-query-on-exit-flag erc-server-process nil) - - (with-current-buffer (get-buffer-create "#chan") + (cl-letf (((symbol-function 'erc-stamp--current-time) + (lambda () '(0 1)))) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (erc-stamp--tz t) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) + (erc-modules '(fill stamp)) + (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) (erc-mode) - (erc-munge-invisibility-spec) - (setq erc-server-process proc - erc-networks--id id - erc-channel-users (make-hash-table :test 'equal) - erc--target (erc--target-from-string "#chan") - erc-default-recipients (list "#chan")) - (erc--initialize-markers (point) nil) - - (erc-update-channel-member - "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil t) - - (erc-update-channel-member - "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) - - (setq msg "This server is in debug mode and is logging all user I/O.\ + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil= t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + + (setq msg "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.") - (erc-display-message nil 'notice (current-buffer) msg) + (erc-display-message nil 'notice (current-buffer) msg) =20 - (setq msg "bob: come, you are a tedious fool: to the purpose.\ + (setq msg "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.") - (erc-display-message nil nil (current-buffer) - (erc-format-privmessage "alice" msg nil t)) - - ;; Introduce an artificial gap in properties `line-prefix' and - ;; `wrap-prefix' and later ensure they're not incremented twice. - (save-excursion - (forward-line -1) - (search-forward "? ") - (remove-text-properties (1- (point)) (point) - '(line-prefix t wrap-prefix t))) - - (setq msg "alice: Either your unparagoned mistress is dead,\ + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) + + (setq msg "alice: Either your unparagoned mistress is dead,\ or she's outprized by a trifle.") - (erc-display-message nil nil (current-buffer) - (erc-format-privmessage "bob" msg nil t)) - - (let ((original-window-buffer (window-buffer (selected-window)))) - (set-window-buffer (selected-window) (current-buffer)) - ;; Defend against non-local exits from `ert-skip' - (unwind-protect - (funcall test) - (set-window-buffer (selected-window) original-window-buffer) - (when noninteractive - (kill-buffer))))))) + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (while-let ((buf (pop erc-fill-tests--buffers))) + (kill-buffer buf)) + (kill-buffer)))))))) =20 (defun erc-fill-tests--wrap-check-props (speaker) ;; Prefix props are applied properly and faces are accounted @@ -127,6 +136,39 @@ erc-fill-tests--wrap-check-prefixes ;; Ensure the loop is not visited twice due to the gap. (erc-fill-tests--wrap-check-props "<bob> "))) =20 +;; Set this variable to t to generate new snapshots after carefully +;; reviewing the output of each. +(defvar erc-fill-tests--save-p nil) + +(defun erc-fill-tests--compare (name) + (let* ((dir (expand-file-name "fill/snapshots/" (ert-resource-directory)= )) + (expect-file (file-name-with-extension (expand-file-name name dir) + "eld")) + (erc--own-property-names + (seq-difference `(erc-timestamp font-lock-face + ,@erc--own-property-names) + '(display wrap-prefix line-prefix) + #'eq)) + (print-circle t) + (print-escape-newlines t) + (print-escape-nonascii t) + (got (erc--remove-text-properties + (buffer-substring (point-min) erc-insert-marker))) + (repr (string-replace "erc-fill--wrap-value" + (number-to-string erc-fill--wrap-value) + (prin1-to-string got)))) + (with-current-buffer (generate-new-buffer name) + (push name erc-fill-tests--buffers) + (with-silent-modifications + (insert (setq got (read repr)))) + (erc-mode)) + (if erc-fill-tests--save-p + (with-temp-file expect-file + (insert repr)) + (with-temp-buffer + (insert-file-contents-literally expect-file) + (should (equal got (read (current-buffer)))))))) + (ert-deftest erc-fill-wrap--monospace () :tags '(:unstable) =20 @@ -136,23 +178,27 @@ erc-fill-wrap--monospace (set-window-buffer (selected-window) (current-buffer)) (should (=3D erc-fill--wrap-value 27)) (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-01-start") =20 (ert-info ("Shift right by one (plus)") (ert-with-message-capture messages (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) (should (string-match (rx "for further adjustment") messages))) (should (=3D erc-fill--wrap-value 29)) - (erc-fill-tests--wrap-check-prefixes)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-02-right")) =20 (ert-info ("Shift left by five") (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) (should (=3D erc-fill--wrap-value 25)) - (erc-fill-tests--wrap-check-prefixes)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-03-left")) =20 (ert-info ("Reset") (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) (should (=3D erc-fill--wrap-value 27)) - (erc-fill-tests--wrap-check-prefixes))))) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-04-reset"))))) =20 (ert-deftest erc-fill-wrap--variable-pitch () :tags '(:unstable) diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld new file mode 100644 index 00000000000..3f5f344cc64 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 29) line-prefix #3=3D(space :width (-= 29 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 29 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 29 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld new file mode 100644 index 00000000000..3b215936c39 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 25) line-prefix #3=3D(space :width (-= 25 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 25 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 25 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file --=20 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Refactor-marker-initialization-in-erc-open.patch From 29e533b873d1f061099562944122a31542572470 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Jan 2023 20:48:24 -0800 Subject: [PATCH 1/8] [5.6] Refactor marker initialization in erc-open * lisp/erc/erc.el (erc--initialize-markers): New helper to ensure prompt and its associated markers are set up correctly. (erc-open): When determining whether a session is a logical continuation, leverage the work already performed by the `erc-networks' library to that effect. Its verdicts are based on network context and thus reliable even when a user dials anew from an entry-point, which is not a simple reconnection because the user expects a clean slate for everything except an existing buffer's messages, meaning `erc--server-reconnecting' will be nil and local-module state variables need resetting. Also remove the check for `erc-reuse-buffers' and instead trust that `erc-get-buffer-create' always does the right thing in. Replace all code involving marker and prompt setup by deferring to a new helper, `erc--initialize markers'. * test/lisp/erc/erc-tests.el (erc--initialize-markers): New test. * test/lisp/erc/erc-scenarios-base-local-module-modes.el: New file. * test/lisp/erc/erc-scenarios-base-local-modules.el (erc-scenarios-base-local-modules--mode-persistence): Move test to separate file to help with parallel "-j" runs. (Bug#60936.) --- lisp/erc/erc.el | 79 ++++--- .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 -------- test/lisp/erc/erc-tests.el | 79 ++++++- 4 files changed, 331 insertions(+), 137 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index d35907a1677..8261801ec0d 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1966,6 +1966,45 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Respect existing multiline input after prompt. Expect any + ;; text preceding it on the same line, including whitespace, + ;; to be part of the prompt itself. + (goto-char (point-max)) + (forward-line 0) + (while (and (not (get-text-property (point) 'erc-prompt)) + (zerop (forward-line -1)))) + (cl-assert (not (= (point) (point-min)))) + (set-marker erc-insert-marker (point)) + ;; If the input area is clean, this search should fail and + ;; return point max. Otherwise, it should return the position + ;; after the last char with the `erc-prompt' property, as per + ;; the doc string for `next-single-property-change'. + (set-marker erc-input-marker + (next-single-property-change (point) 'erc-prompt nil + (point-max))) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -1999,10 +2038,12 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2020,21 +2061,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2081,20 +2107,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 1318207a3bf..d6dbd87c8cc 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -82,105 +82,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..c5a40d9bc72 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From 8d61af8380bb1589d50434bcddaae14039139dd9 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 2/8] [5.6] Adjust some old text properties in ERC buffers TODO: mention adjustment in ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Replace `rear-sticky' text property, which has been around since 2002, with more useful `erc-message' property. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. (erc-put-text-property, erc-list): Alias these to built-in functions. (erc--own-property-names, erc--remove-text-properties) Add internal variable and helper function for filtering values returned by `filter-buffer-substring-function'. (erc-restore-text-properties): Don't forget tags when restoring. (erc--get-eq-comparable-cmd): New function to extract commands for use as easily searchable text-property values. (Bug#60936.) --- lisp/erc/erc.el | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 8261801ec0d..95d374b121e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2880,7 +2880,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) + (put-text-property + 0 (length string) 'erc-message + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4258,6 +4260,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -4309,7 +4335,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) @@ -5681,7 +5707,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5691,14 +5717,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7292,10 +7313,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7315,6 +7337,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Expose-insertion-time-as-text-prop-in-erc-stamp.patch From d42790326b1ae2c3340113ff979dea309df5097f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 03:10:20 -0800 Subject: [PATCH 3/8] [5.6] Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property `erc-timestamp' to store lisp time object formerly ensconced in a closure. Instead of creating a new lambda for the cursor-sensor function of each message in a buffer, leave a gap between messages to trip the sensor function. The motivation behind this change is to allow third parties access to valuable timestamp data already stored by ERC anyway. Of secondary importance is discouraging the reliance on those lambdas as a means of detecting message bounds. The gap now serves a similar purpose. Basically, the final character in a message, a newline, will not have a timestamp or a sensor function. When the stamps module isn't loaded, the `erc-message' property can be used instead. Also, instead of looking for the `invisible' text property at point, which is normally `point-max' and thus outside the accessible portion of the buffer, look at the beginning of the inserted message. This allows hook members running before this function to opt out of timestamps by marking a message as invisible. (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-stamp.el | 15 ++- test/lisp/erc/erc-stamp-tests.el | 207 +++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..051d0702f06 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -162,7 +162,7 @@ erc-add-timestamp This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) + (unless (get-text-property (point-min) 'invisible) (let ((ct (current-time))) (if (fboundp erc-insert-timestamp-function) (funcall erc-insert-timestamp-function @@ -174,12 +174,12 @@ erc-add-timestamp (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -400,11 +400,16 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + ;; Could also pass an &optional `zone' arg to `format-time-string'. + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..935b9e650b3 --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,207 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\s (char-after (field-beginning (point))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;; This concerns a proposed partial reversal of the changes resulting +;; from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also a lasting commitment. The docs mention that it's +;; pointless to pair the old `intangible' property with `invisible' +;; and suggest users look at `cursor-intangible-mode'. Turning off +;; the latter does indeed do the trick as does decrementing the end of +;; the `cursor-intangible' interval so that, in addition to C-n +;; working, a C-f from before the timestamp doesn't overshoot. This +;; appears to be the case whether `erc-hide-timestamps' is enabled or +;; not, but it may be inadvisable for some reason (a hack) and +;; therefore warrants further investigation. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + +;;; erc-stamp-tests.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Make-some-erc-stamp-functions-more-limber.patch From 890945775a3b0aeb060a66d33590e6b85a25adb7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 4/8] [5.6] Make some erc-stamp functions more limber TODO: update ERC-NEWS announcing deprecation. * lisp/erc/erc-stamp.el (erc-timestamp-format-right): Deprecate option and change meaning of its nil value to fall through to `erc-timestamp-format'. Do this to allow modules to predict what the right-hand stamp's final width will be. This also saves `erc-insert-timestamp-left-and-right' from calling `erc-format-timestamp' again for no reason. (erc-stamp--current-time): Add new generic function and method to return current time. Default to calling `current-time'. (erc-stamp--current-time): New internal variable to hold time value used to construct time formatted stamp passed to `erc-insert-timestamp-function'. (erc-add-timestamp): Bind `erc-stamp--current-time' when calling `erc-insert-timestamp-function'. (erc-insert-timestamp-left-and-right): Use STRING parameter and favor it over the now deprecated `erc-timestamp-format-right' to avoid formatting twice. Also extract current time from the variable `erc-stamp--current-time' for similar reasons. (Bug#60936.) (erc-stamp--tz): New internal variable. (erc-format-timestamp): Pass `erc-stamp--tz' as time-zone to `format-time-string'. --- lisp/erc/erc-stamp.el | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 051d0702f06..736aa498803 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,17 +165,31 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." (unless (get-text-property (point-min) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) @@ -336,12 +358,13 @@ erc-insert-timestamp-left-and-right (setq erc-timestamp-last-inserted-right ts-right)))) ;; for testing: (setq erc-timestamp-only-if-changed-flag nil) +(defvar erc-stamp--tz nil) (defun erc-format-timestamp (time format) "Return TIME formatted as string according to FORMAT. Return the empty string if FORMAT is nil." (if format - (let ((ts (format-time-string format time))) + (let ((ts (format-time-string format time erc-stamp--tz))) (erc-put-text-property 0 (length ts) 'font-lock-face 'erc-timestamp-face ts) (erc-put-text-property 0 (length ts) 'invisible 'timestamp ts) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Put-display-properties-to-better-use-in-erc-stam.patch From f3f15873c9e9c0ae90b34becf3f2db23ed11f8aa Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 5/8] [5.6] Put display properties to better use in erc-stamp * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-stamp-right-margin-width): New option to determine width of right margin when `erc-stamp--display-margin-mode' is active or `erc-timestamp-use-align-to' is set to `margin'. (erc-stamp--display-margin-force): Add new helper function for `erc-stamp--display-margin-mode'. (erc-stamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--nil, erc-timestamp-use-align-to--t): Adjust spacing for new default right-hand stamp, `erc-format-timestamp', which lacks a leading space. (erc-timestamp-use-align-to--integer, erc-timestamp-use-align-to--margin): New tests. (Bug#60936.) --- lisp/erc/erc-stamp.el | 156 +++++++++++++++++++++++++++---- test/lisp/erc/erc-stamp-tests.el | 70 ++++++++++++-- 2 files changed, 202 insertions(+), 24 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 736aa498803..e689caf7b61 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -239,14 +239,109 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. -A side effect of enabling this is that there will only be one -space before a right timestamp in any saved logs." - :type 'boolean) +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + +Enabling this option produces a side effect in that stamps aren't +indented in saved logs. When its value is an integer, this +option adds a space after the end of a message if the stamp +doesn't already start with one. And when its value is t, it adds +a single space, unconditionally. And while this option never +adds a space when its value is `margin', ERC does offer a +workaround in `erc-stamp-prefix-log-filter', which strips +trailing stamps from messages and puts them before every line." + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.6")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +(defun erc-stamp--adjust-right-margin (cols) + "Adjust right margin by COLS. +When COLS is zero, reset width to `erc-stamp-right-margin-width' +or one col more than the `string-width' of +`erc-timestamp-format'." + (let ((width + (if (zerop cols) + (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))) + (+ right-margin-width cols)))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + +(defun erc-stamp-prefix-log-filter (text) + "Prefix every message in the buffer with a stamp. +Remove trailing stamps as well. For now, hard code the format to +\"ZNC\"-log style, which is [HH:MM:SS]. Expect to be used as a +`erc-log-filter-function' when `erc-timestamp-use-align-to' is +non-nil." + (insert text) + (goto-char (point-min)) + (while + (progn + (when-let* (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) + (delete-region beg (1+ end))) + (when-let (time (get-text-property (point) 'erc-timestamp)) + (insert (format-time-string "[%H:%M:%S] " time))) + (zerop (forward-line)))) + "") + +(declare-function erc--remove-text-properties "erc" (string)) + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." + :interactive nil + (if erc-stamp--display-margin-mode + (progn + (erc-stamp--adjust-right-margin 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) + (kill-local-variable 'right-margin-width) + (kill-local-variable 'right-fringe-width) + (set-window-margins nil left-margin-width nil) + (set-window-fringes nil left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -265,6 +360,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -275,6 +371,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -326,25 +424,47 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 935b9e650b3..01e71e348e0 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,67 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-stamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one[" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo[" nil t)) + ;; Field starts at format string (right bracket) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns a proposed partial reversal of the changes resulting -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From 5f414800a7f16d990bf2531f9a2dd97fd5c3ff07 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 6/8] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. (Bug#60936.) --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-variant-for-erc-match-invisibility-spec.patch From 89ad86dfc004f855344745fccd857edfd70f14cf Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 05:34:56 -0800 Subject: [PATCH 7/8] [5.6] Add variant for erc-match invisibility spec * lisp/erc/erc-match.el (erc-match-enable, erc-match-disable): Arrange for possibly adding or removing `erc-match' from `buffer-invisibility-spec'. (erc-match--hide-fools-offset-bounds): Add new variable to serve as switch for activating invisibility on a modified interval that's offset toward `point-min' by one character. (erc-hide-fools): Optionally offset start and end of invisible region by minus one. (erc-match--modify-invisibility-spec): New housekeeping function to set up and tear down offset spec. (Bug#60936.) --- lisp/erc/erc-match.el | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 52ee5c855f3..a5e9720bad4 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -647,15 +650,22 @@ erc-go-to-log-matches-buffer (get-buffer (car buffer-cons)))))) (switch-to-buffer buffer-name))) -(define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +673,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch Content-Transfer-Encoding: quoted-printable From 1162cf9dc8e1d6f6a99d99c4c49cae949d2d04d3 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 8/8] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-compat.el (erc-compat--29-set-transient-map-timer, erc-compat--29-set-transient-map, erc-compat--set-transient-map): Backport `set-transient-map' definition from Emacs 29. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill--wrap-value, erc-fill--wrap-movement): New variables to support new local module. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap-mode, erc-fill-wrap-enable, erc-fill-wrap-disable): New local module. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-compat.el | 57 +++ lisp/erc/erc-fill.el | 273 ++++++++++++++- test/lisp/erc/erc-fill-tests.el | 324 ++++++++++++++++++ .../fill/snapshots/monospace-01-start.eld | 1 + .../fill/snapshots/monospace-02-right.eld | 1 + .../fill/snapshots/monospace-03-left.eld | 1 + .../fill/snapshots/monospace-04-reset.eld | 1 + 7 files changed, 653 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-01-sta= rt.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-02-rig= ht.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-03-lef= t.eld create mode 100644 test/lisp/erc/resources/fill/snapshots/monospace-04-res= et.eld diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 5601ede27a5..7d635e5b1af 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,6 +409,63 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) =20 +;; FIXME remove these after bumping Compat version to 29 +(defvar erc-compat--29-set-transient-map-timer nil) + +(defun erc-compat--29-set-transient-map + (map &optional keep-pred on-exit message timeout) + (let* ((message + (when message + (let (keys) + (map-keymap (lambda (key cmd) (and cmd (push key keys))) map) + (format-spec + (if (stringp message) message "Repeat with %k") + `((?k . ,(mapconcat + (lambda (key) + (substitute-command-keys + (format "\\`%s'" (key-description (vector key)= )))) + keys ", "))))))) + (clearfun (make-symbol "clear-transient-map")) + (exitfun (lambda () + (internal-pop-keymap map 'overriding-terminal-local-ma= p) + (remove-hook 'pre-command-hook clearfun) + (when message (message "")) + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer= )) + (when on-exit (funcall on-exit))))) + (fset clearfun + (lambda () + (with-demoted-errors "set-transient-map PCH: %S" + (if (cond + ((null keep-pred) nil) + ((and (not (eq map (cadr overriding-terminal-local-map)= )) + (memq map (cddr overriding-terminal-local-map))) + t) + ((eq t keep-pred) + (let ((mc (lookup-key map (this-command-keys-vector)))) + (when (and mc (symbolp mc)) + (setq mc (or (command-remapping mc) mc))) + (and mc (eq this-command mc)))) + (t (funcall keep-pred))) + (when message (message "%s" message)) + (funcall exitfun))))) + (add-hook 'pre-command-hook clearfun) + (internal-push-keymap map 'overriding-terminal-local-map) + (when timeout + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (setq erc-compat--29-set-transient-map-timer + (run-with-idle-timer timeout nil exitfun))) + (when message (message "%s" message)) + exitfun)) + +(defmacro erc-compat--set-transient-map (&rest args) + (cons (if (>=3D emacs-major-version 29) + 'set-transient-map + 'erc-compat--29-set-transient-map) + args)) + + (provide 'erc-compat) =20 ;;; erc-compat.el ends here diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..032206b514a 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. =20 +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: =20 (require 'erc) @@ -79,16 +82,29 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) =20 (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) =20 (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +171,253 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) =20 +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-visual-keys nil) + +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.6") ; FIXME sync on release + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall (pcase erc-fill--wrap-visual-keys + ('non-input + (if (>=3D (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "Defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c a" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + +;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + ;; FIXME use `erc-button--display-error-notice-with-keys' + ;; when bug#60933 is ready. + (concat "Enabling default global module `fill' needed by lo= cal" + " module `fill-wrap'. This will impact \C-]all\C-]= ERC" + " sessions. Add `fill' to `erc-modules' to avoid t= his" + " warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-= keys + vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center)) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-visual-keys) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the Info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill-wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- erc-fill--wrap-value ,le= n)) + (space :width erc-fill--wrap-value)))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. Another use +;; case would be to fix lines affected by toggling a display-oriented +;; mode, like `display-line-numbers-mode'. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +That is, recalculate the width of all accessible lines and reset +local prefix VALUE when non-nil." + (save-excursion + (when value + (setq erc-fill--wrap-value value)) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (line-beginning-position) (line-end-position)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf erc-fill--wrap-value arg) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. + + \\`+', \\`=3D' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`C-+', \\`C-=3D' Shift right margin rightward (shrink it) + by one column + \\`C--' Shift right margin leftward (grow it) by one + column + \\`C-0' Reset the right margin to the default + +Note that misalignment may occur when messages contain +decorations applied by third-party modules. See +`erc-fill--wrap-fix' for a temporary workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (unless (get-buffer-window) + (user-error "Command called in an undisplayed buffer")) + (let* ((total (erc-fill--wrap-nudge arg)) + (win-ratio (/ (float (- (window-point) (window-start))) + (- (window-end nil t) (window-start))))) + (when (zerop arg) + (setq arg 1)) + (erc-compat--set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?=3D ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (recenter (round (* win-ratio (window-height)))))) + (define-key map (vector (list 'control key)) + (lambda () + (interactive) + (erc-stamp--adjust-right-margin (- a)) + (recenter (round (* win-ratio (window-height)))))= ))) + map) + t + (lambda () + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (recenter (round (* win-ratio (window-height)))))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center= '." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests= .el new file mode 100644 index 00000000000..a254d5bbc73 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,324 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;; FIXME these fixtures (and tests) are now largely useless. Due to +;; the author's ignorance regarding display properties, the "space" +;; specs of prefix props on different lines didn't initially leverage +;; a common variable (`erc-fill--wrap-value'), so the column twiddling +;; was more laborious. See decades-old comment above +;; calc_pixel_width_or_height in in xdisp.c for examples. +;; +;; TODO maybe use erts files instead of own snapshots. + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defvar erc-fill-tests--buffers nil) + +(defun erc-fill-tests--wrap-populate (test) + (cl-letf (((symbol-function 'erc-stamp--current-time) + (lambda () '(0 1)))) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (erc-stamp--tz t) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) + (erc-modules '(fill stamp)) + (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil= t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + + (setq msg "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.") + (erc-display-message nil 'notice (current-buffer) msg) + + (setq msg "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.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) + + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (while-let ((buf (pop erc-fill-tests--buffers))) + (kill-buffer buf)) + (kill-buffer)))))))) + +(defun erc-fill-tests--wrap-check-props (speaker) + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward speaker nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- erc-fill--wrap-value (,w)))) + (=3D w (string-pixel-width speaker))) + (`(space :width (- erc-fill--wrap-value ,w)) + (=3D w (length speaker)))))) + +(defun erc-fill-tests--wrap-check-prefixes () + (save-excursion + (goto-char (point-min)) + (erc-fill-tests--wrap-check-props "*** ") + (erc-fill-tests--wrap-check-props "<alice> ") + ;; Ensure the loop is not visited twice due to the gap. + (erc-fill-tests--wrap-check-props "<bob> "))) + +;; Set this variable to t to generate new snapshots after carefully +;; reviewing the output of each. +(defvar erc-fill-tests--save-p nil) + +(defun erc-fill-tests--compare (name) + (let* ((dir (expand-file-name "fill/snapshots/" (ert-resource-directory)= )) + (expect-file (file-name-with-extension (expand-file-name name dir) + "eld")) + (erc--own-property-names + (seq-difference `(erc-timestamp font-lock-face + ,@erc--own-property-names) + '(display wrap-prefix line-prefix) + #'eq)) + (print-circle t) + (print-escape-newlines t) + (print-escape-nonascii t) + (got (erc--remove-text-properties + (buffer-substring (point-min) erc-insert-marker))) + (repr (string-replace "erc-fill--wrap-value" + (number-to-string erc-fill--wrap-value) + (prin1-to-string got)))) + (with-current-buffer (generate-new-buffer name) + (push name erc-fill-tests--buffers) + (with-silent-modifications + (insert (setq got (read repr)))) + (erc-mode)) + (if erc-fill-tests--save-p + (with-temp-file expect-file + (insert repr)) + (with-temp-buffer + (insert-file-contents-literally expect-file) + (should (equal got (read (current-buffer)))))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-01-start") + + (ert-info ("Shift right by one (plus)") + (ert-with-message-capture messages + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) + (should (string-match (rx "for further adjustment") messages))) + (should (=3D erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-02-right")) + + (ert-info ("Shift left by five") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) + (should (=3D erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-03-left")) + + (ert-info ("Reset") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill-tests--compare "monospace-04-reset"))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + (lambda () + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 2) + (should (=3D erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge -6) + (should (=3D erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 0) + (should (=3D erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + + ;; FIXME get rid of this "void variable `erc--results-ewoc'" + ;; error, which seems related to operating in a non-default + ;; frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +(ert-deftest erc-fill-wrap-visual-keys--body () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (execute-kbd-macro "\C-e") + (should (search-backward "tedious fool" nil t)) + (should-not (looking-back "done to her\\.")) + (forward-char) + (execute-kbd-macro "\C-e") + (should (search-forward "done to her." nil t))) + + (ert-info ("Value: nil") + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (goto-char (point-min)) + (should (search-forward "in debug mode" nil t)) + (execute-kbd-macro "\C-a") + (should (looking-at (rx "*** "))) + (execute-kbd-macro "\C-e") + (should (eql ?\] (char-before (point))))) + + (ert-info ("Value: t") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (should (search-backward "tedious fool" nil t)) + (execute-kbd-macro "\C-e") + (should-not (looking-back (rx "done to her\\."))) + (should (search-forward "done to her." nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))))))) + +(ert-deftest erc-fill-wrap-visual-keys--prompt () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (goto-char erc-input-marker) + (insert "This buffer is for text that is not saved, and for Lisp " + "evaluation. To create a file, visit it with C-x C-f and " + "enter text in its buffer.") + + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-e") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: nil") ; same + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (execute-kbd-macro "\C-y") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: non-input") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (execute-kbd-macro "\C-y") + (execute-kbd-macro "\C-a") + (should-not (looking-at "This buffer")) + (execute-kbd-macro "\C-p") + (should-not (looking-back "its buffer\\.")) + (should (search-forward "its buffer." nil t)) + (should (search-backward "ERC> " nil t)) + (execute-kbd-macro "\C-a"))))) + +;;; erc-fill-tests.el ends here diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld new file mode 100644 index 00000000000..3f5f344cc64 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 29) line-prefix #3=3D(space :width (-= 29 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 29 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 29 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b= /test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld new file mode 100644 index 00000000000..3b215936c39 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 25) line-prefix #3=3D(space :width (-= 25 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 25 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 25 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld = b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld new file mode 100644 index 00000000000..8262c5056f4 --- /dev/null +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -0,0 +1 @@ +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is loggin= g all user I/O. If you do not wish for everything you send to be readable b= y the server owner(s), please disconnect.[00:00]\n<alice> bob: come, you ar= e a tedious fool: to the purpose. What was done to Elbow's wife, that he ha= th cause to complain of? Come me to what was done to her.\n<bob> alice: Eit= her your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2= 1 183 (wrap-prefix #2=3D(space :width 27) line-prefix #3=3D(space :width (-= 27 (4)))) 183 190 (wrap-prefix #2# line-prefix #3# display #1=3D((margin r= ight-margin) #("[00:00]" 0 7 (display #1# isearch-open-invisible timestamp = invisible timestamp font-lock-face erc-timestamp-face)))) 190 191 (wrap-pre= fix #2# line-prefix #3#) 191 192 (wrap-prefix #2# line-prefix #4=3D(space := width (- 27 (8)))) 192 197 (wrap-prefix #2# line-prefix #4#) 197 315 (wrap-= prefix #2# line-prefix #4#) 316 348 (wrap-prefix #2# line-prefix #4#) 348 3= 49 (wrap-prefix #2# line-prefix #4#) 349 350 (wrap-prefix #2# line-prefix #= 5=3D(space :width (- 27 (6)))) 350 353 (wrap-prefix #2# line-prefix #5#) 35= 3 435 (wrap-prefix #2# line-prefix #5#) 435 436 (wrap-prefix #2# line-prefi= x #5#)) \ No newline at end of file --=20 2.39.1 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 7 Feb 2023 15:23:35 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Feb 07 10:23:35 2023 Received: from localhost ([127.0.0.1]:53782 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pPPok-0007cA-UT for submit <at> debbugs.gnu.org; Tue, 07 Feb 2023 10:23:35 -0500 Received: from mail-108-mta253.mxroute.com ([136.175.108.253]:32965) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pPPoj-0007bs-Ar for 60936 <at> debbugs.gnu.org; Tue, 07 Feb 2023 10:23:33 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta253.mxroute.com (ZoneMTA) with ESMTPSA id 1862c797981000011e.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Tue, 07 Feb 2023 15:23:23 +0000 X-Zone-Loop: 768b454177f5b3fa414db91f30cfa8ad3ac92c43ced1 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=uskaP2NV95vscz6nkuTpgqIHYAap4nlMu937qqdLr4g=; b=fGUwEtgKHZsHVGQhfbhBLK2t0k BUha7VSjr8REYuHKGtDSHUChdichLhHTfbI7l+Fy9wkXYxs1PD24Hehm2wxnW7qUogCr3tYMLtgkC 4MdUFMDO7ZDI3K8StuvlVi7cP95ruPIz0/4bKPKv2xgJGed7OcAVjPyG/kvJRWcm/eaArOOysZVz9 r301SKKfkJL7/XrcIJzur6PtBAk0Go4w6H3yuLSMI5Xm+GXBLTuM1DyfLAccB+qY3R+7uATG08TJE MNyDYCmdE4G66rf52fD8ne8uYZuxn8Qz6KZ87l0Mck8AsSrnMzsE6clFa/UAxrNJ9zJKHilrp1odP xcQr24Jg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Tue, 07 Feb 2023 07:23:20 -0800 Message-ID: <87r0v18pp3.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v7. Remove unused variable. Get smarter about display props. Add test for key bindings. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v6-v7.diff From c514a426bef91674fc726816ff415183f4d1da0c Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Tue, 7 Feb 2023 00:30:23 -0800 Subject: [PATCH 0/8] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (8): [5.6] Refactor marker initialization in erc-open [5.6] Adjust some old text properties in ERC buffers [5.6] Expose insertion time as text prop in erc-stamp [5.6] Make some erc-stamp functions more limber [5.6] Put display properties to better use in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add variant for erc-match invisibility spec [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-compat.el | 56 ++++ lisp/erc/erc-fill.el | 307 ++++++++++++++++-- lisp/erc/erc-match.el | 31 +- lisp/erc/erc-stamp.el | 204 ++++++++++-- lisp/erc/erc.el | 136 +++++--- test/lisp/erc/erc-fill-tests.el | 278 ++++++++++++++++ .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 ------ test/lisp/erc/erc-stamp-tests.el | 265 +++++++++++++++ test/lisp/erc/erc-tests.el | 79 ++++- 10 files changed, 1451 insertions(+), 215 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el create mode 100644 test/lisp/erc/erc-stamp-tests.el Interdiff: diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index aae8280baa9..994555acecf 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -95,7 +95,6 @@ erc--features-to-modules (erc-join autojoin) (erc-page page ctcp-page) (erc-sound sound ctcp-sound) - (erc-fill fill-wrap) (erc-stamp stamp timestamp) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 13e95967bf8..ba538a7c152 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -171,7 +171,6 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) -(defvar-local erc-fill--wrap-prefix nil) (defvar-local erc-fill--wrap-value nil) (defvar-local erc-fill--wrap-visual-keys nil) @@ -195,12 +194,12 @@ erc-fill-wrap-visual-keys :type '(choice (const nil) (const t) (const non-input))) (defun erc-fill--wrap-move (normal-cmd visual-cmd arg) - (funcall - (pcase erc-fill--wrap-visual-keys - ('non-input (if (>= (point) erc-input-marker) normal-cmd visual-cmd)) - ('t visual-cmd) - (_ normal-cmd)) - arg)) + (funcall (pcase erc-fill--wrap-visual-keys + ('non-input + (if (>= (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) (defun erc-fill--wrap-kill-line (arg) "Defer to `kill-line' or `kill-visual-line'." @@ -252,6 +251,7 @@ erc-fill-wrap-mode-map (defvar erc-match-mode) (defvar erc-match--hide-fools-offset-bounds) +;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) (define-erc-module fill-wrap nil "Fill style leveraging `visual-line-mode'. This local module depends on the global `fill' module. To use @@ -265,10 +265,12 @@ fill-wrap (unless erc-fill-mode (unless (memq 'fill erc-modules) (setq msg - (concat "WARNING: enabling default global module `fill' needed " - " by local module `fill-wrap'. This will impact all" - " ERC sessions. Add `fill' to `erc-modules' to avoid " - " this warning. See Info:\"(erc) Modules\" for more."))) + ;; FIXME use `erc-button--display-error-notice-with-keys' + ;; when bug#60933 is ready. + (concat "Enabling default global module `fill' needed by local" + " module `fill-wrap'. This will impact \C-]all\C-] ERC" + " sessions. Add `fill' to `erc-modules' to avoid this" + " warning. See Info:\"(erc) Modules\" for more."))) (erc-fill-mode +1)) ;; Set local value of user option (can we avoid this somehow?) (unless (eq erc-fill-function #'erc-fill-wrap) @@ -277,7 +279,6 @@ fill-wrap ((alist-get 'erc-fill-wrap-mode vars))) (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-keys vars) - erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) (when (or erc-stamp-mode (memq 'stamp erc-modules)) (erc-stamp--display-margin-mode +1)) @@ -285,11 +286,7 @@ fill-wrap (require 'erc-match) (setq erc-match--hide-fools-offset-bounds t)) (setq erc-fill--wrap-value - (or erc-fill--wrap-value erc-fill-static-center) - ;; - erc-fill--wrap-prefix - (or erc-fill--wrap-prefix - (list 'space :width erc-fill--wrap-value))) + (or erc-fill--wrap-value erc-fill-static-center)) (visual-line-mode +1) (unless (local-variable-p 'erc-fill--wrap-visual-keys) (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) @@ -298,7 +295,6 @@ fill-wrap ((when erc-stamp--display-margin-mode (erc-stamp--display-margin-mode -1)) (kill-local-variable 'erc-button--add-nickname-face-function) - (kill-local-variable 'erc-fill--wrap-prefix) (kill-local-variable 'erc-fill--wrap-value) (kill-local-variable 'erc-fill-function) (kill-local-variable 'erc-fill--wrap-visual-keys) @@ -307,7 +303,7 @@ fill-wrap (defvar-local erc-fill--wrap-length-function nil "Function to determine length of overhanging characters. -It should return an EXPR as defined by the info node `(elisp) +It should return an EXPR as defined by the Info node `(elisp) Pixel Specification'. This value should represent the width of the overhang with all faces applied, including any enclosing brackets (which are not normally fontified) and a trailing space. @@ -337,20 +333,22 @@ erc-fill-wrap ;; Leaving out the final newline doesn't seem to affect anything. (erc-put-text-properties (point-min) (point-max) '(line-prefix wrap-prefix) nil - `((space :width (- ,erc-fill--wrap-value ,len)) - ,erc-fill--wrap-prefix))))) + `((space :width (- erc-fill--wrap-value ,len)) + (space :width erc-fill--wrap-value)))))) ;; This is an experimental helper for third-party modules. You could, ;; for example, use this to automatically resize the prefix to a -;; fraction of the window's width on some event change. +;; fraction of the window's width on some event change. Another use +;; case would be to fix lines affected by toggling a display-oriented +;; mode, like `display-line-numbers-mode'. (defun erc-fill--wrap-fix (&optional value) "Re-wrap from `point-min' to `point-max'. -Reset prefix to VALUE, when given." +That is, recalculate the width of all accessible lines and reset +local prefix VALUE when non-nil." (save-excursion (when value - (setq erc-fill--wrap-value value - erc-fill--wrap-prefix (list 'space :width value))) + (setq erc-fill--wrap-value value)) (let ((inhibit-field-text-motion t) (inhibit-read-only t)) (goto-char (point-min)) @@ -361,22 +359,9 @@ erc-fill--wrap-fix (erc-fill-wrap)))))) (defun erc-fill--wrap-nudge (arg) - (save-excursion - (save-restriction - (widen) - (let ((inhibit-field-text-motion t) - (inhibit-read-only t) ; necessary? - (p (goto-char (point-min))) - v) - (when (zerop arg) - (setq arg (- erc-fill-static-center erc-fill--wrap-value))) - (cl-incf (caddr erc-fill--wrap-prefix) arg) - (cl-incf erc-fill--wrap-value arg) - (while (setq p (next-single-property-change p 'line-prefix)) - (when-let* ((this-v (get-text-property p 'line-prefix)) - ((not (eq this-v v)))) - (setq v this-v) - (cl-incf (nth 1 (nth 2 v)) arg)))))) ; (space :width (- *i* len)) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf erc-fill--wrap-value arg) arg) (defun erc-fill-wrap-nudge (arg) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index 04001ec6524..8e8d585617a 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -19,6 +19,13 @@ ;;; Commentary: +;; FIXME these fixtures (and tests) are now largely useless. Due to +;; the author's ignorance regarding display properties, the "space" +;; specs of prefix props on different lines didn't initially leverage +;; a common variable (`erc-fill--wrap-value'), so the column twiddling +;; was more laborious. See decades-old comment above +;; calc_pixel_width_or_height in in xdisp.c for examples. + ;;; Code: (require 'ert-x) (require 'erc-fill) @@ -91,55 +98,34 @@ erc-fill-tests--wrap-populate (when noninteractive (kill-buffer))))))) -(defun erc-fill-tests--wrap-check-nudge (expected-width) +(defun erc-fill-tests--wrap-check-props (speaker) + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward speaker nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- erc-fill--wrap-value (,w)))) + (= w (string-pixel-width speaker))) + (`(space :width (- erc-fill--wrap-value ,w)) + (= w (length speaker)))))) + +(defun erc-fill-tests--wrap-check-prefixes () (save-excursion (goto-char (point-min)) - (should (search-forward "*** This server" nil t)) - (should (get-text-property (pos-bol) 'line-prefix)) - (should (get-text-property (pos-eol) 'line-prefix)) - (should (equal (get-text-property (pos-bol) 'wrap-prefix) - `(space :width ,expected-width))) - (should (equal (get-text-property (pos-eol) 'wrap-prefix) - `(space :width ,expected-width))) - - ;; Prefix props are applied properly and faces are accounted - ;; for when determining widths. - (should (search-forward "<a" nil t)) - (should (get-text-property (pos-bol) 'line-prefix)) - (should (get-text-property (pos-eol) 'line-prefix)) - (should (equal (get-text-property (pos-bol) 'wrap-prefix) - `(space :width ,expected-width))) - (should (equal (get-text-property (pos-eol) 'wrap-prefix) - `(space :width ,expected-width))) - - ;; The last elt in the `:width' value is a singleton (NUM) when - ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the - ;; prod rules table under (info "(elisp) Pixel Specification"). - (should (pcase (get-text-property (point) 'line-prefix) - ((and (guard (fboundp 'string-pixel-width)) - `(space :width (- ,n (,w)))) - (and (= n expected-width) - (= w (string-pixel-width "<alice> ")))) - (`(space :width (- ,n ,w)) - (and (= n expected-width) - (= w (length "<alice> ")))))) - + (erc-fill-tests--wrap-check-props "*** ") + (erc-fill-tests--wrap-check-props "<alice> ") ;; Ensure the loop is not visited twice due to the gap. - (should (search-forward "<b" nil t)) - (should (get-text-property (pos-bol) 'line-prefix)) - (should (get-text-property (pos-eol) 'line-prefix)) - (should (equal (get-text-property (pos-bol) 'wrap-prefix) - `(space :width ,expected-width))) - (should (equal (get-text-property (pos-eol) 'wrap-prefix) - `(space :width ,expected-width))) - (should (pcase (get-text-property (point) 'line-prefix) - ((and (guard (fboundp 'string-pixel-width)) - `(space :width (- ,n (,w)))) - (and (= n expected-width) - (= w (string-pixel-width "<bob> ")))) - (`(space :width (- ,n ,w)) - (and (= n expected-width) - (= w (length "<bob> ")))))))) + (erc-fill-tests--wrap-check-props "<bob> "))) (ert-deftest erc-fill-wrap--monospace () :tags '(:unstable) @@ -148,21 +134,25 @@ erc-fill-wrap--monospace (lambda () (set-window-buffer (selected-window) (current-buffer)) - (erc-fill-tests--wrap-check-nudge 27) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) - (ert-info ("Shift right by one") + (ert-info ("Shift right by one (plus)") (ert-with-message-capture messages (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) (should (string-match (rx "for further adjustment") messages))) - (erc-fill-tests--wrap-check-nudge 29)) + (should (= erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes)) (ert-info ("Shift left by five") (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) - (erc-fill-tests--wrap-check-nudge 25)) + (should (= erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes)) (ert-info ("Reset") (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) - (erc-fill-tests--wrap-check-nudge 27))))) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes))))) (ert-deftest erc-fill-wrap--variable-pitch () :tags '(:unstable) @@ -179,13 +169,17 @@ erc-fill-wrap--variable-pitch (erc-fill-tests--wrap-populate (lambda () - (erc-fill-tests--wrap-check-nudge 27) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) (erc-fill--wrap-nudge 2) - (erc-fill-tests--wrap-check-nudge 29) + (should (= erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) (erc-fill--wrap-nudge -6) - (erc-fill-tests--wrap-check-nudge 25) + (should (= erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) (erc-fill--wrap-nudge 0) - (erc-fill-tests--wrap-check-nudge 27) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) ;; FIXME get rid of this "void variable `erc--results-ewoc'" ;; error, which seems related to operating in a non-default @@ -195,4 +189,90 @@ erc-fill-wrap--variable-pitch ;; serve as visual confirmation that the test passed. (goto-char (point-max)))))) +(ert-deftest erc-fill-wrap-visual-keys--body () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (execute-kbd-macro "\C-e") + (should (search-backward "tedious fool" nil t)) + (should-not (looking-back "done to her\\.")) + (forward-char) + (execute-kbd-macro "\C-e") + (should (search-forward "done to her." nil t))) + + (ert-info ("Value: nil") + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (goto-char (point-min)) + (should (search-forward "in debug mode" nil t)) + (execute-kbd-macro "\C-a") + (should (looking-at (rx "*** "))) + (execute-kbd-macro "\C-e") + (should (eql ?\] (char-before (point))))) + + (ert-info ("Value: t") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (should (search-backward "tedious fool" nil t)) + (execute-kbd-macro "\C-e") + (should-not (looking-back (rx "done to her\\."))) + (should (search-forward "done to her." nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))))))) + +(ert-deftest erc-fill-wrap-visual-keys--prompt () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (goto-char erc-input-marker) + (insert "This buffer is for text that is not saved, and for Lisp " + "evaluation. To create a file, visit it with C-x C-f and " + "enter text in its buffer.") + + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-e") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: nil") ; same + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (execute-kbd-macro "\C-y") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: non-input") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (execute-kbd-macro "\C-y") + (execute-kbd-macro "\C-a") + (should-not (looking-at "This buffer")) + (execute-kbd-macro "\C-p") + (should-not (looking-back "its buffer\\.")) + (should (search-forward "its buffer." nil t)) + (should (search-backward "ERC> " nil t)) + (execute-kbd-macro "\C-a"))))) + ;;; erc-fill-tests.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Refactor-marker-initialization-in-erc-open.patch From e93e145a8ae792e5b07e15b24d2821b9c09e3432 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Jan 2023 20:48:24 -0800 Subject: [PATCH 1/8] [5.6] Refactor marker initialization in erc-open * lisp/erc/erc.el (erc--initialize-markers): New helper to ensure prompt and its associated markers are set up correctly. (erc-open): When determining whether a session is a logical continuation, leverage the work already performed by the `erc-networks' library to that effect. Its verdicts are based on network context and thus reliable even when a user dials anew from an entry-point, which is not a simple reconnection because the user expects a clean slate for everything except an existing buffer's messages, meaning `erc--server-reconnecting' will be nil and local-module state variables need resetting. Also remove the check for `erc-reuse-buffers' and instead trust that `erc-get-buffer-create' always does the right thing in. Replace all code involving marker and prompt setup by deferring to a new helper, `erc--initialize markers'. * test/lisp/erc/erc-tests.el (erc--initialize-markers): New test. * test/lisp/erc/erc-scenarios-base-local-module-modes.el: New file. * test/lisp/erc/erc-scenarios-base-local-modules.el (erc-scenarios-base-local-modules--mode-persistence): Move test to separate file to help with parallel "-j" runs. (Bug#60936.) --- lisp/erc/erc.el | 79 ++++--- .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 -------- test/lisp/erc/erc-tests.el | 79 ++++++- 4 files changed, 331 insertions(+), 137 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ff1820cfaf2..363fe30ee58 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1966,6 +1966,45 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Respect existing multiline input after prompt. Expect any + ;; text preceding it on the same line, including whitespace, + ;; to be part of the prompt itself. + (goto-char (point-max)) + (forward-line 0) + (while (and (not (get-text-property (point) 'erc-prompt)) + (zerop (forward-line -1)))) + (cl-assert (not (= (point) (point-min)))) + (set-marker erc-insert-marker (point)) + ;; If the input area is clean, this search should fail and + ;; return point max. Otherwise, it should return the position + ;; after the last char with the `erc-prompt' property, as per + ;; the doc string for `next-single-property-change'. + (set-marker erc-input-marker + (next-single-property-change (point) 'erc-prompt nil + (point-max))) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -1999,10 +2038,12 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2020,21 +2061,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2081,20 +2107,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 1318207a3bf..d6dbd87c8cc 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -82,105 +82,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..c5a40d9bc72 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From e8876b407a4dffa0e7467856e7256506b60411b6 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 2/8] [5.6] Adjust some old text properties in ERC buffers TODO: mention adjustment in ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Replace `rear-sticky' text property, which has been around since 2002, with more useful `erc-message' property. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. (erc-put-text-property, erc-list): Alias these to built-in functions. (erc--own-property-names, erc--remove-text-properties) Add internal variable and helper function for filtering values returned by `filter-buffer-substring-function'. (erc-restore-text-properties): Don't forget tags when restoring. (erc--get-eq-comparable-cmd): New function to extract commands for use as easily searchable text-property values. (Bug#60936.) --- lisp/erc/erc.el | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 363fe30ee58..6b3d0b4af2f 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2880,7 +2880,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) + (put-text-property + 0 (length string) 'erc-message + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4258,6 +4260,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -4309,7 +4335,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) @@ -5681,7 +5707,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5691,14 +5717,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7292,10 +7313,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7315,6 +7337,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Expose-insertion-time-as-text-prop-in-erc-stamp.patch From fcc63e5d4ff4c5d3db48e15caee8b11680da9748 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 03:10:20 -0800 Subject: [PATCH 3/8] [5.6] Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property `erc-timestamp' to store lisp time object formerly ensconced in a closure. Instead of creating a new lambda for the cursor-sensor function of each message in a buffer, leave a gap between messages to trip the sensor function. The motivation behind this change is to allow third parties access to valuable timestamp data already stored by ERC anyway. Of secondary importance is discouraging the reliance on those lambdas as a means of detecting message bounds. The gap now serves a similar purpose. Basically, the final character in a message, a newline, will not have a timestamp or a sensor function. When the stamps module isn't loaded, the `erc-message' property can be used instead. Also, instead of looking for the `invisible' text property at point, which is normally `point-max' and thus outside the accessible portion of the buffer, look at the beginning of the inserted message. This allows hook members running before this function to opt out of timestamps by marking a message as invisible. (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-stamp.el | 14 ++- test/lisp/erc/erc-stamp-tests.el | 207 +++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..08cdc1c8518 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -162,7 +162,7 @@ erc-add-timestamp This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) + (unless (get-text-property (point-min) 'invisible) (let ((ct (current-time))) (if (fboundp erc-insert-timestamp-function) (funcall erc-insert-timestamp-function @@ -174,12 +174,12 @@ erc-add-timestamp (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -400,11 +400,15 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..935b9e650b3 --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,207 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\s (char-after (field-beginning (point))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;; This concerns a proposed partial reversal of the changes resulting +;; from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also a lasting commitment. The docs mention that it's +;; pointless to pair the old `intangible' property with `invisible' +;; and suggest users look at `cursor-intangible-mode'. Turning off +;; the latter does indeed do the trick as does decrementing the end of +;; the `cursor-intangible' interval so that, in addition to C-n +;; working, a C-f from before the timestamp doesn't overshoot. This +;; appears to be the case whether `erc-hide-timestamps' is enabled or +;; not, but it may be inadvisable for some reason (a hack) and +;; therefore warrants further investigation. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + +;;; erc-stamp-tests.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Make-some-erc-stamp-functions-more-limber.patch From 454023b0aaf43a68adc2709e57b1d647d5a96374 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 4/8] [5.6] Make some erc-stamp functions more limber TODO: update ERC-NEWS announcing deprecation. * lisp/erc/erc-stamp.el (erc-timestamp-format-right): Deprecate option and change meaning of its nil value to fall through to `erc-timestamp-format'. Do this to allow modules to predict what the right-hand stamp's final width will be. This also saves `erc-insert-timestamp-left-and-right' from calling `erc-format-timestamp' again for no reason. (erc-stamp--current-time): Add new generic function and method to return current time. Default to calling `current-time'. (erc-stamp--current-time): New internal variable to hold time value used to construct time formatted stamp passed to `erc-insert-timestamp-function'. (erc-add-timestamp): Bind `erc-stamp--current-time' when calling `erc-insert-timestamp-function'. (erc-insert-timestamp-left-and-right): Use STRING parameter and favor it over the now deprecated `erc-timestamp-format-right' to avoid formatting twice. Also extract current time from the variable `erc-stamp--current-time' for similar reasons. (Bug#60936.) --- lisp/erc/erc-stamp.el | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 08cdc1c8518..b9ad61aaf3e 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,17 +165,31 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." (unless (get-text-property (point-min) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Put-display-properties-to-better-use-in-erc-stam.patch From 98ad3c2a93d59b9d3d0258a0a4c5b268bfcae409 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 5/8] [5.6] Put display properties to better use in erc-stamp * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-stamp-right-margin-width): New option to determine width of right margin when `erc-stamp--display-margin-mode' is active or `erc-timestamp-use-align-to' is set to `margin'. (erc-stamp--display-margin-force): Add new helper function for `erc-stamp--display-margin-mode'. (erc-stamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--nil, erc-timestamp-use-align-to--t): Adjust spacing for new default right-hand stamp, `erc-format-timestamp', which lacks a leading space. (erc-timestamp-use-align-to--integer, erc-timestamp-use-align-to--margin): New tests. (Bug#60936.) --- lisp/erc/erc-stamp.el | 154 +++++++++++++++++++++++++++---- test/lisp/erc/erc-stamp-tests.el | 70 ++++++++++++-- 2 files changed, 200 insertions(+), 24 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index b9ad61aaf3e..d1c2f790bc8 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -239,14 +239,107 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. -A side effect of enabling this is that there will only be one -space before a right timestamp in any saved logs." - :type 'boolean) +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + +Enabling this option produces a side effect in that stamps aren't +indented in saved logs. When its value is an integer, this +option adds a space after the end of a message if the stamp +doesn't already start with one. And when its value is t, it adds +a single space, unconditionally. And while this option never +adds a space when its value is `margin', ERC does offer a +workaround in `erc-stamp-prefix-log-filter', which strips +trailing stamps from messages and puts them before every line." + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.5")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +(defun erc-stamp--adjust-right-margin (cols) + "Adjust right margin by COLS. +When COLS is zero, reset width to `erc-stamp-right-margin-width' +or one col more than the `string-width' of +`erc-timestamp-format'." + (let ((width + (if (zerop cols) + (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))) + (+ right-margin-width cols)))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + +(defun erc-stamp-prefix-log-filter (text) + "Prefix every message in the buffer with a stamp. +Remove trailing stamps as well. For now, hard code the format to +\"ZNC\"-log style, which is [HH:MM:SS]. Expect to be used as a +`erc-log-filter-function' when `erc-timestamp-use-align-to' is +non-nil." + (insert text) + (goto-char (point-min)) + (while + (progn + (when-let* (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) + (delete-region beg (1+ end))) + (when-let (time (get-text-property (point) 'erc-timestamp)) + (insert (format-time-string "[%H:%M:%S] " time))) + (zerop (forward-line)))) + "") + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." + :interactive nil + (if erc-stamp--display-margin-mode + (progn + (erc-stamp--adjust-right-margin 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) + (kill-local-variable 'right-margin-width) + (kill-local-variable 'right-fringe-width) + (set-window-margins left-margin-width nil) + (set-window-fringes left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -265,6 +358,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -275,6 +369,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -326,25 +422,47 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 935b9e650b3..01e71e348e0 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,67 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-stamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one[" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo[" nil t)) + ;; Field starts at format string (right bracket) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns a proposed partial reversal of the changes resulting -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From c99c11e05bd8c1b7b4fa8e7db1943d02473b4308 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 6/8] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. (Bug#60936.) --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-variant-for-erc-match-invisibility-spec.patch From e713cb5d0def830da82921964a69e2a90a6dc810 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 05:34:56 -0800 Subject: [PATCH 7/8] [5.6] Add variant for erc-match invisibility spec * lisp/erc/erc-match.el (erc-match-enable, erc-match-disable): Arrange for possibly adding or removing `erc-match' from `buffer-invisibility-spec'. (erc-match--hide-fools-offset-bounds): Add new variable to serve as switch for activating invisibility on a modified interval that's offset toward `point-min' by one character. (erc-hide-fools): Optionally offset start and end of invisible region by minus one. (erc-match--modify-invisibility-spec): New housekeeping function to set up and tear down offset spec. (Bug#60936.) --- lisp/erc/erc-match.el | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 499bcaf5724..87272f0b647 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -649,13 +652,22 @@ erc-go-to-log-matches-buffer (define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) + (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +675,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch From c514a426bef91674fc726816ff415183f4d1da0c Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 8/8] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-compat.el (erc-compat--29-set-transient-map-timer, erc-compat--29-set-transient-map, erc-compat--set-transient-map): Backport `set-transient-map' definition from Emacs 29. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill--wrap-value, erc-fill--wrap-movement): New variables to support new local module. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap-mode, erc-fill-wrap-enable, erc-fill-wrap-disable): New local module. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. (Bug#60936.) --- lisp/erc/erc-compat.el | 56 +++++++ lisp/erc/erc-fill.el | 273 ++++++++++++++++++++++++++++++- test/lisp/erc/erc-fill-tests.el | 278 ++++++++++++++++++++++++++++++++ 3 files changed, 602 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 5601ede27a5..a4367fe4ba5 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,6 +409,62 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) +(defvar erc-compat--29-set-transient-map-timer nil) + +(defun erc-compat--29-set-transient-map + (map &optional keep-pred on-exit message timeout) + (let* ((message + (when message + (let (keys) + (map-keymap (lambda (key cmd) (and cmd (push key keys))) map) + (format-spec + (if (stringp message) message "Repeat with %k") + `((?k . ,(mapconcat + (lambda (key) + (substitute-command-keys + (format "\\`%s'" (key-description (vector key))))) + keys ", "))))))) + (clearfun (make-symbol "clear-transient-map")) + (exitfun (lambda () + (internal-pop-keymap map 'overriding-terminal-local-map) + (remove-hook 'pre-command-hook clearfun) + (when message (message "")) + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (when on-exit (funcall on-exit))))) + (fset clearfun + (lambda () + (with-demoted-errors "set-transient-map PCH: %S" + (if (cond + ((null keep-pred) nil) + ((and (not (eq map (cadr overriding-terminal-local-map))) + (memq map (cddr overriding-terminal-local-map))) + t) + ((eq t keep-pred) + (let ((mc (lookup-key map (this-command-keys-vector)))) + (when (and mc (symbolp mc)) + (setq mc (or (command-remapping mc) mc))) + (and mc (eq this-command mc)))) + (t (funcall keep-pred))) + (when message (message "%s" message)) + (funcall exitfun))))) + (add-hook 'pre-command-hook clearfun) + (internal-push-keymap map 'overriding-terminal-local-map) + (when timeout + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (setq erc-compat--29-set-transient-map-timer + (run-with-idle-timer timeout nil exitfun))) + (when message (message "%s" message)) + exitfun)) + +(defmacro erc-compat--set-transient-map (&rest args) + (cons (if (>= emacs-major-version 29) + 'set-transient-map + 'erc-compat--29-set-transient-map) + args)) + + (provide 'erc-compat) ;;; erc-compat.el ends here diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..ba538a7c152 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: (require 'erc) @@ -79,16 +82,29 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +171,253 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-visual-keys nil) + +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall (pcase erc-fill--wrap-visual-keys + ('non-input + (if (>= (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "Defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c a" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + +;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + ;; FIXME use `erc-button--display-error-notice-with-keys' + ;; when bug#60933 is ready. + (concat "Enabling default global module `fill' needed by local" + " module `fill-wrap'. This will impact \C-]all\C-] ERC" + " sessions. Add `fill' to `erc-modules' to avoid this" + " warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-keys + vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center)) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-visual-keys) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the Info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill-wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- erc-fill--wrap-value ,len)) + (space :width erc-fill--wrap-value)))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. Another use +;; case would be to fix lines affected by toggling a display-oriented +;; mode, like `display-line-numbers-mode'. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +That is, recalculate the width of all accessible lines and reset +local prefix VALUE when non-nil." + (save-excursion + (when value + (setq erc-fill--wrap-value value)) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (line-beginning-position) (line-end-position)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf erc-fill--wrap-value arg) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. + + \\`+', \\`=' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`C-+', \\`C-=' Shift right margin rightward (shrink it) + by one column + \\`C--' Shift right margin leftward (grow it) by one + column + \\`C-0' Reset the right margin to the default + +Note that misalignment may occur when messages contain +decorations applied by third-party modules. See +`erc-fill--wrap-fix' for a temporary workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (unless (get-buffer-window) + (user-error "Command called in an undisplayed buffer")) + (let* ((total (erc-fill--wrap-nudge arg)) + (win-ratio (/ (float (- (window-point) (window-start))) + (- (window-end nil t) (window-start))))) + (when (zerop arg) + (setq arg 1)) + (erc-compat--set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?= ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (recenter (round (* win-ratio (window-height)))))) + (define-key map (vector (list 'control key)) + (lambda () + (interactive) + (erc-stamp--adjust-right-margin (- a)) + (recenter (round (* win-ratio (window-height)))))))) + map) + t + (lambda () + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (recenter (round (* win-ratio (window-height)))))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el new file mode 100644 index 00000000000..8e8d585617a --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,278 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;; FIXME these fixtures (and tests) are now largely useless. Due to +;; the author's ignorance regarding display properties, the "space" +;; specs of prefix props on different lines didn't initially leverage +;; a common variable (`erc-fill--wrap-value'), so the column twiddling +;; was more laborious. See decades-old comment above +;; calc_pixel_width_or_height in in xdisp.c for examples. + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defun erc-fill-tests--wrap-populate (test) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) + (erc-modules '(fill stamp)) + (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + + (setq msg "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.") + (erc-display-message nil 'notice (current-buffer) msg) + + (setq msg "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.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) + + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (kill-buffer))))))) + +(defun erc-fill-tests--wrap-check-props (speaker) + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward speaker nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width erc-fill--wrap-value))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- erc-fill--wrap-value (,w)))) + (= w (string-pixel-width speaker))) + (`(space :width (- erc-fill--wrap-value ,w)) + (= w (length speaker)))))) + +(defun erc-fill-tests--wrap-check-prefixes () + (save-excursion + (goto-char (point-min)) + (erc-fill-tests--wrap-check-props "*** ") + (erc-fill-tests--wrap-check-props "<alice> ") + ;; Ensure the loop is not visited twice due to the gap. + (erc-fill-tests--wrap-check-props "<bob> "))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + + (ert-info ("Shift right by one (plus)") + (ert-with-message-capture messages + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) + (should (string-match (rx "for further adjustment") messages))) + (should (= erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes)) + + (ert-info ("Shift left by five") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) + (should (= erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes)) + + (ert-info ("Reset") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + (lambda () + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 2) + (should (= erc-fill--wrap-value 29)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge -6) + (should (= erc-fill--wrap-value 25)) + (erc-fill-tests--wrap-check-prefixes) + (erc-fill--wrap-nudge 0) + (should (= erc-fill--wrap-value 27)) + (erc-fill-tests--wrap-check-prefixes) + + ;; FIXME get rid of this "void variable `erc--results-ewoc'" + ;; error, which seems related to operating in a non-default + ;; frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +(ert-deftest erc-fill-wrap-visual-keys--body () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (execute-kbd-macro "\C-e") + (should (search-backward "tedious fool" nil t)) + (should-not (looking-back "done to her\\.")) + (forward-char) + (execute-kbd-macro "\C-e") + (should (search-forward "done to her." nil t))) + + (ert-info ("Value: nil") + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (goto-char (point-min)) + (should (search-forward "in debug mode" nil t)) + (execute-kbd-macro "\C-a") + (should (looking-at (rx "*** "))) + (execute-kbd-macro "\C-e") + (should (eql ?\] (char-before (point))))) + + (ert-info ("Value: t") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (goto-char (point-min)) + (should (search-forward "that he hath" nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))) + (should (search-backward "tedious fool" nil t)) + (execute-kbd-macro "\C-e") + (should-not (looking-back (rx "done to her\\."))) + (should (search-forward "done to her." nil t)) + (execute-kbd-macro "\C-a") + (should-not (looking-at (rx "<alice> "))))))) + +(ert-deftest erc-fill-wrap-visual-keys--prompt () + :tags '(:unstable) + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (goto-char erc-input-marker) + (insert "This buffer is for text that is not saved, and for Lisp " + "evaluation. To create a file, visit it with C-x C-f and " + "enter text in its buffer.") + + (ert-info ("Value: non-input") + (should (eq erc-fill--wrap-visual-keys 'non-input)) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-e") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: nil") ; same + (execute-kbd-macro "\C-ca") + (should-not erc-fill--wrap-visual-keys) + (execute-kbd-macro "\C-y") + (should (looking-back "its buffer\\.")) + (execute-kbd-macro "\C-a") + (should (looking-at "This buffer")) + (execute-kbd-macro "\C-k") + (should (eobp))) + + (ert-info ("Value: non-input") + (execute-kbd-macro "\C-ca") + (should (eq erc-fill--wrap-visual-keys t)) + (execute-kbd-macro "\C-y") + (execute-kbd-macro "\C-a") + (should-not (looking-at "This buffer")) + (execute-kbd-macro "\C-p") + (should-not (looking-back "its buffer\\.")) + (should (search-forward "its buffer." nil t)) + (should (search-backward "ERC> " nil t)) + (execute-kbd-macro "\C-a"))))) + +;;; erc-fill-tests.el ends here -- 2.39.1 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 1 Feb 2023 14:27:58 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 01 09:27:58 2023 Received: from localhost ([127.0.0.1]:56936 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pNE5e-0007iz-0c for submit <at> debbugs.gnu.org; Wed, 01 Feb 2023 09:27:58 -0500 Received: from mail-108-mta91.mxroute.com ([136.175.108.91]:40931) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pNE5d-0007im-0c for 60936 <at> debbugs.gnu.org; Wed, 01 Feb 2023 09:27:57 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta91.mxroute.com (ZoneMTA) with ESMTPSA id 1860d606d89000011e.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Wed, 01 Feb 2023 14:27:48 +0000 X-Zone-Loop: 3eaaa0c75a975981d708ae9087893295e48e9fa99fda 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=5TYvnH2GGCZjzyvR4sX7D83fiAPKJFStpTpRPSqEoGA=; b=TKHHvH/U5vRqifRd1jPa64ld6J ADlIXHgr1sxMC6fyQq7epDb+OLgQsxR5+JiTsT8u/udnjHpNRUj4ra/PIKeEGaebZQOovLiPxscRx n9biwPUxpK34cl8uNKMVGpvfVYaQA3enYwQ9MrRlBkLtSgkSueERqj19k0HCbYaxbp4ewqJU5V9Pp NP65zsg9Re3okGfIEWs4SG05FQIqVitO+BHjKEJukXqHMXtjenzHPK0cSy6/uXfxiavf2wEaC2XvA +6eNzAy4h1jggN2Lumt6uQZ1e/3ZQJ8ZDemZF3OrWrYOso4XgMka92IURVKFqwNxftHNVDfrUH4YY Ltz5iWTg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Wed, 01 Feb 2023 06:27:44 -0800 Message-ID: <87mt5xcvfj.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v6. Revert addition of leading space for `margin' timestamps. Add `erc-log-filter-function' tailored to new `erc-timestamp-use-align-to' offerings. (For now, this log style resembles those produced by the ZNC bouncer. See attached sample and screenshot of originating buffer.) --=-=-= Content-Type: text/plain Content-Disposition: attachment; filename="#chan!tester@HIDDEN:6667.txt" [13:48:07] [13:48:07] [Wed Feb 1 2023] [13:48:07] *** You have joined channel #chan [13:48:07] *** Users on #chan: @bob alice tester [13:48:07] <alice> tester, welcome! [13:48:07] <bob> tester, welcome! [13:48:07] *** #chan modes: +nt [13:48:07] *** #chan was created on 2023-02-01 12:58:04 [13:48:09] <bob> alice: An actor too perhaps, if I see cause. [13:48:13] <alice> bob: Nay, but the devil take mocking: speak, sad brow and true maid. [13:48:17] <bob> alice: My liege, your highness now may do me good. [13:48:22] <alice> bob: Farewell! God knows when we shall meet again. [13:48:27] <bob> alice: Well said, old mocker: I must needs be friends with thee. --=-=-= Content-Type: image/png Content-Disposition: attachment; filename=fill-wrap-log-compare-chan.png Content-Transfer-Encoding: base64 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 4O/vT2pqKpcvX2bMmDEGWwMbk5tCXfbV1X5dunSRt6F7/PHHefHFFwH91nSm7ld/8OBBPvnkE7p1 68bbb7/NmTNnOHPmDOnp6QAkJSUxZswY4uPjSUlJISEhgTVr1gBNc39OnToVpVJJWloau3fvJiMj o5q8MdevsfrdzftT8BtqtVqq608geNBZu3at1KVLFyk7O7uaLF9VIvUMeF8a1XetJEmSVKGrlPq1 /VjqGfC+pM4vlRLibkk9A96XJg79SpIkSSot0UqRQR9KkUEfSlqtzqj+H7lw4YLk5uYmxcXFmWx/ ZmGmVKbTSpIkSVdyrkrd10ZKY7ZNMEjzQ2q01H1tpLTyp49qzWd34l6p+9pIac3Pa+VzlVKlNGDD EKn3F/2kDPVN+XxFZYVcdve1kdKwLSOlmPRT0qn009KEHROlXl88KpVXlBvkn5ubK5WWVq9zXeTk 5EiOjo7S5cuXpcGDB0udOnWSzp07JwUGBspptm7dKo0YMUI+7t+/vxQdHV2vciRJksLDw6XDhw/X mcbDw0O6cOGCwTkHBwcpJiZGPs7KypJ8fHzk47Fjx0qffvqpfBwQECBdvHjRZP3GUpd/8vLyJHNz cyk/P1+WHzx4UAoJCZGPASknJ0c+XrBggfTSSy/Jxzdu3JAA6ejRow2yLzw8XNq/f798vH79eqlX r141pq3J/8b8ayx/Y3Jj7bNkyRKpXbt2UnR0tKTVaqvZbExujLrsM9Z+//nPf6Rp06ZJOp1O6tOn j9S+fXtJkiSpb9++UmxsrNGyo6OjpY4dO0qSJElvvfWWtHTpUkmSJKlDhw7V7jG1Wi3FxsZK48eP l8aNGyefb8z9qVKpJDMzM0mlUsnnli5dKr344osm1b8p6ne378+/MnFxcVJcXJxkcb8DWYGgsQwc OJBNmzaxYMECVq5ciZ2dXbU0SktzAMzMFXj7OpF0OZv8vFIy0goACAzV95RY2yjx8nXkerKKrFuF 2Nlb1alv7/D7r/K0tDRmz57NsGHDaN26tcn2q0rz+ODUKn6+eZaS8hIAsktyGuCJ6uSV5lOkLcK1 mQst7X+fm2am0A9GZPzWM5lVnM2cqNcNdEvLS7G3+r3nxdnZucF2BAcHk52dzeDBgzEzMxwIGTFi BK+++iq3bt1CoVCQkpJCZGRkg8uqDzk5OajV6mpD9nfWdeDAgaxZs4bHHnuMM2fOUFFRIS8WMkW/ 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 jQGaGwNU7vXylVkZQ9K+9rCPDesqyS+wk18QrX0EuOCisxLqH6Cs1IMlxUjRZOcQHkERERlJpvvv v/87/T3AarV+QUMR+fJJz7BgNBupq/FRWebFbDFy8fwsrl7hxtg9NVw8xYnveBeffNhGKBhhyfV5 scxlD2eamcpyLzl5NhZdnYPZ0jvZMJj2znQLqQ4TR490UlXuxeEwc+WyHOYvGhubBo+n/+amAL/6 2SFmz3Uxc45rqA+jiIh8werr6wEweDyeSH8PTEvT6koRSV4wGOaZf63iaK2fB783lbR0TYSIiJzu SktLAdVIisgw6/B2YTTAvfedrSBSROQMo4ykiIiIiCREGUkRERERGZQB55k2Vbf0+/MlhSqcFxER EfkyUkZSRERERJKiQFJEREREkqJAUkRERESSokBSRERERJISVyD57489QGXpR8M9FhERERE5jcQV SDYcqeG+5Qv5xbqHCPj9wz0mERERETkNxBVIrvnBT7jhH77Baz9/nq8vuoTdO7YN97hEREREZJSL K5C0pFhZufqbPPPGVlzZY3lgxVL2frBjuMcmIiIiIqNYQott6g8fpPFoLVa7HWtq6nCNSURERERO A3EFki0N9Xzv63fw8O03kFdYxIY3t1E0dfpwj01ERERERrEBt0gEeHrNvVSWfsQ/PrGBr15/83CP SUREREROA3EFkrPnL2DV95/DlT12uMcjIiIiIqeJuALJJbf/3XCPQ0REREROM9rZRkRERESSokBS RERERJKiQFJEREREkjJgjeSSQtcXMQ4REREROc0oIykiIiIiSVEgKSIiIiJJUSApIiIiIkn5f6oo TjljaGhAAAAAAElFTkSuQmCC --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v5-v6.diff From 4dc8b4968313d3e99c680f25693a2a5ef7e301c5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 1 Feb 2023 05:59:21 -0800 Subject: [PATCH 0/8] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (8): [5.6] Refactor marker initialization in erc-open [5.6] Adjust some old text properties in ERC buffers [5.6] Expose insertion time as text prop in erc-stamp [5.6] Make some erc-stamp functions more limber [5.6] Put display properties to better use in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add variant for erc-match invisibility spec [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-common.el | 1 + lisp/erc/erc-compat.el | 56 +++ lisp/erc/erc-fill.el | 322 ++++++++++++++++-- lisp/erc/erc-match.el | 31 +- lisp/erc/erc-stamp.el | 204 +++++++++-- lisp/erc/erc.el | 136 +++++--- test/lisp/erc/erc-fill-tests.el | 198 +++++++++++ .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 ------ test/lisp/erc/erc-stamp-tests.el | 265 ++++++++++++++ test/lisp/erc/erc-tests.el | 79 ++++- 11 files changed, 1387 insertions(+), 215 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el create mode 100644 test/lisp/erc/erc-stamp-tests.el Interdiff: diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 8862b14b061..d1c2f790bc8 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -251,8 +251,14 @@ erc-timestamp-use-align-to right edge. If the value is `margin', the stamp appears in the right margin when visible. -A side effect of enabling this is that there will only be one -space before a right timestamp in any saved logs." +Enabling this option produces a side effect in that stamps aren't +indented in saved logs. When its value is an integer, this +option adds a space after the end of a message if the stamp +doesn't already start with one. And when its value is t, it adds +a single space, unconditionally. And while this option never +adds a space when its value is `margin', ERC does offer a +workaround in `erc-stamp-prefix-log-filter', which strips +trailing stamps from messages and puts them before every line." :type '(choice boolean integer (const margin)) :package-version '(ERC . "5.5")) ; FIXME sync on release @@ -287,6 +293,28 @@ erc-stamp--adjust-right-margin (set-window-margins nil left-margin-width width) (set-window-fringes nil left-fringe-width 0))) +(defun erc-stamp-prefix-log-filter (text) + "Prefix every message in the buffer with a stamp. +Remove trailing stamps as well. For now, hard code the format to +\"ZNC\"-log style, which is [HH:MM:SS]. Expect to be used as a +`erc-log-filter-function' when `erc-timestamp-use-align-to' is +non-nil." + (insert text) + (goto-char (point-min)) + (while + (progn + (when-let* (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) + (delete-region beg (1+ end))) + (when-let (time (get-text-property (point) 'erc-timestamp)) + (insert (format-time-string "[%H:%M:%S] " time))) + (zerop (forward-line)))) + "") + ;; If people want to use this directly, we can convert it into ;; a local module. (define-minor-mode erc-stamp--display-margin-mode @@ -408,8 +436,6 @@ erc-insert-timestamp-right (put-text-property from (point) 'display `(space :align-to (- right ,s))))) ('margin - (unless (eq ?\s (aref string 0)) - (insert-and-inherit " ")) (put-text-property 0 (length string) 'display `((margin right-margin) ,string) string)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 73260ff126b..01e71e348e0 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -155,8 +155,8 @@ erc-timestamp-use-align-to--margin (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Space not added (treated as opaque string). - (should (search-forward "msg one [" nil t)) - ;; Field covers stamp and leading space + (should (search-forward "msg one[" nil t)) + ;; Field covers stamp alone (should (eql ?e (char-before (field-beginning (point))))) ;; Vanity props extended (should (get-text-property (field-beginning (point)) 'wrap-prefix)) @@ -170,9 +170,9 @@ erc-timestamp-use-align-to--margin (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; No hard wrap - (should (search-forward "oooo [" nil t)) - ;; Field starts at leading space. - (should (eql ?\s (char-after (field-beginning (point))))) + (should (search-forward "oooo[" nil t)) + ;; Field starts at format string (right bracket) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns a proposed partial reversal of the changes resulting -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Refactor-marker-initialization-in-erc-open.patch From e22e001fe0dfc53acc229a99ff2a4f761610861a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Jan 2023 20:48:24 -0800 Subject: [PATCH 1/8] [5.6] Refactor marker initialization in erc-open * lisp/erc/erc.el (erc--initialize-markers): New helper to ensure prompt and its associated markers are set up correctly. (erc-open): When determining whether a session is a logical continuation, leverage the work already performed by the `erc-networks' library to that effect. Its verdicts are based on network context and thus reliable even when a user dials anew from an entry-point, which is not a simple reconnection because the user expects a clean slate for everything except an existing buffer's messages, meaning `erc--server-reconnecting' will be nil and local-module state variables need resetting. Also remove the check for `erc-reuse-buffers' and instead trust that `erc-get-buffer-create' always does the right thing in. Replace all code involving marker and prompt setup by deferring to a new helper, `erc--initialize markers'. * test/lisp/erc/erc-tests.el (erc--initialize-markers): New test. * test/lisp/erc/erc-scenarios-base-local-module-modes.el: New file. * test/lisp/erc/erc-scenarios-base-local-modules.el (erc-scenarios-base-local-modules--mode-persistence): Move test to separate file to help with parallel "-j" runs. --- lisp/erc/erc.el | 79 ++++--- .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 -------- test/lisp/erc/erc-tests.el | 79 ++++++- 4 files changed, 331 insertions(+), 137 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ff1820cfaf2..363fe30ee58 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1966,6 +1966,45 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Respect existing multiline input after prompt. Expect any + ;; text preceding it on the same line, including whitespace, + ;; to be part of the prompt itself. + (goto-char (point-max)) + (forward-line 0) + (while (and (not (get-text-property (point) 'erc-prompt)) + (zerop (forward-line -1)))) + (cl-assert (not (= (point) (point-min)))) + (set-marker erc-insert-marker (point)) + ;; If the input area is clean, this search should fail and + ;; return point max. Otherwise, it should return the position + ;; after the last char with the `erc-prompt' property, as per + ;; the doc string for `next-single-property-change'. + (set-marker erc-input-marker + (next-single-property-change (point) 'erc-prompt nil + (point-max))) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -1999,10 +2038,12 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2020,21 +2061,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2081,20 +2107,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 1318207a3bf..d6dbd87c8cc 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -82,105 +82,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..c5a40d9bc72 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From dd598dfae6dd975534ec289c180ff01264fe81e9 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 2/8] [5.6] Adjust some old text properties in ERC buffers TODO: mention adjustment in ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Replace `rear-sticky' text property, which has been around since 2002, with more useful `erc-message' property. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. (erc-put-text-property, erc-list): Alias these to built-in functions. (erc--own-property-names, erc--remove-text-properties) Add internal variable and helper function for filtering values returned by `filter-buffer-substring-function'. (erc-restore-text-properties): Don't forget tags when restoring. (erc--get-eq-comparable-cmd): New function to extract commands for use as easily searchable text-property values. --- lisp/erc/erc.el | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 363fe30ee58..6b3d0b4af2f 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2880,7 +2880,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) + (put-text-property + 0 (length string) 'erc-message + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4258,6 +4260,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -4309,7 +4335,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) @@ -5681,7 +5707,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5691,14 +5717,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7292,10 +7313,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7315,6 +7337,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Expose-insertion-time-as-text-prop-in-erc-stamp.patch From b23671842178070026b6036e79a4a88848d8759a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 03:10:20 -0800 Subject: [PATCH 3/8] [5.6] Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property `erc-timestamp' to store lisp time object formerly ensconced in a closure. Instead of creating a new lambda for the cursor-sensor function of each message in a buffer, leave a gap between messages to trip the sensor function. The motivation behind this change is to allow third parties access to valuable timestamp data already stored by ERC anyway. Of secondary importance is discouraging the reliance on those lambdas as a means of detecting message bounds. The gap now serves a similar purpose. Basically, the final character in a message, a newline, will not have a timestamp or a sensor function. When the stamps module isn't loaded, the `erc-message' property can be used instead. Also, instead of looking for the `invisible' text property at point, which is normally `point-max' and thus outside the accessible portion of the buffer, look at the beginning of the inserted message. This allows hook members running before this function to opt out of timestamps by marking a message as invisible. (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. --- lisp/erc/erc-stamp.el | 14 ++- test/lisp/erc/erc-stamp-tests.el | 207 +++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..08cdc1c8518 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -162,7 +162,7 @@ erc-add-timestamp This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) + (unless (get-text-property (point-min) 'invisible) (let ((ct (current-time))) (if (fboundp erc-insert-timestamp-function) (funcall erc-insert-timestamp-function @@ -174,12 +174,12 @@ erc-add-timestamp (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -400,11 +400,15 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..935b9e650b3 --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,207 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\s (char-after (field-beginning (point))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;; This concerns a proposed partial reversal of the changes resulting +;; from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also a lasting commitment. The docs mention that it's +;; pointless to pair the old `intangible' property with `invisible' +;; and suggest users look at `cursor-intangible-mode'. Turning off +;; the latter does indeed do the trick as does decrementing the end of +;; the `cursor-intangible' interval so that, in addition to C-n +;; working, a C-f from before the timestamp doesn't overshoot. This +;; appears to be the case whether `erc-hide-timestamps' is enabled or +;; not, but it may be inadvisable for some reason (a hack) and +;; therefore warrants further investigation. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + +;;; erc-stamp-tests.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Make-some-erc-stamp-functions-more-limber.patch From eac909ce56cf8dba87750676e13c37c974f72cd8 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 4/8] [5.6] Make some erc-stamp functions more limber TODO: update ERC-NEWS announcing deprecation. * lisp/erc/erc-stamp.el (erc-timestamp-format-right): Deprecate option and change meaning of its nil value to fall through to `erc-timestamp-format'. Do this to allow modules to predict what the right-hand stamp's final width will be. This also saves `erc-insert-timestamp-left-and-right' from calling `erc-format-timestamp' again for no reason. (erc-stamp--current-time): Add new generic function and method to return current time. Default to calling `current-time'. (erc-stamp--current-time): New internal variable to hold time value used to construct time formatted stamp passed to `erc-insert-timestamp-function'. (erc-add-timestamp): Bind `erc-stamp--current-time' when calling `erc-insert-timestamp-function'. (erc-insert-timestamp-left-and-right): Use STRING parameter and favor it over the now deprecated `erc-timestamp-format-right' to avoid formatting twice. Also extract current time from the variable `erc-stamp--current-time' for similar reasons. --- lisp/erc/erc-stamp.el | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 08cdc1c8518..b9ad61aaf3e 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,17 +165,31 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." (unless (get-text-property (point-min) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Put-display-properties-to-better-use-in-erc-stam.patch From b88dfe1945b3f13507bdcbc438bf438d0bb2e8b1 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 5/8] [5.6] Put display properties to better use in erc-stamp * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-stamp-right-margin-width): New option to determine width of right margin when `erc-stamp--display-margin-mode' is active or `erc-timestamp-use-align-to' is set to `margin'. (erc-stamp--display-margin-force): Add new helper function for `erc-stamp--display-margin-mode'. (erc-stamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--nil, erc-timestamp-use-align-to--t): Adjust spacing for new default right-hand stamp, `erc-format-timestamp', which lacks a leading space. (erc-timestamp-use-align-to--integer, erc-timestamp-use-align-to--margin): New tests. --- lisp/erc/erc-stamp.el | 154 +++++++++++++++++++++++++++---- test/lisp/erc/erc-stamp-tests.el | 70 ++++++++++++-- 2 files changed, 200 insertions(+), 24 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index b9ad61aaf3e..d1c2f790bc8 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -239,14 +239,107 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. -A side effect of enabling this is that there will only be one -space before a right timestamp in any saved logs." - :type 'boolean) +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + +Enabling this option produces a side effect in that stamps aren't +indented in saved logs. When its value is an integer, this +option adds a space after the end of a message if the stamp +doesn't already start with one. And when its value is t, it adds +a single space, unconditionally. And while this option never +adds a space when its value is `margin', ERC does offer a +workaround in `erc-stamp-prefix-log-filter', which strips +trailing stamps from messages and puts them before every line." + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.5")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +(defun erc-stamp--adjust-right-margin (cols) + "Adjust right margin by COLS. +When COLS is zero, reset width to `erc-stamp-right-margin-width' +or one col more than the `string-width' of +`erc-timestamp-format'." + (let ((width + (if (zerop cols) + (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))) + (+ right-margin-width cols)))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + +(defun erc-stamp-prefix-log-filter (text) + "Prefix every message in the buffer with a stamp. +Remove trailing stamps as well. For now, hard code the format to +\"ZNC\"-log style, which is [HH:MM:SS]. Expect to be used as a +`erc-log-filter-function' when `erc-timestamp-use-align-to' is +non-nil." + (insert text) + (goto-char (point-min)) + (while + (progn + (when-let* (((< (point) (pos-eol))) + (end (1- (pos-eol))) + ((eq 'erc-timestamp (field-at-pos end))) + (beg (field-beginning end)) + ;; Skip a line that's just a timestamp. + ((> beg (point)))) + (delete-region beg (1+ end))) + (when-let (time (get-text-property (point) 'erc-timestamp)) + (insert (format-time-string "[%H:%M:%S] " time))) + (zerop (forward-line)))) + "") + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." + :interactive nil + (if erc-stamp--display-margin-mode + (progn + (erc-stamp--adjust-right-margin 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) + (kill-local-variable 'right-margin-width) + (kill-local-variable 'right-fringe-width) + (set-window-margins left-margin-width nil) + (set-window-fringes left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -265,6 +358,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -275,6 +369,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -326,25 +422,47 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 935b9e650b3..01e71e348e0 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,67 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-stamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one[" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo[" nil t)) + ;; Field starts at format string (right bracket) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns a proposed partial reversal of the changes resulting -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From 4a5909b379c5d0393c6a9f46a41b8d45531e02be Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 6/8] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-variant-for-erc-match-invisibility-spec.patch From 3e6d4d199863f4c70404b90febc0e66ec9e45885 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 05:34:56 -0800 Subject: [PATCH 7/8] [5.6] Add variant for erc-match invisibility spec * lisp/erc/erc-match.el (erc-match-enable, erc-match-disable): Arrange for possibly adding or removing `erc-match' from `buffer-invisibility-spec'. (erc-match--hide-fools-offset-bounds): Add new variable to serve as switch for activating invisibility on a modified interval that's offset toward `point-min' by one character. (erc-hide-fools): Optionally offset start and end of invisible region by minus one. (erc-match--modify-invisibility-spec): New housekeeping function to set up and tear down offset spec. --- lisp/erc/erc-match.el | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 499bcaf5724..87272f0b647 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -649,13 +652,22 @@ erc-go-to-log-matches-buffer (define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) + (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +675,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch From 4dc8b4968313d3e99c680f25693a2a5ef7e301c5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 8/8] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-compat.el (erc-compat--29-set-transient-map-timer, erc-compat--29-set-transient-map, erc-compat--set-transient-map): Backport `set-transient-map' definition from Emacs 29. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill-wrap-mode, erc-fill--wrap-prefix, erc-fill--wrap-value, erc-fill--wrap-movement): New minor mode and variables to support it. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. --- lisp/erc/erc-common.el | 1 + lisp/erc/erc-compat.el | 56 +++++++ lisp/erc/erc-fill.el | 288 +++++++++++++++++++++++++++++++- test/lisp/erc/erc-fill-tests.el | 198 ++++++++++++++++++++++ 4 files changed, 538 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 994555acecf..aae8280baa9 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -95,6 +95,7 @@ erc--features-to-modules (erc-join autojoin) (erc-page page ctcp-page) (erc-sound sound ctcp-sound) + (erc-fill fill-wrap) (erc-stamp stamp timestamp) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 5601ede27a5..a4367fe4ba5 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,6 +409,62 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) +(defvar erc-compat--29-set-transient-map-timer nil) + +(defun erc-compat--29-set-transient-map + (map &optional keep-pred on-exit message timeout) + (let* ((message + (when message + (let (keys) + (map-keymap (lambda (key cmd) (and cmd (push key keys))) map) + (format-spec + (if (stringp message) message "Repeat with %k") + `((?k . ,(mapconcat + (lambda (key) + (substitute-command-keys + (format "\\`%s'" (key-description (vector key))))) + keys ", "))))))) + (clearfun (make-symbol "clear-transient-map")) + (exitfun (lambda () + (internal-pop-keymap map 'overriding-terminal-local-map) + (remove-hook 'pre-command-hook clearfun) + (when message (message "")) + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (when on-exit (funcall on-exit))))) + (fset clearfun + (lambda () + (with-demoted-errors "set-transient-map PCH: %S" + (if (cond + ((null keep-pred) nil) + ((and (not (eq map (cadr overriding-terminal-local-map))) + (memq map (cddr overriding-terminal-local-map))) + t) + ((eq t keep-pred) + (let ((mc (lookup-key map (this-command-keys-vector)))) + (when (and mc (symbolp mc)) + (setq mc (or (command-remapping mc) mc))) + (and mc (eq this-command mc)))) + (t (funcall keep-pred))) + (when message (message "%s" message)) + (funcall exitfun))))) + (add-hook 'pre-command-hook clearfun) + (internal-push-keymap map 'overriding-terminal-local-map) + (when timeout + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (setq erc-compat--29-set-transient-map-timer + (run-with-idle-timer timeout nil exitfun))) + (when message (message "%s" message)) + exitfun)) + +(defmacro erc-compat--set-transient-map (&rest args) + (cons (if (>= emacs-major-version 29) + 'set-transient-map + 'erc-compat--29-set-transient-map) + args)) + + (provide 'erc-compat) ;;; erc-compat.el ends here diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..13e95967bf8 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: (require 'erc) @@ -79,16 +82,29 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +171,268 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) +(defvar-local erc-fill--wrap-prefix nil) +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-visual-keys nil) + +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall + (pcase erc-fill--wrap-visual-keys + ('non-input (if (>= (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "Defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c a" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + (concat "WARNING: enabling default global module `fill' needed " + " by local module `fill-wrap'. This will impact all" + " ERC sessions. Add `fill' to `erc-modules' to avoid " + " this warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-keys + vars) + erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center) + ;; + erc-fill--wrap-prefix + (or erc-fill--wrap-prefix + (list 'space :width erc-fill--wrap-value))) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-prefix) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-visual-keys) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill-wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- ,erc-fill--wrap-value ,len)) + ,erc-fill--wrap-prefix))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +Reset prefix to VALUE, when given." + (save-excursion + (when value + (setq erc-fill--wrap-value value + erc-fill--wrap-prefix (list 'space :width value))) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (line-beginning-position) (line-end-position)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (save-excursion + (save-restriction + (widen) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t) ; necessary? + (p (goto-char (point-min))) + v) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf (caddr erc-fill--wrap-prefix) arg) + (cl-incf erc-fill--wrap-value arg) + (while (setq p (next-single-property-change p 'line-prefix)) + (when-let* ((this-v (get-text-property p 'line-prefix)) + ((not (eq this-v v)))) + (setq v this-v) + (cl-incf (nth 1 (nth 2 v)) arg)))))) ; (space :width (- *i* len)) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. + + \\`+', \\`=' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`C-+', \\`C-=' Shift right margin rightward (shrink it) + by one column + \\`C--' Shift right margin leftward (grow it) by one + column + \\`C-0' Reset the right margin to the default + +Note that misalignment may occur when messages contain +decorations applied by third-party modules. See +`erc-fill--wrap-fix' for a temporary workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (unless (get-buffer-window) + (user-error "Command called in an undisplayed buffer")) + (let* ((total (erc-fill--wrap-nudge arg)) + (win-ratio (/ (float (- (window-point) (window-start))) + (- (window-end nil t) (window-start))))) + (when (zerop arg) + (setq arg 1)) + (erc-compat--set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?= ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (recenter (round (* win-ratio (window-height)))))) + (define-key map (vector (list 'control key)) + (lambda () + (interactive) + (erc-stamp--adjust-right-margin (- a)) + (recenter (round (* win-ratio (window-height)))))))) + map) + t + (lambda () + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (recenter (round (* win-ratio (window-height)))))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el new file mode 100644 index 00000000000..04001ec6524 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,198 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defun erc-fill-tests--wrap-populate (test) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) + (erc-modules '(fill stamp)) + (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + + (setq msg "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.") + (erc-display-message nil 'notice (current-buffer) msg) + + (setq msg "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.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) + + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (kill-buffer))))))) + +(defun erc-fill-tests--wrap-check-nudge (expected-width) + (save-excursion + (goto-char (point-min)) + (should (search-forward "*** This server" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- ,n (,w)))) + (and (= n expected-width) + (= w (string-pixel-width "<alice> ")))) + (`(space :width (- ,n ,w)) + (and (= n expected-width) + (= w (length "<alice> ")))))) + + ;; Ensure the loop is not visited twice due to the gap. + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- ,n (,w)))) + (and (= n expected-width) + (= w (string-pixel-width "<bob> ")))) + (`(space :width (- ,n ,w)) + (and (= n expected-width) + (= w (length "<bob> ")))))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (erc-fill-tests--wrap-check-nudge 27) + + (ert-info ("Shift right by one") + (ert-with-message-capture messages + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) + (should (string-match (rx "for further adjustment") messages))) + (erc-fill-tests--wrap-check-nudge 29)) + + (ert-info ("Shift left by five") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) + (erc-fill-tests--wrap-check-nudge 25)) + + (ert-info ("Reset") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) + (erc-fill-tests--wrap-check-nudge 27))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + (lambda () + (erc-fill-tests--wrap-check-nudge 27) + (erc-fill--wrap-nudge 2) + (erc-fill-tests--wrap-check-nudge 29) + (erc-fill--wrap-nudge -6) + (erc-fill-tests--wrap-check-nudge 25) + (erc-fill--wrap-nudge 0) + (erc-fill-tests--wrap-check-nudge 27) + + ;; FIXME get rid of this "void variable `erc--results-ewoc'" + ;; error, which seems related to operating in a non-default + ;; frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +;;; erc-fill-tests.el ends here -- 2.39.1 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 31 Jan 2023 15:28:52 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jan 31 10:28:52 2023 Received: from localhost ([127.0.0.1]:54720 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pMsZ2-0002ey-FF for submit <at> debbugs.gnu.org; Tue, 31 Jan 2023 10:28:52 -0500 Received: from mail-108-mta157.mxroute.com ([136.175.108.157]:46511) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pMsZ1-0002em-4W for 60936 <at> debbugs.gnu.org; Tue, 31 Jan 2023 10:28:51 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta157.mxroute.com (ZoneMTA) with ESMTPSA id 1860871cb3e000011e.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Tue, 31 Jan 2023 15:28:40 +0000 X-Zone-Loop: 5a4ddb979a6944bc261e813bd9bda7967d8bc5e461d6 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=yvFUZamSuKi2bNzaRngTDXcigqgmrQizasJDh+xYMXM=; b=KJbmHh/9xUdSpbPfA0N7wiNTia ncetPzbKEFx26OjTCiQF41ij2uGgWwzaT4oIwDAAOqxnK+LUhn+Dis3nxZZFoqxlJ7A+Z1DO1rfPp QE6d10Ougyp5o2wZ0k5dCnJXV/l3G1ueR6S7yYr8703CYAmZYkzyKab6ip97i/7N38obUvg5pXUwS jIh81n8ya3CCuUMQDhJLmq+bj8UynlG5Pvv1PX9ogrmET2jEAqhRxgj/xPj7VD0W4KVCyKowA4Tdb VhcBvgoq1WfIRaocJZQGZYxegk80fmvDzr4abtLAj+TDL79L7CK+P0+nQDF1qL5+SbtOuztb2H9Vu FhiRp4+w==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Tue, 31 Jan 2023 07:28:29 -0800 Message-ID: <87a61yiuzm.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v5. Fix some sloppiness in nudge command. Add (temporary) compat function for `set-transient-map'. Improve tests. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v4-v5.diff From a3e7f1555a29b147688112b01e20057d595a8eac Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Tue, 31 Jan 2023 06:48:02 -0800 Subject: [PATCH 0/8] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (8): [5.6] Refactor marker initialization in erc-open [5.6] Adjust some old text properties in ERC buffers [5.6] Expose insertion time as text prop in erc-stamp [5.6] Make some erc-stamp functions more limber [5.6] Put display properties to better use in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add variant for erc-match invisibility spec [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-common.el | 1 + lisp/erc/erc-compat.el | 56 +++ lisp/erc/erc-fill.el | 322 ++++++++++++++++-- lisp/erc/erc-match.el | 31 +- lisp/erc/erc-stamp.el | 174 ++++++++-- lisp/erc/erc.el | 136 +++++--- test/lisp/erc/erc-fill-tests.el | 198 +++++++++++ .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 ------ test/lisp/erc/erc-stamp-tests.el | 265 ++++++++++++++ test/lisp/erc/erc-tests.el | 79 ++++- 11 files changed, 1359 insertions(+), 213 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el create mode 100644 test/lisp/erc/erc-stamp-tests.el Interdiff: diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 5601ede27a5..a4367fe4ba5 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,6 +409,62 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) +(defvar erc-compat--29-set-transient-map-timer nil) + +(defun erc-compat--29-set-transient-map + (map &optional keep-pred on-exit message timeout) + (let* ((message + (when message + (let (keys) + (map-keymap (lambda (key cmd) (and cmd (push key keys))) map) + (format-spec + (if (stringp message) message "Repeat with %k") + `((?k . ,(mapconcat + (lambda (key) + (substitute-command-keys + (format "\\`%s'" (key-description (vector key))))) + keys ", "))))))) + (clearfun (make-symbol "clear-transient-map")) + (exitfun (lambda () + (internal-pop-keymap map 'overriding-terminal-local-map) + (remove-hook 'pre-command-hook clearfun) + (when message (message "")) + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (when on-exit (funcall on-exit))))) + (fset clearfun + (lambda () + (with-demoted-errors "set-transient-map PCH: %S" + (if (cond + ((null keep-pred) nil) + ((and (not (eq map (cadr overriding-terminal-local-map))) + (memq map (cddr overriding-terminal-local-map))) + t) + ((eq t keep-pred) + (let ((mc (lookup-key map (this-command-keys-vector)))) + (when (and mc (symbolp mc)) + (setq mc (or (command-remapping mc) mc))) + (and mc (eq this-command mc)))) + (t (funcall keep-pred))) + (when message (message "%s" message)) + (funcall exitfun))))) + (add-hook 'pre-command-hook clearfun) + (internal-push-keymap map 'overriding-terminal-local-map) + (when timeout + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (setq erc-compat--29-set-transient-map-timer + (run-with-idle-timer timeout nil exitfun))) + (when message (message "%s" message)) + exitfun)) + +(defmacro erc-compat--set-transient-map (&rest args) + (cons (if (>= emacs-major-version 29) + 'set-transient-map + 'erc-compat--29-set-transient-map) + args)) + + (provide 'erc-compat) ;;; erc-compat.el ends here diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index ecd721f2f03..13e95967bf8 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -366,35 +366,48 @@ erc-fill--wrap-nudge (widen) (let ((inhibit-field-text-motion t) (inhibit-read-only t) ; necessary? - (p (goto-char (point-min)))) + (p (goto-char (point-min))) + v) (when (zerop arg) (setq arg (- erc-fill-static-center erc-fill--wrap-value))) (cl-incf (caddr erc-fill--wrap-prefix) arg) (cl-incf erc-fill--wrap-value arg) (while (setq p (next-single-property-change p 'line-prefix)) - (when-let ((v (get-text-property p 'line-prefix))) - (cl-incf (nth 1 (nth 2 v)) arg) ; (space :width (- *this* len)) - (when-let - ((e (text-property-not-all p (point-max) 'line-prefix v))) - (goto-char e))))))) + (when-let* ((this-v (get-text-property p 'line-prefix)) + ((not (eq this-v v)))) + (setq v this-v) + (cl-incf (nth 1 (nth 2 v)) arg)))))) ; (space :width (- *i* len)) arg) (defun erc-fill-wrap-nudge (arg) "Adjust `erc-fill-wrap' by ARG columns. Offer to repeat command in a manner similar to -`text-scale-adjust'. Note that misalignment may occur when -messages contain decorations applied by third-party modules. -See `erc-fill--wrap-fix' for a workaround." +`text-scale-adjust'. + + \\`+', \\`=' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`C-+', \\`C-=' Shift right margin rightward (shrink it) + by one column + \\`C--' Shift right margin leftward (grow it) by one + column + \\`C-0' Reset the right margin to the default + +Note that misalignment may occur when messages contain +decorations applied by third-party modules. See +`erc-fill--wrap-fix' for a temporary workaround." (interactive "p") (unless erc-fill--wrap-value (cl-assert (not erc-fill-wrap-mode)) (user-error "Minor mode `erc-fill-wrap-mode' disabled")) - (let ((total (erc-fill--wrap-nudge arg)) - (start (window-start)) - (marker (set-marker (make-marker) (point)))) + (unless (get-buffer-window) + (user-error "Command called in an undisplayed buffer")) + (let* ((total (erc-fill--wrap-nudge arg)) + (win-ratio (/ (float (- (window-point) (window-start))) + (- (window-end nil t) (window-start))))) (when (zerop arg) (setq arg 1)) - (set-transient-map + (erc-compat--set-transient-map (let ((map (make-sparse-keymap))) (dolist (key '(?+ ?= ?- ?0)) (let ((a (pcase key @@ -405,18 +418,20 @@ erc-fill-wrap-nudge (lambda () (interactive) (cl-incf total (erc-fill--wrap-nudge a)) - (set-window-start (selected-window) start) - (goto-char marker))))) + (recenter (round (* win-ratio (window-height)))))) + (define-key map (vector (list 'control key)) + (lambda () + (interactive) + (erc-stamp--adjust-right-margin (- a)) + (recenter (round (* win-ratio (window-height)))))))) map) t (lambda () - (set-marker marker nil) (message "Fill prefix: %d (%+d col%s)" erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) "Use %k for further adjustment" 1) - (goto-char marker) - (set-window-start (selected-window) start))) + (recenter (round (* win-ratio (window-height)))))) (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 21885f3a36f..8862b14b061 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -269,6 +269,24 @@ erc-stamp--display-margin-force (let ((erc-timestamp-use-align-to 'margin)) (apply orig r))) +(defun erc-stamp--adjust-right-margin (cols) + "Adjust right margin by COLS. +When COLS is zero, reset width to `erc-stamp-right-margin-width' +or one col more than the `string-width' of +`erc-timestamp-format'." + (let ((width + (if (zerop cols) + (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))) + (+ right-margin-width cols)))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + ;; If people want to use this directly, we can convert it into ;; a local module. (define-minor-mode erc-stamp--display-margin-mode @@ -280,15 +298,8 @@ erc-stamp--display-margin-mode message text so that stamps will be visible when yanked." :interactive nil (if erc-stamp--display-margin-mode - (let ((width (or erc-stamp-right-margin-width - (1+ (string-width (or erc-timestamp-last-inserted - (erc-format-timestamp - (current-time) - erc-timestamp-format))))))) - (setq right-margin-width width - right-fringe-width 0) - (set-window-margins nil left-margin-width width) - (set-window-fringes nil left-fringe-width 0) + (progn + (erc-stamp--adjust-right-margin 0) (add-function :filter-return (local 'filter-buffer-substring-function) #'erc--remove-text-properties) (add-function :around (local 'erc-insert-timestamp-function) @@ -397,6 +408,8 @@ erc-insert-timestamp-right (put-text-property from (point) 'display `(space :align-to (- right ,s))))) ('margin + (unless (eq ?\s (aref string 0)) + (insert-and-inherit " ")) (put-text-property 0 (length string) 'display `((margin right-margin) ,string) string)) @@ -451,9 +464,8 @@ erc-format-timestamp ;; N.B. Later use categories instead of this harmless, but ;; inelegant, hack. -- BPT (and erc-timestamp-intangible - ;; (not erc-hide-timestamps) ; bug#11706 - (erc-put-text-property 0 (1- (length ts)) - 'cursor-intangible t ts)) + (not erc-hide-timestamps) ; bug#11706 + (erc-put-text-property 0 (length ts) 'cursor-intangible t ts)) ts) "")) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index 77d553bc3a2..04001ec6524 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -29,8 +29,12 @@ erc-fill-tests--wrap-populate (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) (erc-server-users (make-hash-table :test 'equal)) (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) (erc-modules '(fill stamp)) (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) (when (bound-and-true-p erc-button-mode) (push 'erc-button-add-buttons erc-insert-modify-hook)) @@ -53,28 +57,89 @@ erc-fill-tests--wrap-populate (erc-update-channel-member "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + (setq msg "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.") - (erc-display-message nil 'notice (current-buffer) msg) + (setq msg "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.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) - (erc-display-message - nil nil (current-buffer) - (erc-format-privmessage "alice" msg nil t)) (setq msg "alice: Either your unparagoned mistress is dead,\ or she's outprized by a trifle.") - - (erc-display-message - nil nil (current-buffer) - (erc-format-privmessage "bob" msg nil t)) - - (funcall test) - (when noninteractive - (kill-buffer))))) + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (kill-buffer))))))) + +(defun erc-fill-tests--wrap-check-nudge (expected-width) + (save-excursion + (goto-char (point-min)) + (should (search-forward "*** This server" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- ,n (,w)))) + (and (= n expected-width) + (= w (string-pixel-width "<alice> ")))) + (`(space :width (- ,n ,w)) + (and (= n expected-width) + (= w (length "<alice> ")))))) + + ;; Ensure the loop is not visited twice due to the gap. + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- ,n (,w)))) + (and (= n expected-width) + (= w (string-pixel-width "<bob> ")))) + (`(space :width (- ,n ,w)) + (and (= n expected-width) + (= w (length "<bob> ")))))))) (ert-deftest erc-fill-wrap--monospace () :tags '(:unstable) @@ -82,42 +147,22 @@ erc-fill-wrap--monospace (erc-fill-tests--wrap-populate (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (erc-fill-tests--wrap-check-nudge 27) - ;; Prefix props are applied properly and faces are accounted - ;; for when determining widths. - (goto-char (point-min)) - (should (search-forward "<a" nil t)) - (should (get-text-property (pos-bol) 'line-prefix)) - (should (get-text-property (pos-eol) 'line-prefix)) - (should (equal (get-text-property (pos-bol) 'wrap-prefix) - '(space :width 27))) - (should (equal (get-text-property (pos-eol) 'wrap-prefix) - '(space :width 27))) - ;; The last elt in the `:width' value is a singleton (NUM) when - ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the - ;; prod rules table under (info "(elisp) Pixel Specification"). - (should (pcase (get-text-property (point) 'line-prefix) - ((and (guard (fboundp 'string-pixel-width)) - `(space :width (- 27 (,w)))) - (= w (string-pixel-width "<alice> "))) - (`(space :width (- 27 ,w)) - (= w (length "<alice> "))))) - - (erc-fill--wrap-nudge 2) - - (should (search-forward "<b" nil t)) - (should (get-text-property (pos-bol) 'line-prefix)) - (should (get-text-property (pos-eol) 'line-prefix)) - (should (equal (get-text-property (pos-bol) 'wrap-prefix) - '(space :width 29))) - (should (equal (get-text-property (pos-eol) 'wrap-prefix) - '(space :width 29))) - (should (pcase (get-text-property (point) 'line-prefix) - ((and (guard (fboundp 'string-pixel-width)) - `(space :width (- 29 (,w)))) - (= w (string-pixel-width "<bob> "))) - (`(space :width (- 29 ,w)) - (= w (length "<bob> ")))))))) + (ert-info ("Shift right by one") + (ert-with-message-capture messages + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) + (should (string-match (rx "for further adjustment") messages))) + (erc-fill-tests--wrap-check-nudge 29)) + + (ert-info ("Shift left by five") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) + (erc-fill-tests--wrap-check-nudge 25)) + + (ert-info ("Reset") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) + (erc-fill-tests--wrap-check-nudge 27))))) (ert-deftest erc-fill-wrap--variable-pitch () :tags '(:unstable) @@ -133,37 +178,18 @@ erc-fill-wrap--variable-pitch :font 'unspecified) (erc-fill-tests--wrap-populate - (lambda () - - (goto-char (point-min)) - (should (search-forward "<a" nil t)) - (should (get-text-property (pos-bol) 'line-prefix)) - (should (get-text-property (pos-eol) 'line-prefix)) - (should (equal (get-text-property (pos-bol) 'wrap-prefix) - '(space :width 27))) - (should (equal (get-text-property (pos-eol) 'wrap-prefix) - '(space :width 27))) - (should (pcase (get-text-property (point) 'line-prefix) - (`(space :width (- 27 (,w))) - (> w (string-pixel-width "<alice> "))))) - + (erc-fill-tests--wrap-check-nudge 27) (erc-fill--wrap-nudge 2) - - (should (search-forward "<b" nil t)) - (should (get-text-property (pos-bol) 'line-prefix)) - (should (get-text-property (pos-eol) 'line-prefix)) - (should (equal (get-text-property (pos-bol) 'wrap-prefix) - '(space :width 29))) - (should (equal (get-text-property (pos-eol) 'wrap-prefix) - '(space :width 29))) - (should (pcase (get-text-property (point) 'line-prefix) - (`(space :width (- 29 (,w))) - (> w (string-pixel-width "<bob> "))))) - - ;; FIXME figure out how to get rid of this "void variable - ;; `erc--results-ewoc'" error, which seems related to operating - ;; in this second frame. + (erc-fill-tests--wrap-check-nudge 29) + (erc-fill--wrap-nudge -6) + (erc-fill-tests--wrap-check-nudge 25) + (erc-fill--wrap-nudge 0) + (erc-fill-tests--wrap-check-nudge 27) + + ;; FIXME get rid of this "void variable `erc--results-ewoc'" + ;; error, which seems related to operating in a non-default + ;; frame. ;; ;; As a kludge, checking if point made it to the prompt can ;; serve as visual confirmation that the test passed. diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 69523274812..73260ff126b 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -155,8 +155,8 @@ erc-timestamp-use-align-to--margin (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Space not added (treated as opaque string). - (should (search-forward "msg one[" nil t)) - ;; Field covers stamp alone + (should (search-forward "msg one [" nil t)) + ;; Field covers stamp and leading space (should (eql ?e (char-before (field-beginning (point))))) ;; Vanity props extended (should (get-text-property (field-beginning (point)) 'wrap-prefix)) @@ -170,12 +170,13 @@ erc-timestamp-use-align-to--margin (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; No hard wrap - (should (search-forward "oooo[" nil t)) + (should (search-forward "oooo [" nil t)) ;; Field starts at leading space. - (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\s (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) -;; This concerns the partial reversal of changes resulting from: +;; This concerns a proposed partial reversal of the changes resulting +;; from: ;; ;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) ;; @@ -186,12 +187,15 @@ erc-timestamp-use-align-to--margin ;; C-n puts point one past the start of the message (i.e., two chars ;; beyond the timestamp's closing "]". Dropping the invisible ;; property when timestamps are hidden does indeed prevent this, but -;; it's also irreversible, which at least one user has complained -;; about. Turning off `cursor-intangible-mode' does do the trick, but -;; a better solution seems to be decrementing the end of the -;; `cursor-intangible' interval so that, in addition to C-n working, a -;; C-f from before the timestamp doesn't overshoot. This works -;; whether `erc-hide-timestamps' is enabled or not. +;; it's also a lasting commitment. The docs mention that it's +;; pointless to pair the old `intangible' property with `invisible' +;; and suggest users look at `cursor-intangible-mode'. Turning off +;; the latter does indeed do the trick as does decrementing the end of +;; the `cursor-intangible' interval so that, in addition to C-n +;; working, a C-f from before the timestamp doesn't overshoot. This +;; appears to be the case whether `erc-hide-timestamps' is enabled or +;; not, but it may be inadvisable for some reason (a hack) and +;; therefore warrants further investigation. ;; ;; Note some striking omissions here: ;; -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Refactor-marker-initialization-in-erc-open.patch From 2f0595bcea827fd302c9c313fbf1d61e32b70210 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Jan 2023 20:48:24 -0800 Subject: [PATCH 1/8] [5.6] Refactor marker initialization in erc-open * lisp/erc/erc.el (erc--initialize-markers): New helper to ensure prompt and its associated markers are set up correctly. (erc-open): When determining whether a session is a logical continuation, leverage the work already performed by the `erc-networks' library to that effect. Its verdicts are based on network context and thus reliable even when a user dials anew from an entry-point, which is not a simple reconnection because the user expects a clean slate for everything except an existing buffer's messages, meaning `erc--server-reconnecting' will be nil and local-module state variables need resetting. Also remove the check for `erc-reuse-buffers' and instead trust that `erc-get-buffer-create' always does the right thing in. Replace all code involving marker and prompt setup by deferring to a new helper, `erc--initialize markers'. * test/lisp/erc/erc-tests.el (erc--initialize-markers): New test. * test/lisp/erc/erc-scenarios-base-local-module-modes.el: New file. * test/lisp/erc/erc-scenarios-base-local-modules.el (erc-scenarios-base-local-modules--mode-persistence): Move test to separate file to help with parallel "-j" runs. --- lisp/erc/erc.el | 79 ++++--- .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 -------- test/lisp/erc/erc-tests.el | 79 ++++++- 4 files changed, 331 insertions(+), 137 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ff1820cfaf2..363fe30ee58 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1966,6 +1966,45 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Respect existing multiline input after prompt. Expect any + ;; text preceding it on the same line, including whitespace, + ;; to be part of the prompt itself. + (goto-char (point-max)) + (forward-line 0) + (while (and (not (get-text-property (point) 'erc-prompt)) + (zerop (forward-line -1)))) + (cl-assert (not (= (point) (point-min)))) + (set-marker erc-insert-marker (point)) + ;; If the input area is clean, this search should fail and + ;; return point max. Otherwise, it should return the position + ;; after the last char with the `erc-prompt' property, as per + ;; the doc string for `next-single-property-change'. + (set-marker erc-input-marker + (next-single-property-change (point) 'erc-prompt nil + (point-max))) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -1999,10 +2038,12 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2020,21 +2061,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2081,20 +2107,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 1318207a3bf..d6dbd87c8cc 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -82,105 +82,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..c5a40d9bc72 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From d7f122aa18fd5d94fbbe9f9cb4da80750d7de418 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 2/8] [5.6] Adjust some old text properties in ERC buffers TODO: mention adjustment in ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Replace `rear-sticky' text property, which has been around since 2002, with more useful `erc-message' property. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. (erc-put-text-property, erc-list): Alias these to built-in functions. (erc--own-property-names, erc--remove-text-properties) Add internal variable and helper function for filtering values returned by `filter-buffer-substring-function'. (erc-restore-text-properties): Don't forget tags when restoring. (erc--get-eq-comparable-cmd): New function to extract commands for use as easily searchable text-property values. --- lisp/erc/erc.el | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 363fe30ee58..6b3d0b4af2f 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2880,7 +2880,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) + (put-text-property + 0 (length string) 'erc-message + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4258,6 +4260,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -4309,7 +4335,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) @@ -5681,7 +5707,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5691,14 +5717,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7292,10 +7313,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7315,6 +7337,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Expose-insertion-time-as-text-prop-in-erc-stamp.patch From 0119e887e11eb9d63a2502179355f918058d37f0 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 03:10:20 -0800 Subject: [PATCH 3/8] [5.6] Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property `erc-timestamp' to store lisp time object formerly ensconced in a closure. Instead of creating a new lambda for the cursor-sensor function of each message in a buffer, leave a gap between messages to trip the sensor function. The motivation behind this change is to allow third parties access to valuable timestamp data already stored by ERC anyway. Of secondary importance is discouraging the reliance on those lambdas as a means of detecting message bounds. The gap now serves a similar purpose. Basically, the final character in a message, a newline, will not have a timestamp or a sensor function. When the stamps module isn't loaded, the `erc-message' property can be used instead. Also, instead of looking for the `invisible' text property at point, which is normally `point-max' and thus outside the accessible portion of the buffer, look at the beginning of the inserted message. This allows hook members running before this function to opt out of timestamps by marking a message as invisible. (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. --- lisp/erc/erc-stamp.el | 14 ++- test/lisp/erc/erc-stamp-tests.el | 207 +++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..08cdc1c8518 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -162,7 +162,7 @@ erc-add-timestamp This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) + (unless (get-text-property (point-min) 'invisible) (let ((ct (current-time))) (if (fboundp erc-insert-timestamp-function) (funcall erc-insert-timestamp-function @@ -174,12 +174,12 @@ erc-add-timestamp (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -400,11 +400,15 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..935b9e650b3 --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,207 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\s (char-after (field-beginning (point))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;; This concerns a proposed partial reversal of the changes resulting +;; from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also a lasting commitment. The docs mention that it's +;; pointless to pair the old `intangible' property with `invisible' +;; and suggest users look at `cursor-intangible-mode'. Turning off +;; the latter does indeed do the trick as does decrementing the end of +;; the `cursor-intangible' interval so that, in addition to C-n +;; working, a C-f from before the timestamp doesn't overshoot. This +;; appears to be the case whether `erc-hide-timestamps' is enabled or +;; not, but it may be inadvisable for some reason (a hack) and +;; therefore warrants further investigation. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + +;;; erc-stamp-tests.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Make-some-erc-stamp-functions-more-limber.patch From 284d96b13dfb07a60315dc140a56e7cd58cf4b6f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 4/8] [5.6] Make some erc-stamp functions more limber TODO: update ERC-NEWS announcing deprecation. * lisp/erc/erc-stamp.el (erc-timestamp-format-right): Deprecate option and change meaning of its nil value to fall through to `erc-timestamp-format'. Do this to allow modules to predict what the right-hand stamp's final width will be. This also saves `erc-insert-timestamp-left-and-right' from calling `erc-format-timestamp' again for no reason. (erc-stamp--current-time): Add new generic function and method to return current time. Default to calling `current-time'. (erc-stamp--current-time): New internal variable to hold time value used to construct time formatted stamp passed to `erc-insert-timestamp-function'. (erc-add-timestamp): Bind `erc-stamp--current-time' when calling `erc-insert-timestamp-function'. (erc-insert-timestamp-left-and-right): Use STRING parameter and favor it over the now deprecated `erc-timestamp-format-right' to avoid formatting twice. Also extract current time from the variable `erc-stamp--current-time' for similar reasons. --- lisp/erc/erc-stamp.el | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 08cdc1c8518..b9ad61aaf3e 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,17 +165,31 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." (unless (get-text-property (point-min) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Put-display-properties-to-better-use-in-erc-stam.patch From d11132c81daa79a412ffe29e54dbefda07c1cc15 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 5/8] [5.6] Put display properties to better use in erc-stamp * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-stamp-right-margin-width): New option to determine width of right margin when `erc-stamp--display-margin-mode' is active or `erc-timestamp-use-align-to' is set to `margin'. (erc-stamp--display-margin-force): Add new helper function for `erc-stamp--display-margin-mode'. (erc-stamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--nil, erc-timestamp-use-align-to--t): Adjust spacing for new default right-hand stamp, `erc-format-timestamp', which lacks a leading space. (erc-timestamp-use-align-to--integer, erc-timestamp-use-align-to--margin): New tests. --- lisp/erc/erc-stamp.el | 124 +++++++++++++++++++++++++++---- test/lisp/erc/erc-stamp-tests.el | 70 +++++++++++++++-- 2 files changed, 172 insertions(+), 22 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index b9ad61aaf3e..8862b14b061 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -239,14 +239,79 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + A side effect of enabling this is that there will only be one space before a right timestamp in any saved logs." - :type 'boolean) + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.5")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +(defun erc-stamp--adjust-right-margin (cols) + "Adjust right margin by COLS. +When COLS is zero, reset width to `erc-stamp-right-margin-width' +or one col more than the `string-width' of +`erc-timestamp-format'." + (let ((width + (if (zerop cols) + (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))) + (+ right-margin-width cols)))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." + :interactive nil + (if erc-stamp--display-margin-mode + (progn + (erc-stamp--adjust-right-margin 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) + (kill-local-variable 'right-margin-width) + (kill-local-variable 'right-fringe-width) + (set-window-margins left-margin-width nil) + (set-window-fringes left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -265,6 +330,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -275,6 +341,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -326,25 +394,49 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (unless (eq ?\s (aref string 0)) + (insert-and-inherit " ")) + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 935b9e650b3..73260ff126b 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,67 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-stamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one [" nil t)) + ;; Field covers stamp and leading space + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns a proposed partial reversal of the changes resulting -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From 2c71d2de411226c317680a5146d3f8a011265eaf Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 6/8] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-variant-for-erc-match-invisibility-spec.patch From ba93c5adde0389eba5f5089591bd3f933a83d013 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 05:34:56 -0800 Subject: [PATCH 7/8] [5.6] Add variant for erc-match invisibility spec * lisp/erc/erc-match.el (erc-match-enable, erc-match-disable): Arrange for possibly adding or removing `erc-match' from `buffer-invisibility-spec'. (erc-match--hide-fools-offset-bounds): Add new variable to serve as switch for activating invisibility on a modified interval that's offset toward `point-min' by one character. (erc-hide-fools): Optionally offset start and end of invisible region by minus one. (erc-match--modify-invisibility-spec): New housekeeping function to set up and tear down offset spec. --- lisp/erc/erc-match.el | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 499bcaf5724..87272f0b647 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -649,13 +652,22 @@ erc-go-to-log-matches-buffer (define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) + (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +675,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch From a3e7f1555a29b147688112b01e20057d595a8eac Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 8/8] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-compat.el (erc-compat--29-set-transient-map-timer, erc-compat--29-set-transient-map, erc-compat--set-transient-map): Backport `set-transient-map' definition from Emacs 29. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill-wrap-mode, erc-fill--wrap-prefix, erc-fill--wrap-value, erc-fill--wrap-movement): New minor mode and variables to support it. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. --- lisp/erc/erc-common.el | 1 + lisp/erc/erc-compat.el | 56 +++++++ lisp/erc/erc-fill.el | 288 +++++++++++++++++++++++++++++++- test/lisp/erc/erc-fill-tests.el | 198 ++++++++++++++++++++++ 4 files changed, 538 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 994555acecf..aae8280baa9 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -95,6 +95,7 @@ erc--features-to-modules (erc-join autojoin) (erc-page page ctcp-page) (erc-sound sound ctcp-sound) + (erc-fill fill-wrap) (erc-stamp stamp timestamp) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 5601ede27a5..a4367fe4ba5 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -409,6 +409,62 @@ erc-compat--29-browse-url-irc (cons '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) existing)))))) +(defvar erc-compat--29-set-transient-map-timer nil) + +(defun erc-compat--29-set-transient-map + (map &optional keep-pred on-exit message timeout) + (let* ((message + (when message + (let (keys) + (map-keymap (lambda (key cmd) (and cmd (push key keys))) map) + (format-spec + (if (stringp message) message "Repeat with %k") + `((?k . ,(mapconcat + (lambda (key) + (substitute-command-keys + (format "\\`%s'" (key-description (vector key))))) + keys ", "))))))) + (clearfun (make-symbol "clear-transient-map")) + (exitfun (lambda () + (internal-pop-keymap map 'overriding-terminal-local-map) + (remove-hook 'pre-command-hook clearfun) + (when message (message "")) + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (when on-exit (funcall on-exit))))) + (fset clearfun + (lambda () + (with-demoted-errors "set-transient-map PCH: %S" + (if (cond + ((null keep-pred) nil) + ((and (not (eq map (cadr overriding-terminal-local-map))) + (memq map (cddr overriding-terminal-local-map))) + t) + ((eq t keep-pred) + (let ((mc (lookup-key map (this-command-keys-vector)))) + (when (and mc (symbolp mc)) + (setq mc (or (command-remapping mc) mc))) + (and mc (eq this-command mc)))) + (t (funcall keep-pred))) + (when message (message "%s" message)) + (funcall exitfun))))) + (add-hook 'pre-command-hook clearfun) + (internal-push-keymap map 'overriding-terminal-local-map) + (when timeout + (when erc-compat--29-set-transient-map-timer + (cancel-timer erc-compat--29-set-transient-map-timer)) + (setq erc-compat--29-set-transient-map-timer + (run-with-idle-timer timeout nil exitfun))) + (when message (message "%s" message)) + exitfun)) + +(defmacro erc-compat--set-transient-map (&rest args) + (cons (if (>= emacs-major-version 29) + 'set-transient-map + 'erc-compat--29-set-transient-map) + args)) + + (provide 'erc-compat) ;;; erc-compat.el ends here diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..13e95967bf8 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: (require 'erc) @@ -79,16 +82,29 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +171,268 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) +(defvar-local erc-fill--wrap-prefix nil) +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-visual-keys nil) + +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall + (pcase erc-fill--wrap-visual-keys + ('non-input (if (>= (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "Defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c a" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + (concat "WARNING: enabling default global module `fill' needed " + " by local module `fill-wrap'. This will impact all" + " ERC sessions. Add `fill' to `erc-modules' to avoid " + " this warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-keys + vars) + erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center) + ;; + erc-fill--wrap-prefix + (or erc-fill--wrap-prefix + (list 'space :width erc-fill--wrap-value))) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-prefix) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-visual-keys) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill-wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- ,erc-fill--wrap-value ,len)) + ,erc-fill--wrap-prefix))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +Reset prefix to VALUE, when given." + (save-excursion + (when value + (setq erc-fill--wrap-value value + erc-fill--wrap-prefix (list 'space :width value))) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (line-beginning-position) (line-end-position)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (save-excursion + (save-restriction + (widen) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t) ; necessary? + (p (goto-char (point-min))) + v) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf (caddr erc-fill--wrap-prefix) arg) + (cl-incf erc-fill--wrap-value arg) + (while (setq p (next-single-property-change p 'line-prefix)) + (when-let* ((this-v (get-text-property p 'line-prefix)) + ((not (eq this-v v)))) + (setq v this-v) + (cl-incf (nth 1 (nth 2 v)) arg)))))) ; (space :width (- *i* len)) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. + + \\`+', \\`=' Increase indentation by one column + \\`-' Decrease indentation by one column + \\`0' Reset indentation to the default + \\`C-+', \\`C-=' Shift right margin rightward (shrink it) + by one column + \\`C--' Shift right margin leftward (grow it) by one + column + \\`C-0' Reset the right margin to the default + +Note that misalignment may occur when messages contain +decorations applied by third-party modules. See +`erc-fill--wrap-fix' for a temporary workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (unless (get-buffer-window) + (user-error "Command called in an undisplayed buffer")) + (let* ((total (erc-fill--wrap-nudge arg)) + (win-ratio (/ (float (- (window-point) (window-start))) + (- (window-end nil t) (window-start))))) + (when (zerop arg) + (setq arg 1)) + (erc-compat--set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?= ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (recenter (round (* win-ratio (window-height)))))) + (define-key map (vector (list 'control key)) + (lambda () + (interactive) + (erc-stamp--adjust-right-margin (- a)) + (recenter (round (* win-ratio (window-height)))))))) + map) + t + (lambda () + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (recenter (round (* win-ratio (window-height)))))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el new file mode 100644 index 00000000000..04001ec6524 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,198 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defun erc-fill-tests--wrap-populate (test) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (pre-command-hook pre-command-hook) + (erc-modules '(fill stamp)) + (msg "Hello World") + (inhibit-message noninteractive) + erc-insert-post-hook + extended-command-history + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + + (setq msg "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.") + (erc-display-message nil 'notice (current-buffer) msg) + + (setq msg "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.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + + ;; Introduce an artificial gap in properties `line-prefix' and + ;; `wrap-prefix' and later ensure they're not incremented twice. + (save-excursion + (forward-line -1) + (search-forward "? ") + (remove-text-properties (1- (point)) (point) + '(line-prefix t wrap-prefix t))) + + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (let ((original-window-buffer (window-buffer (selected-window)))) + (set-window-buffer (selected-window) (current-buffer)) + ;; Defend against non-local exits from `ert-skip' + (unwind-protect + (funcall test) + (set-window-buffer (selected-window) original-window-buffer) + (when noninteractive + (kill-buffer))))))) + +(defun erc-fill-tests--wrap-check-nudge (expected-width) + (save-excursion + (goto-char (point-min)) + (should (search-forward "*** This server" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- ,n (,w)))) + (and (= n expected-width) + (= w (string-pixel-width "<alice> ")))) + (`(space :width (- ,n ,w)) + (and (= n expected-width) + (= w (length "<alice> ")))))) + + ;; Ensure the loop is not visited twice due to the gap. + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + `(space :width ,expected-width))) + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- ,n (,w)))) + (and (= n expected-width) + (= w (string-pixel-width "<bob> ")))) + (`(space :width (- ,n ,w)) + (and (= n expected-width) + (= w (length "<bob> ")))))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + (set-window-buffer (selected-window) (current-buffer)) + (erc-fill-tests--wrap-check-nudge 27) + + (ert-info ("Shift right by one") + (ert-with-message-capture messages + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET +")) + (should (string-match (rx "for further adjustment") messages))) + (erc-fill-tests--wrap-check-nudge 29)) + + (ert-info ("Shift left by five") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET -----")) + (erc-fill-tests--wrap-check-nudge 25)) + + (ert-info ("Reset") + (execute-kbd-macro (kbd "M-x erc-fill-wrap-nudge RET 0")) + (erc-fill-tests--wrap-check-nudge 27))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + (lambda () + (erc-fill-tests--wrap-check-nudge 27) + (erc-fill--wrap-nudge 2) + (erc-fill-tests--wrap-check-nudge 29) + (erc-fill--wrap-nudge -6) + (erc-fill-tests--wrap-check-nudge 25) + (erc-fill--wrap-nudge 0) + (erc-fill-tests--wrap-check-nudge 27) + + ;; FIXME get rid of this "void variable `erc--results-ewoc'" + ;; error, which seems related to operating in a non-default + ;; frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +;;; erc-fill-tests.el ends here -- 2.39.1 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 27 Jan 2023 14:32:01 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 27 09:32:00 2023 Received: from localhost ([127.0.0.1]:36967 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pLPlo-0004sj-QN for submit <at> debbugs.gnu.org; Fri, 27 Jan 2023 09:32:00 -0500 Received: from mail-108-mta2.mxroute.com ([136.175.108.2]:38473) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pLPln-0004sV-Dz for 60936 <at> debbugs.gnu.org; Fri, 27 Jan 2023 09:31:59 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta2.mxroute.com (ZoneMTA) with ESMTPSA id 185f3a45714000011e.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Fri, 27 Jan 2023 14:31:51 +0000 X-Zone-Loop: fef49ba55f7bf28a49544d5f0431fdc279d528aec5fa 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=bM/P+7qko0Si+d88sEKasRmybixdIwRhFQxVl/UaYZQ=; b=Hm8pAh7i1H63e1WFyO/8iOv0Zv PJfx0jn4eUSEuUif9720D9bomVxkVJjkBbkXblebrLfkP5IH4B5SU+7DEvhtd9AzjUPQ1aKQ+g6I8 E6+8r4riF4IYstGw8bEfYW50lnke/66IHTt8R8rgKzUMQqwHzEyNGOFb7rWMd4AEUJv8wqDMy9TfS hnuGtOU/pFeJa4R4vYh2n/bWZ0t64Auli3aVKnaYPN/mGJZMlghonpKmtr9lJr0I0cIc4Lm2VhD8J GqSMECwbEA3bqJvD/3OduD9P+fjIrSEg0JEXljqf10h/nQx5jMeJ9T3bXvUqvXXnKT8NCDqXYt+MY fzNPprPw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Fri, 27 Jan 2023 06:31:47 -0800 Message-ID: <87a6242gmk.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain v4. Fix invisibility for fools and timestamps with wrapped filling. Consolidate prompt setup in `erc-open'. Deprecate some items in erc-stamp. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v3-v4.diff From 8ff3d6905355e41bd91fd8e24577b68e762cfb0a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 06:28:37 -0800 Subject: [PATCH 0/8] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (8): [5.6] Refactor marker initialization in erc-open [5.6] Adjust some old text properties in ERC buffers [5.6] Expose insertion time as text prop in erc-stamp [5.6] Make some erc-stamp functions more limber [5.6] Put display properties to better use in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add variant for erc-match invisibility spec [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-common.el | 1 + lisp/erc/erc-fill.el | 307 ++++++++++++++++-- lisp/erc/erc-match.el | 31 +- lisp/erc/erc-stamp.el | 166 ++++++++-- lisp/erc/erc.el | 136 +++++--- test/lisp/erc/erc-fill-tests.el | 172 ++++++++++ .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 ------ test/lisp/erc/erc-stamp-tests.el | 261 +++++++++++++++ test/lisp/erc/erc-tests.el | 79 ++++- 10 files changed, 1248 insertions(+), 215 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el create mode 100644 test/lisp/erc/erc-stamp-tests.el Interdiff: diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index a05f2a558f8..ecd721f2f03 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -85,8 +85,8 @@ erc-fill-function function is called. A third style resembles static filling but \"wraps\" instead of -fills, courtesy of `visual-line-mode' mode, which ERC -automatically enables when this option is `erc-fill-wrap' or +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when `erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to your preferred initial \"prefix\" width. For adjusting the width during a session, see the command `erc-fill-wrap-nudge'." @@ -96,13 +96,15 @@ erc-fill-function function)) (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left. - -Also used by the `erc-fill-function' variant `erc-fill-wrap' for -its initial leading \"prefix\" width." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -171,65 +173,71 @@ erc-fill-variable (defvar-local erc-fill--wrap-prefix nil) (defvar-local erc-fill--wrap-value nil) -(defvar-local erc-fill--wrap-movement nil) +(defvar-local erc-fill--wrap-visual-keys nil) -(defcustom erc-fill-wrap-movement t - "Whether to override keys defined by `visual-line-mode'. -A value of `display' means to favor default `erc-mode' keys when -point is in the input area." +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." :package-version '(ERC . "5.5") ; FIXME sync on release - :type '(choice boolean (const display :tag "Display area" - :doc "Use `erc-mode' keys in input area"))) + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall + (pcase erc-fill--wrap-visual-keys + ('non-input (if (>= (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) (defun erc-fill--wrap-kill-line (arg) "Defer to `kill-line' or `kill-visual-line'." (interactive "P") - ;; ERC buffers are read-only outside of the input area, but users - ;; still need to see the message. - (pcase erc-fill--wrap-movement - ('display (if (>= (point) erc-input-marker) - (kill-line arg) - (kill-visual-line arg))) - ('t (kill-visual-line arg)) - (_ (kill-line arg)))) + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) (defun erc-fill--wrap-beginning-of-line (arg) "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." (interactive "^p") - (pcase erc-fill--wrap-movement - ('display (if (>= (point) erc-input-marker) - (move-beginning-of-line arg) - (beginning-of-visual-line arg))) - ('t (beginning-of-visual-line arg)) - (_ (move-beginning-of-line arg))) + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) (when (get-text-property (point) 'erc-prompt) (goto-char erc-input-marker))) (defun erc-fill--wrap-end-of-line (arg) - "defer to `move-end-of-line' or `end-of-visual-line'." + "Defer to `move-end-of-line' or `end-of-visual-line'." (interactive "^p") - (pcase erc-fill--wrap-movement - ('display (if (>= (point) erc-input-marker) - (move-end-of-line arg) - (end-of-visual-line arg))) - ('t (end-of-visual-line arg)) - (_ (move-end-of-line arg)))) + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) (defun erc-fill-wrap-cycle-visual-movement (arg) - "Cycle through `erc-fill-wrap-movement' styles ARG times. -Go from nil to t to `display' and back around, but set internal -state instead of mutating `erc-fill-wrap-movement'. When ARG is -0, reset to value of `erc-fill-wrap-movement'." + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." (interactive "^p") (when (zerop arg) - (setq erc-fill--wrap-movement erc-fill-wrap-movement)) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) (while (not (zerop arg)) (cl-incf arg (- (abs arg))) - (setq erc-fill--wrap-movement (pcase erc-fill--wrap-movement - ('nil t) - ('t 'display) - ('display nil)))) - (message "erc-fill-wrap-movement: %S" erc-fill--wrap-movement)) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) (defvar-keymap erc-fill-wrap-mode-map ; Compat 29 :doc "Keymap for ERC's `fill-wrap' module." @@ -237,16 +245,22 @@ erc-fill-wrap-mode-map "<remap> <kill-line>" #'erc-fill--wrap-kill-line "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line - "C-c c" #'erc-fill-wrap-cycle-visual-movement + "C-c a" #'erc-fill-wrap-cycle-visual-movement ;; Not sure if this is problematic because `erc-bol' takes no args. "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + (define-erc-module fill-wrap nil "Fill style leveraging `visual-line-mode'. This local module depends on the global `fill' module. To use it, either include `fill-wrap' in `erc-modules' or set `erc-fill-function' to `erc-fill-wrap'. You can also manually -invoke one of the minor-mode toggles." +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." ((let (msg) (unless erc-fill-mode (unless (memq 'fill erc-modules) @@ -261,11 +275,15 @@ fill-wrap (setq-local erc-fill-function #'erc-fill-wrap)) (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) ((alist-get 'erc-fill-wrap-mode vars))) - (setq erc-fill--wrap-movement (alist-get 'erc-fill--wrap-movement vars) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-keys + vars) erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) - (when (eq erc-timestamp-use-align-to 'margin) - (erc-timestamp--display-margin-mode +1)) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value (or erc-fill--wrap-value erc-fill-static-center) ;; @@ -273,29 +291,30 @@ fill-wrap (or erc-fill--wrap-prefix (list 'space :width erc-fill--wrap-value))) (visual-line-mode +1) - (unless (local-variable-p 'erc-fill--wrap-movement) - (setq erc-fill--wrap-movement erc-fill-wrap-movement)) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) (when msg (erc-display-error-notice nil msg)))) - ((when erc-timestamp--display-margin-mode - (erc-timestamp--display-margin-mode -1)) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) (kill-local-variable 'erc-button--add-nickname-face-function) (kill-local-variable 'erc-fill--wrap-prefix) (kill-local-variable 'erc-fill--wrap-value) (kill-local-variable 'erc-fill-function) - (kill-local-variable 'erc-fill--wrap-movement) + (kill-local-variable 'erc-fill--wrap-visual-keys) (visual-line-mode -1)) 'local) (defvar-local erc-fill--wrap-length-function nil - "Function to determine length of perceived nickname. -It should return an integer representing the length of the -nickname, including any enclosing brackets, or nil, to fall back -to the default behavior of taking the length from the first word.") - -(defvar erc-fill--wrap-use-pixels t) -(declare-function buffer-text-pixel-size "xdisp" - (&optional buffer-or-name window x-limit y-limit)) + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") (defun erc-fill-wrap () "Use text props to mimic the effect of `erc-fill-static'. @@ -309,12 +328,13 @@ erc-fill-wrap (progn (skip-syntax-forward "^-") (forward-char) - (if (and erc-fill--wrap-use-pixels + (if (and erc-fill-wrap-use-pixels (fboundp 'buffer-text-pixel-size)) (save-restriction (narrow-to-region (point-min) (point)) (list (car (buffer-text-pixel-size)))) (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. (erc-put-text-properties (point-min) (point-max) '(line-prefix wrap-prefix) nil `((space :width (- ,erc-fill--wrap-value ,len)) @@ -337,7 +357,7 @@ erc-fill--wrap-fix (while (and (zerop (forward-line)) (< (point) (min (point-max) erc-insert-marker))) (save-restriction - (narrow-to-region (pos-bol) (pos-eol)) + (narrow-to-region (line-beginning-position) (line-end-position)) (erc-fill-wrap)))))) (defun erc-fill--wrap-nudge (arg) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 499bcaf5724..87272f0b647 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -649,13 +652,22 @@ erc-go-to-log-matches-buffer (define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) + (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +675,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index e9592448a33..21885f3a36f 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,29 +165,43 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (unless (get-text-property (point-min) 'invisible) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -232,29 +254,53 @@ erc-timestamp-use-align-to A side effect of enabling this is that there will only be one space before a right timestamp in any saved logs." :type '(choice boolean integer (const margin)) - :package-version '(ERC . "5.4.1")) ; FIXME update when merging - -;; If people want to use this directly, we can offer an option to set -;; the margin's width. -(define-minor-mode erc-timestamp--display-margin-mode - "Internal minor mode for built-in modules integrating with `stamp'." + :package-version '(ERC . "5.5")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." :interactive nil - (if-let ((erc-timestamp--display-margin-mode) - (width (if erc-timestamp-last-inserted-right - (length erc-timestamp-last-inserted-right) - (1+ (length (erc-format-timestamp - (current-time) - erc-timestamp-format-right)))))) - (progn + (if erc-stamp--display-margin-mode + (let ((width (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))))) (setq right-margin-width width right-fringe-width 0) - (unless noninteractive - (set-window-margins nil left-margin-width width) - (set-window-fringes nil left-fringe-width 0))) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) (kill-local-variable 'right-margin-width) - (unless noninteractive - (set-window-margins nil nil) - (set-window-fringes nil nil)))) + (kill-local-variable 'right-fringe-width) + (set-window-margins left-margin-width nil) + (set-window-fringes left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -365,14 +411,19 @@ erc-insert-timestamp-right (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) @@ -400,8 +451,9 @@ erc-format-timestamp ;; N.B. Later use categories instead of this harmless, but ;; inelegant, hack. -- BPT (and erc-timestamp-intangible - (not erc-hide-timestamps) ; bug#11706 - (erc-put-text-property 0 (length ts) 'cursor-intangible t ts)) + ;; (not erc-hide-timestamps) ; bug#11706 + (erc-put-text-property 0 (1- (length ts)) + 'cursor-intangible t ts)) ts) "")) @@ -450,11 +502,15 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 4bc9fc20f8a..6b3d0b4af2f 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1966,6 +1966,45 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Respect existing multiline input after prompt. Expect any + ;; text preceding it on the same line, including whitespace, + ;; to be part of the prompt itself. + (goto-char (point-max)) + (forward-line 0) + (while (and (not (get-text-property (point) 'erc-prompt)) + (zerop (forward-line -1)))) + (cl-assert (not (= (point) (point-min)))) + (set-marker erc-insert-marker (point)) + ;; If the input area is clean, this search should fail and + ;; return point max. Otherwise, it should return the position + ;; after the last char with the `erc-prompt' property, as per + ;; the doc string for `next-single-property-change'. + (set-marker erc-input-marker + (next-single-property-change (point) 'erc-prompt nil + (point-max))) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -1999,10 +2038,12 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2020,21 +2061,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2081,20 +2107,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) @@ -2867,6 +2880,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) + (put-text-property + 0 (length string) 'erc-message + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4244,6 +4260,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -5667,7 +5707,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5677,14 +5717,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7278,10 +7313,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7301,6 +7337,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el index cf243ef43c7..77d553bc3a2 100644 --- a/test/lisp/erc/erc-fill-tests.el +++ b/test/lisp/erc/erc-fill-tests.el @@ -36,6 +36,7 @@ erc-fill-tests--wrap-populate (push 'erc-button-add-buttons erc-insert-modify-hook)) (erc-mode) (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) (with-current-buffer (get-buffer-create "#chan") (erc-mode) @@ -63,13 +64,13 @@ erc-fill-tests--wrap-populate (erc-display-message nil nil (current-buffer) - (erc--format-privmsg "alice" msg nil t nil)) + (erc-format-privmessage "alice" msg nil t)) (setq msg "alice: Either your unparagoned mistress is dead,\ or she's outprized by a trifle.") (erc-display-message nil nil (current-buffer) - (erc--format-privmsg "bob" msg nil t nil)) + (erc-format-privmessage "bob" msg nil t)) (funcall test) (when noninteractive @@ -92,9 +93,15 @@ erc-fill-wrap--monospace '(space :width 27))) (should (equal (get-text-property (pos-eol) 'wrap-prefix) '(space :width 27))) + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). (should (pcase (get-text-property (point) 'line-prefix) - (`(space :width (- 27 (,w))) - (should (= w (string-pixel-width "<alice> ")))))) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- 27 (,w)))) + (= w (string-pixel-width "<alice> "))) + (`(space :width (- 27 ,w)) + (= w (length "<alice> "))))) (erc-fill--wrap-nudge 2) @@ -106,12 +113,17 @@ erc-fill-wrap--monospace (should (equal (get-text-property (pos-eol) 'wrap-prefix) '(space :width 29))) (should (pcase (get-text-property (point) 'line-prefix) - (`(space :width (- 29 (,w))) - (should (= w (string-pixel-width "<bob> "))))))))) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- 29 (,w)))) + (= w (string-pixel-width "<bob> "))) + (`(space :width (- 29 ,w)) + (= w (length "<bob> ")))))))) (ert-deftest erc-fill-wrap--variable-pitch () :tags '(:unstable) - (unless (and (not noninteractive) (display-graphic-p)) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) (ert-skip "Test needs interactive graphical Emacs")) (with-selected-frame (make-frame '((name . "other"))) @@ -124,8 +136,6 @@ erc-fill-wrap--variable-pitch (lambda () - ;; Prefix props are applied properly and faces are accounted - ;; for when determining widths. (goto-char (point-min)) (should (search-forward "<a" nil t)) (should (get-text-property (pos-bol) 'line-prefix)) @@ -136,7 +146,7 @@ erc-fill-wrap--variable-pitch '(space :width 27))) (should (pcase (get-text-property (point) 'line-prefix) (`(space :width (- 27 (,w))) - (should (> w (string-pixel-width "<alice> ")))))) + (> w (string-pixel-width "<alice> "))))) (erc-fill--wrap-nudge 2) @@ -149,7 +159,7 @@ erc-fill-wrap--variable-pitch '(space :width 29))) (should (pcase (get-text-property (point) 'line-prefix) (`(space :width (- 29 (,w))) - (should (> w (string-pixel-width "<bob> ")))))) + (> w (string-pixel-width "<bob> "))))) ;; FIXME figure out how to get rid of this "void variable ;; `erc--results-ewoc'" error, which seems related to operating diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 916d105779a..990c971b4cd 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -81,105 +81,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 4994feefd4e..69523274812 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -20,7 +20,7 @@ ;;; Commentary: ;;; Code: -(require 'ert) +(require 'ert-x) (require 'erc-stamp) (require 'erc-goodies) ; for `erc-make-read-only' @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,9 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) (ert-deftest erc-timestamp-use-align-to--integer () @@ -146,7 +146,7 @@ erc-timestamp-use-align-to--integer (ert-deftest erc-timestamp-use-align-to--margin () (erc-stamp-tests--insert-right (lambda () - (erc-timestamp--display-margin-mode +1) + (erc-stamp--display-margin-mode +1) (ert-info ("margin, normal") (let ((erc-timestamp-use-align-to 'margin)) @@ -155,7 +155,7 @@ erc-timestamp-use-align-to--margin (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Space not added (treated as opaque string). - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one[" nil t)) ;; Field covers stamp alone (should (eql ?e (char-before (field-beginning (point))))) ;; Vanity props extended @@ -170,9 +170,92 @@ erc-timestamp-use-align-to--margin (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; No hard wrap - (should (search-forward "oooo [" nil t)) + (should (search-forward "oooo[" nil t)) ;; Field starts at leading space. - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) +;; This concerns the partial reversal of changes resulting from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also irreversible, which at least one user has complained +;; about. Turning off `cursor-intangible-mode' does do the trick, but +;; a better solution seems to be decrementing the end of the +;; `cursor-intangible' interval so that, in addition to C-n working, a +;; C-f from before the timestamp doesn't overshoot. This works +;; whether `erc-hide-timestamps' is enabled or not. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + ;;; erc-stamp-tests.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..c5a40d9bc72 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Refactor-marker-initialization-in-erc-open.patch From 4ab7539fa3f6b44e645b004438c6256feee3a5b2 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Mon, 23 Jan 2023 20:48:24 -0800 Subject: [PATCH 1/8] [5.6] Refactor marker initialization in erc-open * lisp/erc/erc.el (erc--initialize-markers): New helper to ensure prompt and its associated markers are set up correctly. (erc-open): When determining whether a session is a logical continuation, leverage the work already performed by the `erc-networks' library to that effect. Its verdicts are based on network context and thus reliable even when a user dials anew from an entry-point, which is not a simple reconnection because the user expects a clean slate for everything except an existing buffer's messages, meaning `erc--server-reconnecting' will be nil and local-module state variables need resetting. Also remove the check for `erc-reuse-buffers' and instead trust that `erc-get-buffer-create' always does the right thing in. Replace all code involving marker and prompt setup by deferring to a new helper, `erc--initialize markers'. * test/lisp/erc/erc-tests.el (erc--initialize-markers): New test. * test/lisp/erc/erc-scenarios-base-local-module-modes.el: New file. * test/lisp/erc/erc-scenarios-base-local-modules.el (erc-scenarios-base-local-modules--mode-persistence): Move test to separate file to help with parallel "-j" runs. --- lisp/erc/erc.el | 79 ++++--- .../erc-scenarios-base-local-module-modes.el | 211 ++++++++++++++++++ .../erc/erc-scenarios-base-local-modules.el | 99 -------- test/lisp/erc/erc-tests.el | 79 ++++++- 4 files changed, 331 insertions(+), 137 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-local-module-modes.el diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ff1820cfaf2..363fe30ee58 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1966,6 +1966,45 @@ erc--merge-local-modes (cons (nreverse (car out)) (nreverse (cdr out)))) (list new-modes))) +;; This function doubles as a convenient helper for use in unit tests. +;; Prior to 5.6, its contents lived in `erc-open'. + +(defun erc--initialize-markers (old-point continued-session) + "Ensure prompt and its bounding markers have been initialized." + ;; FIXME erase assertions after code review and additional testing. + (setq erc-insert-marker (make-marker) + erc-input-marker (make-marker)) + (if continued-session + (progn + ;; Respect existing multiline input after prompt. Expect any + ;; text preceding it on the same line, including whitespace, + ;; to be part of the prompt itself. + (goto-char (point-max)) + (forward-line 0) + (while (and (not (get-text-property (point) 'erc-prompt)) + (zerop (forward-line -1)))) + (cl-assert (not (= (point) (point-min)))) + (set-marker erc-insert-marker (point)) + ;; If the input area is clean, this search should fail and + ;; return point max. Otherwise, it should return the position + ;; after the last char with the `erc-prompt' property, as per + ;; the doc string for `next-single-property-change'. + (set-marker erc-input-marker + (next-single-property-change (point) 'erc-prompt nil + (point-max))) + (cl-assert (= (field-end) erc-input-marker)) + (goto-char old-point) + (erc--unhide-prompt)) + (cl-assert (not (get-text-property (point) 'erc-prompt))) + ;; In the original version from `erc-open', the snippet that + ;; handled these newline insertions appeared twice close in + ;; proximity, which was probably unintended. Nevertheless, we + ;; preserve the double newlines here for historical reasons. + (insert "\n\n") + (set-marker erc-insert-marker (point)) + (erc-display-prompt) + (cl-assert (= (point) (point-max))))) + (defun erc-open (&optional server port nick full-name connect passwd tgt-list channel process client-certificate user id) @@ -1999,10 +2038,12 @@ erc-open (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) - (continued-session (and erc--server-reconnecting - (with-suppressed-warnings - ((obsolete erc-reuse-buffers)) - erc-reuse-buffers)))) + (continued-session (or erc--server-reconnecting + erc--target-priors + (and-let* (((not target)) + (m (buffer-local-value + 'erc-input-marker buffer)) + ((marker-position m))))))) (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) @@ -2020,21 +2061,6 @@ erc-open (buffer-local-value 'erc-server-announced-name old-buffer))) ;; connection parameters (setq erc-server-process process) - (setq erc-insert-marker (make-marker)) - (setq erc-input-marker (make-marker)) - ;; go to the end of the buffer and open a new line - ;; (the buffer may have existed) - (goto-char (point-max)) - (forward-line 0) - (when (or continued-session (get-text-property (point) 'erc-prompt)) - (setq continued-session t) - (set-marker erc-input-marker - (or (next-single-property-change (point) 'erc-prompt) - (point-max)))) - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (set-marker erc-insert-marker (point)) ;; stack of default recipients (setq erc-default-recipients tgt-list) (when target @@ -2081,20 +2107,7 @@ erc-open (get-buffer-create (concat "*ERC-DEBUG: " server "*")))) (erc-determine-parameters server port nick full-name user passwd) - - ;; FIXME consolidate this prompt-setup logic with the pass above. - - ;; set up prompt - (unless continued-session - (goto-char (point-max)) - (insert "\n")) - (if continued-session - (progn (goto-char old-point) - (erc--unhide-prompt)) - (set-marker erc-insert-marker (point)) - (erc-display-prompt) - (goto-char (point-max))) - + (erc--initialize-markers old-point continued-session) (save-excursion (run-mode-hooks) (dolist (mod (car delayed-modules)) (funcall mod +1)) (dolist (var (cdr delayed-modules)) (set var nil))) diff --git a/test/lisp/erc/erc-scenarios-base-local-module-modes.el b/test/lisp/erc/erc-scenarios-base-local-module-modes.el new file mode 100644 index 00000000000..7b91e28dc83 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-local-module-modes.el @@ -0,0 +1,211 @@ +;;; erc-scenarios-base-local-module-modes.el --- More local-mod ERC tests -*- 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/>. + +;;; Commentary: + +;; A local module doubles as a minor mode whose mode variable and +;; associated local data can withstand service disruptions. +;; Unfortunately, the current implementation is too unwieldy to be +;; made public because it doesn't perform any of the boiler plate +;; needed to save and restore buffer-local and "network-local" copies +;; of user options. Ultimately, a user-friendly framework must fill +;; this void if third-party local modules are ever to become +;; practical. +;; +;; The following tests all use `sasl' because, as of ERC 5.5, it's the +;; only local module. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(require 'erc-sasl) + +;; After quitting a session for which `sasl' is enabled, you +;; disconnect and toggle `erc-sasl-mode' off. You then reconnect +;; using an alternate nickname. You again disconnect and reconnect, +;; this time immediately, and the mode stays disabled. Finally, you +;; once again disconnect, toggle the mode back on, and reconnect. You +;; are authenticated successfully, just like in the initial session. +;; +;; This is meant to show that a user's local mode settings persist +;; between sessions. It also happens to show (in round four, below) +;; that a server renicking a user on 001 after a 903 is handled just +;; like a user-initiated renick, although this is not the main thrust. + +(ert-deftest erc-scenarios-base-local-module-modes--reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round two, nick rejected, alternate granted") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode off, reconnect") + (erc-sasl-mode -1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Some enigma, some riddle")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round three, send alternate nick initially") + (with-current-buffer "foonet" + + (ert-info ("Keep mode off, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester`") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Let our reciprocal vows be remembered.")) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished"))) + + (ert-info ("Round four, authenticated successfully again") + (with-current-buffer "foonet" + + (ert-info ("Toggle mode on, reconnect") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-sasl-mode +1) + (erc-cmd-RECONNECT)) + + (funcall expect 10 "User modes for tester") + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + (should (equal (buffer-name) "foonet")) + (should-not (cdr (erc-scenarios-common-buflist "#chan"))) + + (with-current-buffer "#chan" + (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) + + (erc-cmd-QUIT ""))))) + +;; In contrast to the mode-persistence test above, this one +;; demonstrates that a user reinvoking an entry point declares their +;; intention to reset local-module state for the server buffer. +;; Whether a local-module's state variable is also reset in target +;; buffers up to the module. That is, by default, they're left alone. + +(ert-deftest erc-scenarios-base-local-module-modes--entrypoint () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/local-modules") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'first 'first)) + (port (process-contact dumb-server :service)) + (erc-modules (cons 'sasl erc-modules)) + (expect (erc-d-t-make-expecter)) + (server-buffer-name (format "127.0.0.1:%d" port))) + + (ert-info ("Round one, initial authentication succeeds as expected") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester")) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (funcall expect 10 "This server is in debug mode") + (erc-cmd-JOIN "#chan") + + (ert-info ("Toggle local-module off in target buffer") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (erc-sasl-mode -1))) + + (erc-cmd-QUIT "") + (funcall expect 10 "finished") + + (ert-info ("Toggle mode off") + (erc-sasl-mode -1) + (should (local-variable-p 'erc-sasl-mode))))) + + (ert-info ("Reconnecting via entry point discards `erc-sasl-mode' value.") + ;; If you were to /RECONNECT here, no PASS changeme would be + ;; sent instead of CAP SASL, resulting in a failure. + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :password "changeme" + :full-name "tester") + (should (string= (buffer-name) server-buffer-name)) + (funcall expect 10 "You are now logged in as tester") + + (erc-d-t-wait-for 10 (equal (buffer-name) "foonet")) + (funcall expect 10 "User modes for tester") + (should erc-sasl-mode)) ; obviously + + ;; No other foonet buffer exists, e.g., foonet<2> + (should-not (cdr (erc-scenarios-common-buflist "foonet"))) + + (ert-info ("Target buffer retains local-module state") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 20 "She is Lavinia, therefore must") + (should-not erc-sasl-mode) + (should (local-variable-p 'erc-sasl-mode)) + (erc-cmd-QUIT "")))))) + +;;; erc-scenarios-base-local-module-modes.el ends here diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el index 916d105779a..990c971b4cd 100644 --- a/test/lisp/erc/erc-scenarios-base-local-modules.el +++ b/test/lisp/erc/erc-scenarios-base-local-modules.el @@ -81,105 +81,6 @@ erc-scenarios-base-local-modules--reconnect-let (erc-cmd-QUIT "") (funcall expect 10 "finished"))))) -;; After quitting a session for which `sasl' is enabled, you -;; disconnect and toggle `erc-sasl-mode' off. You then reconnect -;; using an alternate nickname. You again disconnect and reconnect, -;; this time immediately, and the mode stays disabled. Finally, you -;; once again disconnect, toggle the mode back on, and reconnect. You -;; are authenticated successfully, just like in the initial session. -;; -;; This is meant to show that a user's local mode settings persist -;; between sessions. It also happens to show (in round four, below) -;; that a server renicking a user on 001 after a 903 is handled just -;; like a user-initiated renick, although this is not the main thrust. - -(ert-deftest erc-scenarios-base-local-modules--mode-persistence () - :tags '(:expensive-test) - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/local-modules") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'first 'second 'third 'fourth)) - (port (process-contact dumb-server :service)) - (erc-modules (cons 'sasl erc-modules)) - (expect (erc-d-t-make-expecter)) - (server-buffer-name (format "127.0.0.1:%d" port))) - - (ert-info ("Round one, initial authentication succeeds as expected") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :user "tester" - :password "changeme" - :full-name "tester") - (should (string= (buffer-name) server-buffer-name)) - (funcall expect 10 "You are now logged in as tester")) - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) - (funcall expect 10 "This server is in debug mode") - (erc-cmd-JOIN "#chan") - - (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) - (funcall expect 20 "She is Lavinia, therefore must")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round two, nick rejected, alternate granted") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode off, reconnect") - (erc-sasl-mode -1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Some enigma, some riddle")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round three, send alternate nick initially") - (with-current-buffer "foonet" - - (ert-info ("Keep mode off, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester`") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Let our reciprocal vows be remembered.")) - - (erc-cmd-QUIT "") - (funcall expect 10 "finished"))) - - (ert-info ("Round four, authenticated successfully again") - (with-current-buffer "foonet" - - (ert-info ("Toggle mode on, reconnect") - (should-not erc-sasl-mode) - (should (local-variable-p 'erc-sasl-mode)) - (erc-sasl-mode +1) - (erc-cmd-RECONNECT)) - - (funcall expect 10 "User modes for tester") - (should-not (cdr (erc-scenarios-common-buflist "foonet"))) - (should (equal (buffer-name) "foonet")) - (should-not (cdr (erc-scenarios-common-buflist "#chan"))) - - (with-current-buffer "#chan" - (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")) - - (erc-cmd-QUIT ""))))) - ;; For local modules, the twin toggle commands `erc-FOO-enable' and ;; `erc-FOO-disable' affect all buffers of a connection, whereas ;; `erc-FOO-mode' continues to operate only on the current buffer. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..c5a40d9bc72 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -117,11 +117,7 @@ erc-tests--send-prep ;; Caller should probably shadow `erc-insert-modify-hook' or ;; populate user tables for erc-button. (erc-mode) - (insert "\n\n") - (setq erc-input-marker (make-marker) - erc-insert-marker (make-marker)) - (set-marker erc-insert-marker (point-max)) - (erc-display-prompt) + (erc--initialize-markers (point) nil) (should (= (point) erc-input-marker))) (defun erc-tests--set-fake-server-process (&rest args) @@ -257,6 +253,79 @@ erc-hide-prompt (kill-buffer "bob") (kill-buffer "ServNet")))) +(ert-deftest erc--initialize-markers () + (let ((proc (start-process "true" (current-buffer) "true")) + erc-modules + erc-connect-pre-hook + erc-insert-modify-hook + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (set-process-query-on-exit-flag proc nil) + (erc-mode) + (setq erc-server-process proc + erc-networks--id (erc-networks--id-create 'foonet)) + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 3 (marker-position erc-insert-marker))) + (should (= 8 (marker-position erc-input-marker))) + (should (= 8 (point-max))) + (should (= 8 (point))) + ;; These prompt properties are a continual source of confusion. + ;; Including the literal defaults here can hopefully serve as a + ;; quick reference for anyone operating in that area. + (should (equal (buffer-string) + #("\n\nERC> " + 2 6 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 6 7 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + + ;; Simulate some activity by inserting some text before and + ;; after the prompt (multiline). + (erc-display-error-notice nil "Welcome") + (goto-char (point-max)) + (insert "Hello\nWorld") + (goto-char 3) + (should (looking-at-p (regexp-quote "*** Welcome")))) + + (ert-info ("Reconnect") + (erc-open "localhost" 6667 "tester" "Tester" nil + "fake" nil "#chan" proc nil "user" nil) + (should-not (get-buffer "#chan<2>"))) + + (ert-info ("Existing prompt respected") + (with-current-buffer (should (get-buffer "#chan")) + (should (= ?\n (char-after 1))) + (should (= ?E (char-after erc-insert-marker))) + (should (= 15 (marker-position erc-insert-marker))) + (should (= 20 (marker-position erc-input-marker))) + (should (= 3 (point))) ; point restored + (should (equal (buffer-string) + #("\n\n*** Welcome\nERC> Hello\nWorld" + 2 13 (font-lock-face erc-error-face) + 14 18 ( font-lock-face erc-prompt-face + rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t) + 18 19 ( rear-nonsticky t + erc-prompt t + field erc-prompt + front-sticky t + read-only t)))) + (when noninteractive + (kill-buffer)))))) + (ert-deftest erc--switch-to-buffer () (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From 456f765ec19ecb7421093a887bdb22afac5ec631 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 2/8] [5.6] Adjust some old text properties in ERC buffers TODO: mention adjustment in ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Replace `rear-sticky' text property, which has been around since 2002, with more useful `erc-message' property. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. (erc-put-text-property, erc-list): Alias these to built-in functions. (erc--own-property-names, erc--remove-text-properties) Add internal variable and helper function for filtering values returned by `filter-buffer-substring-function'. (erc-restore-text-properties): Don't forget tags when restoring. (erc--get-eq-comparable-cmd): New function to extract commands for use as easily searchable text-property values. --- lisp/erc/erc.el | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 363fe30ee58..6b3d0b4af2f 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2880,7 +2880,9 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) + (put-text-property + 0 (length string) 'erc-message + (erc--get-eq-comparable-cmd (erc-response.command parsed)) string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4258,6 +4260,30 @@ erc-ensure-channel-name channel (concat "#" channel))) +(defvar erc--own-property-names + '( tags erc-parsed display ; core + ;; `erc-display-prompt' + rear-nonsticky erc-prompt field front-sticky read-only + ;; stamp + cursor-intangible cursor-sensor-functions isearch-open-invisible + ;; match + invisible intangible + ;; button + erc-callback erc-data mouse-face keymap + ;; fill-wrap + line-prefix wrap-prefix) + "Props added by ERC that should not survive killing. +Among those left behind by default are `font-lock-face' and +`erc-secret'.") + +(defun erc--remove-text-properties (string) + "Remove text properties in STRING added by ERC. +Specifically, remove any that aren't members of +`erc--own-property-names'." + (remove-list-of-text-properties 0 (length string) + erc--own-property-names string) + string) + (defun erc-grab-region (start end) "Copy the region between START and END in a recreatable format. @@ -4309,7 +4335,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) @@ -5681,7 +5707,7 @@ erc-highlight-error (erc-put-text-property 0 (length s) 'font-lock-face 'erc-error-face s) s) -(defun erc-put-text-property (start end property value &optional object) +(defalias 'erc-put-text-property 'put-text-property "Set text-property for an object (usually a string). START and END define the characters covered. PROPERTY is the text-property set, usually the symbol `face'. @@ -5691,14 +5717,9 @@ erc-put-text-property OBJECT is modified without being copied first. You can redefine or `defadvice' this function in order to add -EmacsSpeak support." - (put-text-property start end property value object)) +EmacsSpeak support.") -(defun erc-list (thing) - "Return THING if THING is a list, or a list with THING as its element." - (if (listp thing) - thing - (list thing))) +(defalias 'erc-list 'ensure-list) (defun erc-parse-user (string) "Parse STRING as a user specification (nick!login@host). @@ -7292,10 +7313,11 @@ erc-find-parsed-property (defun erc-restore-text-properties () "Restore the property `erc-parsed' for the region." - (let ((parsed-posn (erc-find-parsed-property))) - (put-text-property - (point-min) (point-max) - 'erc-parsed (when parsed-posn (erc-get-parsed-vector parsed-posn))))) + (when-let* ((parsed-posn (erc-find-parsed-property)) + (found (erc-get-parsed-vector parsed-posn))) + (put-text-property (point-min) (point-max) 'erc-parsed found) + (when-let ((tags (get-text-property parsed-posn 'tags))) + (put-text-property (point-min) (point-max) 'tags tags)))) (defun erc-get-parsed-vector (point) "Return the whole parsed vector on POINT." @@ -7315,6 +7337,13 @@ erc-get-parsed-vector-type (and vect (erc-response.command vect))) +(defun erc--get-eq-comparable-cmd (command) + "Return a symbol or a fixnum representing a message's COMMAND. +See also `erc-message-type'." + ;; IRC numerics are three-digit numbers, possibly with leading 0s. + ;; To invert: (if (numberp o) (format "%03d" o) (symbol-name o)) + (if-let* ((n (string-to-number command)) ((zerop n))) (intern command) n)) + ;; Teach url.el how to open irc:// URLs with ERC. ;; To activate, customize `url-irc-function' to `url-irc-erc'. -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Expose-insertion-time-as-text-prop-in-erc-stamp.patch From 9172c82d0e896d4129dd0c83624d282045c52c21 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 03:10:20 -0800 Subject: [PATCH 3/8] [5.6] Expose insertion time as text prop in erc-stamp * lisp/erc/erc-stamp.el (erc-add-timestamp): Add new text property `erc-timestamp' to store lisp time object formerly ensconced in a closure. Instead of creating a new lambda for the cursor-sensor function of each message in a buffer, leave a gap between messages to trip the sensor function. The motivation behind this change is to allow third parties access to valuable timestamp data already stored by ERC anyway. Of secondary importance is discouraging the reliance on those lambdas as a means of detecting message bounds. The gap now serves a similar purpose. Basically, the final character in a message, a newline, will not have a timestamp or a sensor function. When the stamps module isn't loaded, the `erc-message' property can be used instead. Also, instead of looking for the `invisible' text property at point, which is normally `point-max' and thus outside the accessible portion of the buffer, look at the beginning of the inserted message. This allows hook members running before this function to opt out of timestamps by marking a message as invisible. (erc-format-timestamp): Don't omit the `cursor-intangible' property when `erc-hide-timestamps' is non-nil. This reverts the changes from bug#11706. (erc-echo-timestamp): Make interactive and show timestamps even when the variable `erc-echo-timestamps' is nil. (erc--echo-ts-csf): Add new function to serve as value of cursor-sensor function text properties. * test/lisp/erc/erc-stamp-tests.el: New file. --- lisp/erc/erc-stamp.el | 19 +-- test/lisp/erc/erc-stamp-tests.el | 203 +++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+), 7 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..bf1b0c6952c 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -162,7 +162,7 @@ erc-add-timestamp This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." - (unless (get-text-property (point) 'invisible) + (unless (get-text-property (point-min) 'invisible) (let ((ct (current-time))) (if (fboundp erc-insert-timestamp-function) (funcall erc-insert-timestamp-function @@ -174,12 +174,12 @@ erc-add-timestamp (not erc-timestamp-format)) (funcall erc-insert-away-timestamp-function (erc-format-timestamp ct erc-away-timestamp-format))) - (add-text-properties (point-min) (point-max) + (add-text-properties (point-min) (1- (point-max)) ;; It's important for the function to ;; be different on different entries (bug#22700). (list 'cursor-sensor-functions - (list (lambda (_window _before dir) - (erc-echo-timestamp dir ct)))))))) + ;; Regions are no longer contiguous ^ + '(erc--echo-ts-csf) 'erc-timestamp ct))))) (defvar-local erc-timestamp-last-window-width nil "The width of the last window that showed the current buffer. @@ -350,8 +350,9 @@ erc-format-timestamp ;; N.B. Later use categories instead of this harmless, but ;; inelegant, hack. -- BPT (and erc-timestamp-intangible - (not erc-hide-timestamps) ; bug#11706 - (erc-put-text-property 0 (length ts) 'cursor-intangible t ts)) + ;; (not erc-hide-timestamps) ; bug#11706 + (erc-put-text-property 0 (1- (length ts)) + 'cursor-intangible t ts)) ts) "")) @@ -400,11 +401,15 @@ erc-toggle-timestamps (defun erc-echo-timestamp (dir stamp) "Print timestamp text-property of an IRC message." - (when (and erc-echo-timestamps (eq 'entered dir)) + (interactive (list 'entered (get-text-property (point) 'erc-timestamp))) + (when (eq 'entered dir) (when stamp (message "%s" (format-time-string erc-echo-timestamp-format stamp))))) +(defun erc--echo-ts-csf (_window _before dir) + (erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..c8e5d75d77d --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,203 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\s (char-after (field-beginning (point))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;; This concerns the partial reversal of changes resulting from: +;; +;; 24.1.50; Wrong behavior of move-end-of-line in ERC (Bug#11706) +;; +;; Perhaps core behavior has changed since this bug was reported, but +;; C-e stopping one char short of EOL no longer seems a problem. +;; However, invoking C-n (`next-line') exhibits a similar effect. +;; When point is in a stamp or near the beginning of a line, issuing a +;; C-n puts point one past the start of the message (i.e., two chars +;; beyond the timestamp's closing "]". Dropping the invisible +;; property when timestamps are hidden does indeed prevent this, but +;; it's also irreversible, which at least one user has complained +;; about. Turning off `cursor-intangible-mode' does do the trick, but +;; a better solution seems to be decrementing the end of the +;; `cursor-intangible' interval so that, in addition to C-n working, a +;; C-f from before the timestamp doesn't overshoot. This works +;; whether `erc-hide-timestamps' is enabled or not. +;; +;; Note some striking omissions here: +;; +;; 1. a lack of `fill' module integration (we simulate it by +;; making lines short enough to not wrap) +;; 2. functions like `line-move' behave differently when +;; `noninteractive' +;; 3. no actual test assertions involving `cursor-sensor' movement +;; even though that's a huge ingredient + +(ert-deftest erc-timestamp-intangible--left () + (let ((erc-timestamp-only-if-changed-flag nil) + (erc-timestamp-intangible t) ; default changed to nil in 2014 + (erc-hide-timestamps t) + (erc-insert-timestamp-function 'erc-insert-timestamp-left) + (erc-server-process (start-process "true" (current-buffer) "true")) + (erc-insert-modify-hook '(erc-make-read-only erc-add-timestamp)) + msg + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (should (not cursor-sensor-inhibit)) + (set-process-query-on-exit-flag erc-server-process nil) + (erc-mode) + (with-current-buffer (get-buffer-create "*erc-timestamp-intangible*") + (erc-mode) + (erc--initialize-markers (point) nil) + (erc-munge-invisibility-spec) + (erc-display-message nil 'notice (current-buffer) "Welcome") + ;; + ;; Pretend `fill' is active and that these lines are + ;; folded. Otherwise, there's an annoying issue on wrapped lines + ;; (when visual-line-mode is off and stamps are visible) where + ;; C-e sends you to the end of the previous line. + (setq msg "Lorem ipsum dolor sit amet") + (erc-display-message nil nil (current-buffer) + (erc-format-privmessage "alyssa" msg nil t)) + (erc-display-message nil 'notice (current-buffer) "Home") + (goto-char (point-min)) + + ;; EOL is actually EOL (Bug#11706) + + (ert-info ("Notice before stamp, C-e") ; first line/stamp + (should (search-forward "Welcome" nil t)) + (ert-simulate-command '(erc-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) ; `line-end-position' fails because fields + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg before stamp, C-e") + (should (search-forward "Lorem" nil t)) + (goto-char (pos-bol)) + (should (looking-at (rx "["))) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (ert-info ("Privmsg first line, C-e") + (goto-char (pos-bol)) + (should (search-forward "ipsum" nil t)) + (let ((end (pos-eol))) + (ert-simulate-command '(move-end-of-line 1)) + (should (= end (point))))) + + (when noninteractive + (kill-buffer))))) + +;;; erc-stamp-tests.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Make-some-erc-stamp-functions-more-limber.patch From 3671227a2be6ac134279cd383bc18e952c196ef0 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 4/8] [5.6] Make some erc-stamp functions more limber TODO: update ERC-NEWS announcing deprecation. * lisp/erc/erc-stamp.el (erc-timestamp-format-right): Deprecate option and change meaning of its nil value to fall through to `erc-timestamp-format'. Do this to allow modules to predict what the right-hand stamp's final width will be. This also saves `erc-insert-timestamp-left-and-right' from calling `erc-format-timestamp' again for no reason. (erc-stamp--current-time): Add new generic function and method to return current time. Default to calling `current-time'. (erc-stamp--current-time): New internal variable to hold time value used to construct time formatted stamp passed to `erc-insert-timestamp-function'. (erc-add-timestamp): Bind `erc-stamp--current-time' when calling `erc-insert-timestamp-function'. (erc-insert-timestamp-left-and-right): Use STRING parameter and favor it over the now deprecated `erc-timestamp-format-right' to avoid formatting twice. Also extract current time from the variable `erc-stamp--current-time' for similar reasons. --- lisp/erc/erc-stamp.el | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index bf1b0c6952c..459d022338a 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -55,6 +55,9 @@ erc-timestamp-format :type '(choice (const nil) (string))) +;; FIXME remove surrounding whitespace from default value and have +;; `erc-insert-timestamp-left-and-right' add it before insertion. + (defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n" "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. @@ -68,7 +71,7 @@ erc-timestamp-format-left :type '(choice (const nil) (string))) -(defcustom erc-timestamp-format-right " [%H:%M]" +(defcustom erc-timestamp-format-right nil "If set to a string, messages will be timestamped. This string is processed using `format-time-string'. Good examples are \"%T\" and \"%H:%M\". @@ -77,9 +80,14 @@ erc-timestamp-format-right screen when `erc-insert-timestamp-function' is set to `erc-insert-timestamp-left-and-right'. -If nil, timestamping is turned off." +Unlike `erc-timestamp-format' and `erc-timestamp-format-left', if +the value of this option is nil, it falls back to using the value +of `erc-timestamp-format'." + :package-version '(ERC . "5.6") ; FIXME sync on release :type '(choice (const nil) (string))) +(make-obsolete-variable 'erc-timestamp-format-right + 'erc-timestamp-format "30.1") (defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right "Function to use to insert timestamps. @@ -157,17 +165,31 @@ stamp (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp))) +(defvar erc-stamp--current-time nil + "The current time when calling `erc-insert-timestamp-function'. +Specifically, this is the same lisp time object used to create +the stamp passed to `erc-insert-timestamp-function'.") + +(cl-defgeneric erc-stamp--current-time () + "Return a lisp time object to associate with an IRC message. +This becomes the message's `erc-timestamp' text property, which +may not be unique." + (current-time)) + +(cl-defmethod erc-stamp--current-time :around () + (or erc-stamp--current-time (cl-call-next-method))) + (defun erc-add-timestamp () "Add timestamp and text-properties to message. This function is meant to be called from `erc-insert-modify-hook' or `erc-send-modify-hook'." (unless (get-text-property (point-min) 'invisible) - (let ((ct (current-time))) - (if (fboundp erc-insert-timestamp-function) - (funcall erc-insert-timestamp-function - (erc-format-timestamp ct erc-timestamp-format)) - (error "Timestamp function unbound")) + (let* ((ct (erc-stamp--current-time)) + (erc-stamp--current-time ct)) + (funcall erc-insert-timestamp-function + (erc-format-timestamp ct erc-timestamp-format)) + ;; FIXME this will error when advice has been applied. (when (and (fboundp erc-insert-away-timestamp-function) erc-away-timestamp-format (erc-away-time) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Put-display-properties-to-better-use-in-erc-stam.patch From 65833116b95cf7d21a3ed655387c28277d3f3e3a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 5/8] [5.6] Put display properties to better use in erc-stamp * lisp/erc/erc-stamp.el (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-stamp-right-margin-width): New option to determine width of right margin when `erc-stamp--display-margin-mode' is active or `erc-timestamp-use-align-to' is set to `margin'. (erc-stamp--display-margin-force): Add new helper function for `erc-stamp--display-margin-mode'. (erc-stamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el (erc-timestamp-use-align-to--nil, erc-timestamp-use-align-to--t): Adjust spacing for new default right-hand stamp, `erc-format-timestamp', which lacks a leading space. (erc-timestamp-use-align-to--integer, erc-timestamp-use-align-to--margin): New tests. --- lisp/erc/erc-stamp.el | 111 ++++++++++++++++++++++++++----- test/lisp/erc/erc-stamp-tests.el | 70 +++++++++++++++++-- 2 files changed, 159 insertions(+), 22 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 459d022338a..21885f3a36f 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -239,14 +239,68 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + A side effect of enabling this is that there will only be one space before a right timestamp in any saved logs." - :type 'boolean) + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.5")) ; FIXME sync on release + +(defcustom erc-stamp-right-margin-width nil + "Width in columns of the right margin. +When this option is nil, pretend its value is one column greater +than the `string-width' of the formatted `erc-timestamp-format'. +This option only matters when `erc-timestamp-use-align-to' is set +to `margin'." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) integer)) + +(defun erc-stamp--display-margin-force (orig &rest r) + (let ((erc-timestamp-use-align-to 'margin)) + (apply orig r))) + +;; If people want to use this directly, we can convert it into +;; a local module. +(define-minor-mode erc-stamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'. +It binds `erc-timestamp-use-align-to' to `margin' around calls to +`erc-insert-timestamp-function' in the current buffer, and sets +the right window margin to `erc-stamp-right-margin-width'. It +also arranges to remove most text properties when a user kills +message text so that stamps will be visible when yanked." + :interactive nil + (if erc-stamp--display-margin-mode + (let ((width (or erc-stamp-right-margin-width + (1+ (string-width (or erc-timestamp-last-inserted + (erc-format-timestamp + (current-time) + erc-timestamp-format))))))) + (setq right-margin-width width + right-fringe-width 0) + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0) + (add-function :filter-return (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (add-function :around (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force)) + (remove-function (local 'filter-buffer-substring-function) + #'erc--remove-text-properties) + (remove-function (local 'erc-insert-timestamp-function) + #'erc-stamp--display-margin-force) + (kill-local-variable 'right-margin-width) + (kill-local-variable 'right-fringe-width) + (set-window-margins left-margin-width nil) + (set-window-fringes left-fringe-width nil))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -265,6 +319,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -275,6 +330,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -326,25 +383,47 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) -(defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be used with `erc-insert-timestamp-function'. -If the date is changed, it will print a blank line, the date, and -another blank line. If the time is changed, it will then print -it off to the right." - (let* ((ct (current-time)) - (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) - (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) +(defun erc-insert-timestamp-left-and-right (string) + "Insert a stamp on either side when it changes. +When the deprecated option `erc-timestamp-format-right' is nil, +use STRING, which originates from `erc-timestamp-format', for the +right-hand stamp. Use `erc-timestamp-format-left' for the +left-hand stamp and expect it to change less frequently." + (let* ((ct (or erc-stamp--current-time (erc-stamp--current-time))) + (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) + (ts-right (with-suppressed-warnings + ((obsolete erc-timestamp-format-right)) + (if erc-timestamp-format-right + (erc-format-timestamp ct erc-timestamp-format-right) + string)))) ;; insert left timestamp (unless (string-equal ts-left erc-timestamp-last-inserted-left) (goto-char (point-min)) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index c8e5d75d77d..69523274812 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -68,7 +68,7 @@ erc-timestamp-use-align-to--nil (erc-display-message nil 'notice (current-buffer) "begin")) (goto-char (point-min)) (should (search-forward-regexp - (rx "begin" (+ "\t") (* " ") " [") nil t)) + (rx "begin" (+ "\t") (* " ") "[") nil t)) ;; Field includes intervening spaces (should (eql ?n (char-before (field-beginning (point))))) ;; Timestamp extends to the end of the line @@ -85,9 +85,9 @@ erc-timestamp-use-align-to--nil (erc-timestamp-right-column 20)) (erc-display-message nil 'notice (current-buffer) "twenty characters")) - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field excludes leading whitespace (arguably undesirable). - (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\[ (char-after (field-beginning (point))))) ;; Timestamp extends to the end of the line. (should (eql ?\n (char-after (field-end (point))))))))) @@ -101,7 +101,7 @@ erc-timestamp-use-align-to--t (erc-display-message nil nil (current-buffer) msg))) (goto-char (point-min)) ;; Exactly two spaces, one from format, one added by erc-stamp. - (should (search-forward "msg one [" nil t)) + (should (search-forward "msg one [" nil t)) ;; Field covers space between. (should (eql ?e (char-before (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point)))))) @@ -112,9 +112,67 @@ erc-timestamp-use-align-to--t (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) (erc-display-message nil nil (current-buffer) msg))) ;; Indented to pos (this is arguably a bug). - (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") "[") nil t)) ;; Field starts *after* leading space (arguably bad). - (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\[ (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-stamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one[" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo[" nil t)) + ;; Field starts at leading space. + (should (eql ?\[ (char-after (field-beginning (point))))) (should (eql ?\n (char-after (field-end (point))))))))) ;; This concerns the partial reversal of changes resulting from: -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From 23a185750d8e246dc517bc3ad0a11e491f2be2ef Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 6/8] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Add-variant-for-erc-match-invisibility-spec.patch From 563bd525a913e98efca9ce1e50b07924f4c1b689 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 27 Jan 2023 05:34:56 -0800 Subject: [PATCH 7/8] [5.6] Add variant for erc-match invisibility spec * lisp/erc/erc-match.el (erc-match-enable, erc-match-disable): Arrange for possibly adding or removing `erc-match' from `buffer-invisibility-spec'. (erc-match--hide-fools-offset-bounds): Add new variable to serve as switch for activating invisibility on a modified interval that's offset toward `point-min' by one character. (erc-hide-fools): Optionally offset start and end of invisible region by minus one. (erc-match--modify-invisibility-spec): New housekeeping function to set up and tear down offset spec. --- lisp/erc/erc-match.el | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 499bcaf5724..87272f0b647 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,11 @@ match `erc-current-nick-highlight-type'. For all these highlighting types, you can decide whether the entire message or only the sending nick is highlighted." - ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append)) - ((remove-hook 'erc-insert-modify-hook #'erc-match-message))) + ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) + (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (erc-match--modify-invisibility-spec))) ;; Remaining customizations @@ -649,13 +652,22 @@ erc-go-to-log-matches-buffer (define-key erc-mode-map "\C-c\C-k" #'erc-go-to-log-matches-buffer) +(defvar-local erc-match--hide-fools-offset-bounds nil) + (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." - (when (eq match-type 'fool) - (erc-put-text-properties (point-min) (point-max) - '(invisible intangible) - (current-buffer)))) + (when (eq match-type 'fool) + (if erc-match--hide-fools-offset-bounds + (let ((beg (point-min)) + (end (point-max))) + (save-restriction + (widen) + (put-text-property (1- beg) (1- end) 'invisible 'erc-match))) + ;; The docs say `intangible' is deprecated, but this has been + ;; like this for ages. Should verify unneeded and remove if so. + (erc-put-text-properties (point-min) (point-max) + '(invisible intangible))))) (defun erc-beep-on-match (match-type _nickuserhost _message) "Beep when text matches. @@ -663,6 +675,13 @@ erc-beep-on-match (when (member match-type erc-beep-match-types) (beep))) +(defun erc-match--modify-invisibility-spec () + "Add an ellipsis property to the local spec." + (if erc-match-mode + (add-to-invisibility-spec 'erc-match) + (erc-with-all-buffers-of-server nil nil + (remove-from-invisibility-spec 'erc-match)))) + (provide 'erc-match) ;;; erc-match.el ends here -- 2.39.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch From 8ff3d6905355e41bd91fd8e24577b68e762cfb0a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 8/8] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill-wrap-mode, erc-fill--wrap-prefix, erc-fill--wrap-value, erc-fill--wrap-movement): New minor mode and variables to support it. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. --- lisp/erc/erc-common.el | 1 + lisp/erc/erc-fill.el | 273 +++++++++++++++++++++++++++++++- test/lisp/erc/erc-fill-tests.el | 172 ++++++++++++++++++++ 3 files changed, 441 insertions(+), 5 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 994555acecf..aae8280baa9 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -95,6 +95,7 @@ erc--features-to-modules (erc-join autojoin) (erc-page page ctcp-page) (erc-sound sound ctcp-sound) + (erc-fill fill-wrap) (erc-stamp stamp timestamp) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..ecd721f2f03 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: (require 'erc) @@ -79,16 +82,29 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, thanks to `visual-line-mode' mode, which ERC automatically +enables when this option is `erc-fill-wrap' or when +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be centered. -This column denotes the point where the ` ' character between -<nickname> and the entered text will be put, thus aligning nick -names right and text left." + "Number of columns to \"outdent\" the first line of a message. +During early message handing, ERC prepends a span of +non-whitespace characters to every message, such as a bracketed +\"<nickname>\" or an `erc-notice-prefix'. The +`erc-fill-function' variants `erc-fill-static' and +`erc-fill-wrap' look to this option to determine the amount of +padding to apply to that portion until the filled (or wrapped) +message content aligns with the indicated column. See also +https://en.wikipedia.org/wiki/Hanging_indent." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +171,253 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) +(defvar-local erc-fill--wrap-prefix nil) +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-visual-keys nil) + +(defcustom erc-fill-wrap-use-pixels t + "Whether to calculate padding in pixels when possible. +A value of nil means ERC should use columns, which may happen +regardless, depending on the Emacs version. This option only +matters when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type 'boolean) + +(defcustom erc-fill-wrap-visual-keys 'non-input + "Whether to retain keys defined by `visual-line-mode'. +A value of t tells ERC to use movement commands defined by +`visual-line-mode' everywhere in an ERC buffer along with visual +editing commands in the input area. A value of nil means to +never do so. A value of `non-input' tells ERC to act like the +value is nil in the input area and t elsewhere. This option only +plays a role when `erc-fill-wrap-mode' is enabled." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice (const nil) (const t) (const non-input))) + +(defun erc-fill--wrap-move (normal-cmd visual-cmd arg) + (funcall + (pcase erc-fill--wrap-visual-keys + ('non-input (if (>= (point) erc-input-marker) normal-cmd visual-cmd)) + ('t visual-cmd) + (_ normal-cmd)) + arg)) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but we run + ;; `kill-line' anyway so that users can see the error. + (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (erc-fill--wrap-move #'move-beginning-of-line + #'beginning-of-visual-line arg)) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "Defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (erc-fill--wrap-move #'move-end-of-line #'end-of-visual-line arg)) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-visual-keys' styles ARG times. +Go from nil to t to `non-input' and back around, but set internal +state instead of mutating `erc-fill-wrap-visual-keys'. When ARG +is 0, reset to value of `erc-fill-wrap-visual-keys'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-visual-keys (pcase erc-fill--wrap-visual-keys + ('nil t) + ('t 'non-input) + ('non-input nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-visual-keys)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c a" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(defvar erc-match-mode) +(defvar erc-match--hide-fools-offset-bounds) + +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles. When the option +`erc-insert-timestamp-function' is `erc-insert-timestamp-right' +or `erc-insert-timestamp-left-and-right', it shows timestamps in +the right margin." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + (concat "WARNING: enabling default global module `fill' needed " + " by local module `fill-wrap'. This will impact all" + " ERC sessions. Add `fill' to `erc-modules' to avoid " + " this warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-visual-keys (alist-get 'erc-fill--wrap-visual-keys + vars) + erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (or erc-stamp-mode (memq 'stamp erc-modules)) + (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-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center) + ;; + erc-fill--wrap-prefix + (or erc-fill--wrap-prefix + (list 'space :width erc-fill--wrap-value))) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-visual-keys) + (setq erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-stamp--display-margin-mode + (erc-stamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-prefix) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-visual-keys) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of overhanging characters. +It should return an EXPR as defined by the info node `(elisp) +Pixel Specification'. This value should represent the width of +the overhang with all faces applied, including any enclosing +brackets (which are not normally fontified) and a trailing space. +It can also return nil to tell ERC to fall back to the default +behavior of taking the length from the first \"word\". This +variable can be converted to a public one if needed by third +parties.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill-wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + ;; Leaving out the final newline doesn't seem to affect anything. + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- ,erc-fill--wrap-value ,len)) + ,erc-fill--wrap-prefix))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +Reset prefix to VALUE, when given." + (save-excursion + (when value + (setq erc-fill--wrap-value value + erc-fill--wrap-prefix (list 'space :width value))) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (line-beginning-position) (line-end-position)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (save-excursion + (save-restriction + (widen) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t) ; necessary? + (p (goto-char (point-min)))) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf (caddr erc-fill--wrap-prefix) arg) + (cl-incf erc-fill--wrap-value arg) + (while (setq p (next-single-property-change p 'line-prefix)) + (when-let ((v (get-text-property p 'line-prefix))) + (cl-incf (nth 1 (nth 2 v)) arg) ; (space :width (- *this* len)) + (when-let + ((e (text-property-not-all p (point-max) 'line-prefix v))) + (goto-char e))))))) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. Note that misalignment may occur when +messages contain decorations applied by third-party modules. +See `erc-fill--wrap-fix' for a workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (let ((total (erc-fill--wrap-nudge arg)) + (start (window-start)) + (marker (set-marker (make-marker) (point)))) + (when (zerop arg) + (setq arg 1)) + (set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?= ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (set-window-start (selected-window) start) + (goto-char marker))))) + map) + t + (lambda () + (set-marker marker nil) + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (goto-char marker) + (set-window-start (selected-window) start))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el new file mode 100644 index 00000000000..77d553bc3a2 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,172 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defun erc-fill-tests--wrap-populate (test) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (erc-modules '(fill stamp)) + (msg "Hello World") + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + (set-process-query-on-exit-flag erc-server-process nil) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + (setq msg "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.") + + (erc-display-message nil 'notice (current-buffer) msg) + (setq msg "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.") + + (erc-display-message + nil nil (current-buffer) + (erc-format-privmessage "alice" msg nil t)) + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + + (erc-display-message + nil nil (current-buffer) + (erc-format-privmessage "bob" msg nil t)) + + (funcall test) + (when noninteractive + (kill-buffer))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (goto-char (point-min)) + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 27))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 27))) + ;; The last elt in the `:width' value is a singleton (NUM) when + ;; figuring pixels. Otherwise, it's just NUM. See EXPR in the + ;; prod rules table under (info "(elisp) Pixel Specification"). + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- 27 (,w)))) + (= w (string-pixel-width "<alice> "))) + (`(space :width (- 27 ,w)) + (= w (length "<alice> "))))) + + (erc-fill--wrap-nudge 2) + + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 29))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 29))) + (should (pcase (get-text-property (point) 'line-prefix) + ((and (guard (fboundp 'string-pixel-width)) + `(space :width (- 29 (,w)))) + (= w (string-pixel-width "<bob> "))) + (`(space :width (- 29 ,w)) + (= w (length "<bob> ")))))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (fboundp 'string-pixel-width) + (not noninteractive) + (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + + (lambda () + + (goto-char (point-min)) + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 27))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 27))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 27 (,w))) + (> w (string-pixel-width "<alice> "))))) + + (erc-fill--wrap-nudge 2) + + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 29))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 29))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 29 (,w))) + (> w (string-pixel-width "<bob> "))))) + + ;; FIXME figure out how to get rid of this "void variable + ;; `erc--results-ewoc'" error, which seems related to operating + ;; in this second frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +;;; erc-fill-tests.el ends here -- 2.39.1 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936) by debbugs.gnu.org; 25 Jan 2023 14:11:30 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jan 25 09:11:30 2023 Received: from localhost ([127.0.0.1]:58683 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pKgUp-0000pl-TR for submit <at> debbugs.gnu.org; Wed, 25 Jan 2023 09:11:30 -0500 Received: from mail-108-mta128.mxroute.com ([136.175.108.128]:33985) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pKgUm-0000pX-2u for 60936 <at> debbugs.gnu.org; Wed, 25 Jan 2023 09:11:26 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta128.mxroute.com (ZoneMTA) with ESMTPSA id 185e944c9cc000011e.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Wed, 25 Jan 2023 14:11:17 +0000 X-Zone-Loop: 8a4fc8ea35a65305f52721299fed5b2c536b66744dc2 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=czB9RiTxFyE8vJdgpTZ8gr+cwaCV1FpFDDbYGMaj6QQ=; b=Eps4eo9rsVpObc9DYwKS1OKnBZ tB+K/Lrqs0ffVJEl5deR/++NCMVV94aeNYbQgpaOvPBeZqidOOLxIpvjPmrSq9WIa1znoxDeFw3NA 8qMsQrn16FS/QL5zIJO5y1zJgJroZnT6CXaxrlbK2yhWnHr71V3HpHY3IIPuh4z5f91TiCs5Ym0Sw jz/TA167cmpC8pXk2HwQuoEjWshNnPkysWLnNJyY1bqCsiMubhzcYoQW+DGmw6EgAZDspm4PrtY5O WA+SWaisCQVr/UgHYedRioJHxqepOe6OiyhUwpLoJBunxaYJTTLBfA5sfvrOs6qk6/zh6R3B2Yt9G uJm4olqg==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Wed, 25 Jan 2023 06:11:13 -0800 Message-ID: <87a626iu0u.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain v3. Accommodate variable-pitch faces on graphical displays. Use `defvar-keymap', now available in the latest Compat. Screenshot: https://debbugs.gnu.org/cgi/bugreport.cgi?msg=11;filename=fill-wrap-vp.png;bug=60936;att=1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v2-v3.diff From 19ddf027ab3cbfde020e43cdb2bcece828c6638f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 25 Jan 2023 05:51:53 -0800 Subject: [PATCH 0/4] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (4): [5.6] Adjust some old text properties in ERC buffers [5.6] Leverage display properties better in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-common.el | 1 + lisp/erc/erc-fill.el | 281 ++++++++++++++++++++++++++++--- lisp/erc/erc-stamp.el | 66 +++++++- lisp/erc/erc.el | 3 +- test/lisp/erc/erc-fill-tests.el | 162 ++++++++++++++++++ test/lisp/erc/erc-stamp-tests.el | 178 ++++++++++++++++++++ 6 files changed, 656 insertions(+), 35 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el create mode 100644 test/lisp/erc/erc-stamp-tests.el Interdiff: diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 6a461786be1..a05f2a558f8 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: (require 'erc) @@ -228,20 +231,15 @@ erc-fill-wrap-cycle-visual-movement ('display nil)))) (message "erc-fill-wrap-movement: %S" erc-fill--wrap-movement)) -;; We could just override `visual-line-mode-map' locally, but that -;; seems pretty hacky. -(defvar erc-fill-wrap-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map visual-line-mode-map) - (define-key map [remap kill-line] #'erc-fill--wrap-kill-line) - (define-key map [remap move-end-of-line] #'erc-fill--wrap-end-of-line) - (define-key map [remap move-beginning-of-line] - #'erc-fill--wrap-beginning-of-line) - ;; This is redundant anyway (right?). - (define-key map "\C-c\C-a" #'erc-fill-wrap-cycle-visual-movement) - ;; Not sure if this is dumb because `erc-bol' takes no args. - (define-key map [remap erc-bol] #'erc-fill--wrap-beginning-of-line) - map)) +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c c" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) (define-erc-module fill-wrap nil "Fill style leveraging `visual-line-mode'. @@ -295,6 +293,10 @@ erc-fill--wrap-length-function nickname, including any enclosing brackets, or nil, to fall back to the default behavior of taking the length from the first word.") +(defvar erc-fill--wrap-use-pixels t) +(declare-function buffer-text-pixel-size "xdisp" + (&optional buffer-or-name window x-limit y-limit)) + (defun erc-fill-wrap () "Use text props to mimic the effect of `erc-fill-static'. See `erc-fill-wrap-mode' for details." @@ -302,13 +304,20 @@ erc-fill-wrap (erc-fill-wrap-mode +1)) (save-excursion (goto-char (point-min)) - (let ((len (or (and erc-fill--wrap-length-function - (funcall erc-fill--wrap-length-function)) - (progn (skip-syntax-forward "^-") - (- (point) (point-min)))))) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill--wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) (erc-put-text-properties (point-min) (point-max) '(line-prefix wrap-prefix) nil - `((space :width ,(- erc-fill--wrap-value 1 len)) + `((space :width (- ,erc-fill--wrap-value ,len)) ,erc-fill--wrap-prefix))))) ;; This is an experimental helper for third-party modules. You could, @@ -344,7 +353,7 @@ erc-fill--wrap-nudge (cl-incf erc-fill--wrap-value arg) (while (setq p (next-single-property-change p 'line-prefix)) (when-let ((v (get-text-property p 'line-prefix))) - (cl-incf (caddr v) arg) + (cl-incf (nth 1 (nth 2 v)) arg) ; (space :width (- *this* len)) (when-let ((e (text-property-not-all p (point-max) 'line-prefix v))) (goto-char e))))))) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el new file mode 100644 index 00000000000..cf243ef43c7 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,162 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defun erc-fill-tests--wrap-populate (test) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (erc-modules '(fill stamp)) + (msg "Hello World") + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + (setq msg "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.") + + (erc-display-message nil 'notice (current-buffer) msg) + (setq msg "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.") + + (erc-display-message + nil nil (current-buffer) + (erc--format-privmsg "alice" msg nil t nil)) + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + + (erc-display-message + nil nil (current-buffer) + (erc--format-privmsg "bob" msg nil t nil)) + + (funcall test) + (when noninteractive + (kill-buffer))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (goto-char (point-min)) + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 27))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 27))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 27 (,w))) + (should (= w (string-pixel-width "<alice> ")))))) + + (erc-fill--wrap-nudge 2) + + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 29))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 29))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 29 (,w))) + (should (= w (string-pixel-width "<bob> "))))))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (not noninteractive) (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + + (lambda () + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (goto-char (point-min)) + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 27))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 27))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 27 (,w))) + (should (> w (string-pixel-width "<alice> ")))))) + + (erc-fill--wrap-nudge 2) + + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 29))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 29))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 29 (,w))) + (should (> w (string-pixel-width "<bob> ")))))) + + ;; FIXME figure out how to get rid of this "void variable + ;; `erc--results-ewoc'" error, which seems related to operating + ;; in this second frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +;;; erc-fill-tests.el ends here -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From 80dccfa483020177c3e705f3c59c4875a635a568 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 1/4] [5.6] Adjust some old text properties in ERC buffers TODO: because these have been around forever, we should mention their deletion in the misc-library section of ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Remove the confusing `rear-sticky' text property, which has been around since 2002. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. --- lisp/erc/erc.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ff1820cfaf2..4bc9fc20f8a 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2867,7 +2867,6 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4296,7 +4295,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Leverage-display-properties-better-in-erc-stamp.patch From 5e9422dc39c61af03dd3ca24d419927f2f07c8bd Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 2/4] [5.6] Leverage display properties better in erc-stamp (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-timestamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el: New file. --- lisp/erc/erc-stamp.el | 66 ++++++++++-- test/lisp/erc/erc-stamp-tests.el | 178 +++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+), 8 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..e9592448a33 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -217,14 +217,44 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + A side effect of enabling this is that there will only be one space before a right timestamp in any saved logs." - :type 'boolean) + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.4.1")) ; FIXME update when merging + +;; If people want to use this directly, we can offer an option to set +;; the margin's width. +(define-minor-mode erc-timestamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'." + :interactive nil + (if-let ((erc-timestamp--display-margin-mode) + (width (if erc-timestamp-last-inserted-right + (length erc-timestamp-last-inserted-right) + (1+ (length (erc-format-timestamp + (current-time) + erc-timestamp-format-right)))))) + (progn + (setq right-margin-width width + right-fringe-width 0) + (unless noninteractive + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + (kill-local-variable 'right-margin-width) + (unless noninteractive + (set-window-margins nil nil) + (set-window-fringes nil nil)))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -243,6 +273,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -253,6 +284,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -304,12 +337,29 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..4994feefd4e --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,178 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-timestamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one [" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;;; erc-stamp-tests.el ends here -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From 35d1b98e38a2848f3cef3297131a379b1690e6ea Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 3/4] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch From 19ddf027ab3cbfde020e43cdb2bcece828c6638f Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 4/4] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill-wrap-mode, erc-fill--wrap-prefix, erc-fill--wrap-value, erc-fill--wrap-movement): New minor mode and variables to support it. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. * test/lisp/erc/erc-fill-tests.el: New file. --- lisp/erc/erc-common.el | 1 + lisp/erc/erc-fill.el | 247 +++++++++++++++++++++++++++++++- test/lisp/erc/erc-fill-tests.el | 162 +++++++++++++++++++++ 3 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 test/lisp/erc/erc-fill-tests.el diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 994555acecf..aae8280baa9 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -95,6 +95,7 @@ erc--features-to-modules (erc-join autojoin) (erc-page page ctcp-page) (erc-sound sound ctcp-sound) + (erc-fill fill-wrap) (erc-stamp stamp timestamp) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..a05f2a558f8 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -28,6 +28,9 @@ ;; `erc-fill-mode' to switch it on. Customize `erc-fill-function' to ;; change the style. +;; TODO: redo `erc-fill-wrap-nudge' using transient after ERC drops +;; support for Emacs 27. + ;;; Code: (require 'erc) @@ -79,16 +82,27 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, courtesy of `visual-line-mode' mode, which ERC +automatically enables when this option is `erc-fill-wrap' or +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) (defcustom erc-fill-static-center 27 "Column around which all statically filled messages will be centered. This column denotes the point where the ` ' character between <nickname> and the entered text will be put, thus aligning nick -names right and text left." +names right and text left. + +Also used by the `erc-fill-function' variant `erc-fill-wrap' for +its initial leading \"prefix\" width." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +169,235 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) +(defvar-local erc-fill--wrap-prefix nil) +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-movement nil) + +(defcustom erc-fill-wrap-movement t + "Whether to override keys defined by `visual-line-mode'. +A value of `display' means to favor default `erc-mode' keys when +point is in the input area." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice boolean (const display :tag "Display area" + :doc "Use `erc-mode' keys in input area"))) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but users + ;; still need to see the message. + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (kill-line arg) + (kill-visual-line arg))) + ('t (kill-visual-line arg)) + (_ (kill-line arg)))) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (move-beginning-of-line arg) + (beginning-of-visual-line arg))) + ('t (beginning-of-visual-line arg)) + (_ (move-beginning-of-line arg))) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (move-end-of-line arg) + (end-of-visual-line arg))) + ('t (end-of-visual-line arg)) + (_ (move-end-of-line arg)))) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-movement' styles ARG times. +Go from nil to t to `display' and back around, but set internal +state instead of mutating `erc-fill-wrap-movement'. When ARG is +0, reset to value of `erc-fill-wrap-movement'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-movement erc-fill-wrap-movement)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-movement (pcase erc-fill--wrap-movement + ('nil t) + ('t 'display) + ('display nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-movement)) + +(defvar-keymap erc-fill-wrap-mode-map ; Compat 29 + :doc "Keymap for ERC's `fill-wrap' module." + :parent visual-line-mode-map + "<remap> <kill-line>" #'erc-fill--wrap-kill-line + "<remap> <move-end-of-line>" #'erc-fill--wrap-end-of-line + "<remap> <move-beginning-of-line>" #'erc-fill--wrap-beginning-of-line + "C-c c" #'erc-fill-wrap-cycle-visual-movement + ;; Not sure if this is problematic because `erc-bol' takes no args. + "<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line) + +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + (concat "WARNING: enabling default global module `fill' needed " + " by local module `fill-wrap'. This will impact all" + " ERC sessions. Add `fill' to `erc-modules' to avoid " + " this warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-movement (alist-get 'erc-fill--wrap-movement vars) + erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (eq erc-timestamp-use-align-to 'margin) + (erc-timestamp--display-margin-mode +1)) + (setq erc-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center) + ;; + erc-fill--wrap-prefix + (or erc-fill--wrap-prefix + (list 'space :width erc-fill--wrap-value))) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-movement) + (setq erc-fill--wrap-movement erc-fill-wrap-movement)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-timestamp--display-margin-mode + (erc-timestamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-prefix) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-movement) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of perceived nickname. +It should return an integer representing the length of the +nickname, including any enclosing brackets, or nil, to fall back +to the default behavior of taking the length from the first word.") + +(defvar erc-fill--wrap-use-pixels t) +(declare-function buffer-text-pixel-size "xdisp" + (&optional buffer-or-name window x-limit y-limit)) + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let* ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn + (skip-syntax-forward "^-") + (forward-char) + (if (and erc-fill--wrap-use-pixels + (fboundp 'buffer-text-pixel-size)) + (save-restriction + (narrow-to-region (point-min) (point)) + (list (car (buffer-text-pixel-size)))) + (- (point) (point-min))))))) + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width (- ,erc-fill--wrap-value ,len)) + ,erc-fill--wrap-prefix))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +Reset prefix to VALUE, when given." + (save-excursion + (when value + (setq erc-fill--wrap-value value + erc-fill--wrap-prefix (list 'space :width value))) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (pos-bol) (pos-eol)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (save-excursion + (save-restriction + (widen) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t) ; necessary? + (p (goto-char (point-min)))) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf (caddr erc-fill--wrap-prefix) arg) + (cl-incf erc-fill--wrap-value arg) + (while (setq p (next-single-property-change p 'line-prefix)) + (when-let ((v (get-text-property p 'line-prefix))) + (cl-incf (nth 1 (nth 2 v)) arg) ; (space :width (- *this* len)) + (when-let + ((e (text-property-not-all p (point-max) 'line-prefix v))) + (goto-char e))))))) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. Note that misalignment may occur when +messages contain decorations applied by third-party modules. +See `erc-fill--wrap-fix' for a workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (let ((total (erc-fill--wrap-nudge arg)) + (start (window-start)) + (marker (set-marker (make-marker) (point)))) + (when (zerop arg) + (setq arg 1)) + (set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?= ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (set-window-start (selected-window) start) + (goto-char marker))))) + map) + t + (lambda () + (set-marker marker nil) + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (goto-char marker) + (set-window-start (selected-window) start))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." (fill-region (point-min) (point-max) t t) diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el new file mode 100644 index 00000000000..cf243ef43c7 --- /dev/null +++ b/test/lisp/erc/erc-fill-tests.el @@ -0,0 +1,162 @@ +;;; erc-fill-tests.el --- Tests for erc-fill -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert-x) +(require 'erc-fill) + +(defun erc-fill-tests--wrap-populate (test) + (let ((proc (start-process "sleep" (current-buffer) "sleep" "1")) + (id (erc-networks--id-create 'foonet)) + (erc-insert-modify-hook '(erc-fill erc-add-timestamp)) + (erc-server-users (make-hash-table :test 'equal)) + (erc-fill-function 'erc-fill-wrap) + (erc-modules '(fill stamp)) + (msg "Hello World") + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (when (bound-and-true-p erc-button-mode) + (push 'erc-button-add-buttons erc-insert-modify-hook)) + (erc-mode) + (setq erc-server-process proc erc-networks--id id) + + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process proc + erc-networks--id id + erc-channel-users (make-hash-table :test 'equal) + erc--target (erc--target-from-string "#chan") + erc-default-recipients (list "#chan")) + (erc--initialize-markers (point) nil) + + (erc-update-channel-member + "#chan" "alice" "alice" t nil nil nil nil nil "fake" "~u" nil nil t) + + (erc-update-channel-member + "#chan" "bob" "bob" t nil nil nil nil nil "fake" "~u" nil nil t) + (setq msg "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.") + + (erc-display-message nil 'notice (current-buffer) msg) + (setq msg "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.") + + (erc-display-message + nil nil (current-buffer) + (erc--format-privmsg "alice" msg nil t nil)) + (setq msg "alice: Either your unparagoned mistress is dead,\ + or she's outprized by a trifle.") + + (erc-display-message + nil nil (current-buffer) + (erc--format-privmsg "bob" msg nil t nil)) + + (funcall test) + (when noninteractive + (kill-buffer))))) + +(ert-deftest erc-fill-wrap--monospace () + :tags '(:unstable) + + (erc-fill-tests--wrap-populate + + (lambda () + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (goto-char (point-min)) + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 27))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 27))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 27 (,w))) + (should (= w (string-pixel-width "<alice> ")))))) + + (erc-fill--wrap-nudge 2) + + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 29))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 29))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 29 (,w))) + (should (= w (string-pixel-width "<bob> "))))))))) + +(ert-deftest erc-fill-wrap--variable-pitch () + :tags '(:unstable) + (unless (and (not noninteractive) (display-graphic-p)) + (ert-skip "Test needs interactive graphical Emacs")) + + (with-selected-frame (make-frame '((name . "other"))) + (set-face-attribute 'default (selected-frame) + :family "Sans Serif" + :foundry 'unspecified + :font 'unspecified) + + (erc-fill-tests--wrap-populate + + (lambda () + + ;; Prefix props are applied properly and faces are accounted + ;; for when determining widths. + (goto-char (point-min)) + (should (search-forward "<a" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 27))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 27))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 27 (,w))) + (should (> w (string-pixel-width "<alice> ")))))) + + (erc-fill--wrap-nudge 2) + + (should (search-forward "<b" nil t)) + (should (get-text-property (pos-bol) 'line-prefix)) + (should (get-text-property (pos-eol) 'line-prefix)) + (should (equal (get-text-property (pos-bol) 'wrap-prefix) + '(space :width 29))) + (should (equal (get-text-property (pos-eol) 'wrap-prefix) + '(space :width 29))) + (should (pcase (get-text-property (point) 'line-prefix) + (`(space :width (- 29 (,w))) + (should (> w (string-pixel-width "<bob> ")))))) + + ;; FIXME figure out how to get rid of this "void variable + ;; `erc--results-ewoc'" error, which seems related to operating + ;; in this second frame. + ;; + ;; As a kludge, checking if point made it to the prompt can + ;; serve as visual confirmation that the test passed. + (goto-char (point-max)))))) + +;;; erc-fill-tests.el ends here -- 2.38.1 --=-=-=--
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936-quiet) by debbugs.gnu.org; 25 Jan 2023 14:04:28 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jan 25 09:04:28 2023 Received: from localhost ([127.0.0.1]:58679 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pKgO4-0000fB-73 for submit <at> debbugs.gnu.org; Wed, 25 Jan 2023 09:04:28 -0500 Received: from mail-108-mta215.mxroute.com ([136.175.108.215]:34819) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pKgO2-0000ey-Us for 60936-quiet <at> debbugs.gnu.org; Wed, 25 Jan 2023 09:04:27 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta215.mxroute.com (ZoneMTA) with ESMTPSA id 185e93e61e1000011e.001 for <60936-quiet <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Wed, 25 Jan 2023 14:04:17 +0000 X-Zone-Loop: 788babb33c48f849be5d9626d5d1fb6d56b56abd61d9 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:To:From:Sender:Reply-To:Cc: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=ydV7UEmkB4B5jVDDm1CJaYuXCQsS0jEqYASvujgxtUI=; b=FteQredZzfN7QRdRIDZHhQfIaF PpoTDIECmjR/R87/LcFPNzvs3t0Nv/jAJfX9uMrI849Xf9VowZ2le04AEwOWETliQs0+atA3KB5Jf mh7O43bQvRh/aDOtsdR3cRKIKVDdJdPKuZ4Xoazas8qGBr/AqTipYxyBoi7LY4QR0PMl4HLuv/KHn hajBEan8yGJQNkheswySz9d0DTOHvFwKiS/pYGSUG1eyfxGzaJ+cF1lleuO5XUBnAOXSI91jBIaI5 smGYRg+Gf+dtSPU2MkCgaQYt+SLpWeNvFUhy5QrxacyBSP7cFG53eteD53wOQ07cODtnFmwDDfBaH 8IflQg6w==; From: "J.P." <jp@HIDDEN> To: 60936-quiet <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Wed, 25 Jan 2023 06:04:13 -0800 Message-ID: <87lelqiuci.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936-quiet X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain Screenshot (variable-pitch). --=-=-= Content-Type: image/png Content-Disposition: attachment; filename=fill-wrap-vp.png Content-Transfer-Encoding: base64 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 --=-=-=--
Received: (at 60936-quiet) by debbugs.gnu.org; 20 Jan 2023 14:16:22 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jan 20 09:16:22 2023 Received: from localhost ([127.0.0.1]:45980 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pIsBo-0001Sp-8g for submit <at> debbugs.gnu.org; Fri, 20 Jan 2023 09:16:22 -0500 Received: from mail-108-mta2.mxroute.com ([136.175.108.2]:42053) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pIsBl-0001SM-5E for 60936-quiet <at> debbugs.gnu.org; Fri, 20 Jan 2023 09:16:19 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta2.mxroute.com (ZoneMTA) with ESMTPSA id 185cf896d10000011e.001 for <60936-quiet <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Fri, 20 Jan 2023 14:16:08 +0000 X-Zone-Loop: d9ec04496970250d4e7e24177e7cd544b6971d99f75d 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:To:From:Sender:Reply-To:Cc: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=npBOb9Qn2N5hW3BcvkXMt3e9qLO0/oET0268HSnYNJw=; b=gCiSmU0iaHGgxrtHXMg37TEsq/ egwz/pRPl1mhPRsuxyC351G6+unXGJvR72kR0Bku/A9AGT4K+DcC8i5vZe99HfGK3afvZGej7EFPT BRTrm1w7QWVuig55BAlxfWUtopkf/hVPyHwmEJRJnZZUdI4VTxIPFaNCNIi9N5kuYK4kGf/GI6xVV uAXYj9Rh4F4qb/X3+DTvqqQ+Lp9CEvurdyZMy9eoQMuWbJ19vn7Ws0ssvV6z1gyOo3kPnQXIfHYXp L3r/F/f0pY8XUIXSwPM0luJhTc05pt6rgAc7TT5Ak9cdwJIebp6KvFqB9FHkaFvaiZ2bwC6Cbbmet xZAfMjQg==; From: "J.P." <jp@HIDDEN> To: 60936-quiet <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87mt6fao0a.fsf_-_@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:57:57 -0800") References: <87tu0nao77.fsf@HIDDEN> <handler.60936.B.167405364619245.ack <at> debbugs.gnu.org> <87mt6fao0a.fsf_-_@HIDDEN> Date: Fri, 20 Jan 2023 06:16:05 -0800 Message-ID: <873585uw9m.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936-quiet X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain v2. Add toggle for visual-line-mode's command analogs (e.g., `beginning-of-visual-line', `kill-visual-line', etc.). --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v1-v2.diff From 491f9dbb42677bcbfa2f08aea5d165c52c0019b9 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 20 Jan 2023 00:06:53 -0800 Subject: [PATCH 0/4] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (4): [5.6] Adjust some old text properties in ERC buffers [5.6] Leverage display properties better in erc-stamp [5.6] Convert erc-fill minor mode into a proper module [5.6] Add erc-fill style based on visual-line-mode lisp/erc/erc-common.el | 1 + lisp/erc/erc-fill.el | 272 ++++++++++++++++++++++++++++--- lisp/erc/erc-stamp.el | 66 +++++++- lisp/erc/erc.el | 3 +- test/lisp/erc/erc-stamp-tests.el | 178 ++++++++++++++++++++ 5 files changed, 485 insertions(+), 35 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el Interdiff: diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index cfe8b12380f..aae8280baa9 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -95,8 +95,8 @@ erc--features-to-modules (erc-join autojoin) (erc-page page ctcp-page) (erc-sound sound ctcp-sound) - (erc-stamp stamp timestamp) (erc-fill fill-wrap) + (erc-stamp stamp timestamp) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. Keys need not be unique: a library may define more than one diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 95b388cbf84..6a461786be1 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -168,6 +168,80 @@ erc-fill-variable (defvar-local erc-fill--wrap-prefix nil) (defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-movement nil) + +(defcustom erc-fill-wrap-movement t + "Whether to override keys defined by `visual-line-mode'. +A value of `display' means to favor default `erc-mode' keys when +point is in the input area." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice boolean (const display :tag "Display area" + :doc "Use `erc-mode' keys in input area"))) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but users + ;; still need to see the message. + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (kill-line arg) + (kill-visual-line arg))) + ('t (kill-visual-line arg)) + (_ (kill-line arg)))) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (move-beginning-of-line arg) + (beginning-of-visual-line arg))) + ('t (beginning-of-visual-line arg)) + (_ (move-beginning-of-line arg))) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (move-end-of-line arg) + (end-of-visual-line arg))) + ('t (end-of-visual-line arg)) + (_ (move-end-of-line arg)))) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-movement' styles ARG times. +Go from nil to t to `display' and back around, but set internal +state instead of mutating `erc-fill-wrap-movement'. When ARG is +0, reset to value of `erc-fill-wrap-movement'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-movement erc-fill-wrap-movement)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-movement (pcase erc-fill--wrap-movement + ('nil t) + ('t 'display) + ('display nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-movement)) + +;; We could just override `visual-line-mode-map' locally, but that +;; seems pretty hacky. +(defvar erc-fill-wrap-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map visual-line-mode-map) + (define-key map [remap kill-line] #'erc-fill--wrap-kill-line) + (define-key map [remap move-end-of-line] #'erc-fill--wrap-end-of-line) + (define-key map [remap move-beginning-of-line] + #'erc-fill--wrap-beginning-of-line) + ;; This is redundant anyway (right?). + (define-key map "\C-c\C-a" #'erc-fill-wrap-cycle-visual-movement) + ;; Not sure if this is dumb because `erc-bol' takes no args. + (define-key map [remap erc-bol] #'erc-fill--wrap-beginning-of-line) + map)) (define-erc-module fill-wrap nil "Fill style leveraging `visual-line-mode'. @@ -184,12 +258,14 @@ fill-wrap " ERC sessions. Add `fill' to `erc-modules' to avoid " " this warning. See Info:\"(erc) Modules\" for more."))) (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) (unless (eq erc-fill-function #'erc-fill-wrap) (setq-local erc-fill-function #'erc-fill-wrap)) (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) ((alist-get 'erc-fill-wrap-mode vars))) - (setq erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars) - erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars))) + (setq erc-fill--wrap-movement (alist-get 'erc-fill--wrap-movement vars) + erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) (when (eq erc-timestamp-use-align-to 'margin) (erc-timestamp--display-margin-mode +1)) (setq erc-fill--wrap-value @@ -199,6 +275,8 @@ fill-wrap (or erc-fill--wrap-prefix (list 'space :width erc-fill--wrap-value))) (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-movement) + (setq erc-fill--wrap-movement erc-fill-wrap-movement)) (when msg (erc-display-error-notice nil msg)))) ((when erc-timestamp--display-margin-mode @@ -207,6 +285,7 @@ fill-wrap (kill-local-variable 'erc-fill--wrap-prefix) (kill-local-variable 'erc-fill--wrap-value) (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-movement) (visual-line-mode -1)) 'local) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index a45f3531586..4994feefd4e 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -22,6 +22,7 @@ ;;; Code: (require 'ert) (require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' ;; These display-oriented tests are brittle because many factors ;; influence how text properties are applied. We should just -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From f7c371d3acd228a7684abd74b7785af8346915be Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 1/4] [5.6] Adjust some old text properties in ERC buffers TODO: because these have been around forever, we should mention their deletion in the misc-library section of ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Remove the confusing `rear-sticky' text property, which has been around since 2002. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. --- lisp/erc/erc.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 7f51b7bfb2e..f61804f41fd 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2868,7 +2868,6 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4297,7 +4296,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Leverage-display-properties-better-in-erc-stamp.patch From 29f82d69769ead2cdf7f51a6e1ebc0c6205c0a42 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 2/4] [5.6] Leverage display properties better in erc-stamp (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-timestamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el: New file. --- lisp/erc/erc-stamp.el | 66 ++++++++++-- test/lisp/erc/erc-stamp-tests.el | 178 +++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+), 8 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..e9592448a33 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -217,14 +217,44 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + A side effect of enabling this is that there will only be one space before a right timestamp in any saved logs." - :type 'boolean) + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.4.1")) ; FIXME update when merging + +;; If people want to use this directly, we can offer an option to set +;; the margin's width. +(define-minor-mode erc-timestamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'." + :interactive nil + (if-let ((erc-timestamp--display-margin-mode) + (width (if erc-timestamp-last-inserted-right + (length erc-timestamp-last-inserted-right) + (1+ (length (erc-format-timestamp + (current-time) + erc-timestamp-format-right)))))) + (progn + (setq right-margin-width width + right-fringe-width 0) + (unless noninteractive + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + (kill-local-variable 'right-margin-width) + (unless noninteractive + (set-window-margins nil nil) + (set-window-fringes nil nil)))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -243,6 +273,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -253,6 +284,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -304,12 +337,29 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..4994feefd4e --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,178 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert) +(require 'erc-stamp) +(require 'erc-goodies) ; for `erc-make-read-only' + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-timestamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one [" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;;; erc-stamp-tests.el ends here -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From 416daeebb12ea5ebe6317bd852ae9f9548036b40 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 3/4] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch From 491f9dbb42677bcbfa2f08aea5d165c52c0019b9 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 4/4] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill-wrap-mode, erc-fill--wrap-prefix, erc-fill--wrap-value, erc-fill--wrap-movement): New minor mode and variables to support it. (erc-fill-wrap-movement): New option to control how where `visual-line-mode' keys are active. (erc-fill--wrap-kill-line, erc-fill--wrap-beginning-of-line, erc-fill--wrap-end-of-line): New movement commands. (erc-fill-wrap-cycle-visual-movement): New command to cycle local value of `erc-fill-wrap-movement'. (erc-fill-wrap-mode-map): New map based on `visual-line-mode-map'. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. --- lisp/erc/erc-common.el | 1 + lisp/erc/erc-fill.el | 238 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 237 insertions(+), 2 deletions(-) diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 994555acecf..aae8280baa9 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -95,6 +95,7 @@ erc--features-to-modules (erc-join autojoin) (erc-page page ctcp-page) (erc-sound sound ctcp-sound) + (erc-fill fill-wrap) (erc-stamp stamp timestamp) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..6a461786be1 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -79,16 +79,27 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, courtesy of `visual-line-mode' mode, which ERC +automatically enables when this option is `erc-fill-wrap' or +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) (defcustom erc-fill-static-center 27 "Column around which all statically filled messages will be centered. This column denotes the point where the ` ' character between <nickname> and the entered text will be put, thus aligning nick -names right and text left." +names right and text left. + +Also used by the `erc-fill-function' variant `erc-fill-wrap' for +its initial leading \"prefix\" width." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +166,229 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) +(defvar-local erc-fill--wrap-prefix nil) +(defvar-local erc-fill--wrap-value nil) +(defvar-local erc-fill--wrap-movement nil) + +(defcustom erc-fill-wrap-movement t + "Whether to override keys defined by `visual-line-mode'. +A value of `display' means to favor default `erc-mode' keys when +point is in the input area." + :package-version '(ERC . "5.5") ; FIXME sync on release + :type '(choice boolean (const display :tag "Display area" + :doc "Use `erc-mode' keys in input area"))) + +(defun erc-fill--wrap-kill-line (arg) + "Defer to `kill-line' or `kill-visual-line'." + (interactive "P") + ;; ERC buffers are read-only outside of the input area, but users + ;; still need to see the message. + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (kill-line arg) + (kill-visual-line arg))) + ('t (kill-visual-line arg)) + (_ (kill-line arg)))) + +(defun erc-fill--wrap-beginning-of-line (arg) + "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." + (interactive "^p") + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (move-beginning-of-line arg) + (beginning-of-visual-line arg))) + ('t (beginning-of-visual-line arg)) + (_ (move-beginning-of-line arg))) + (when (get-text-property (point) 'erc-prompt) + (goto-char erc-input-marker))) + +(defun erc-fill--wrap-end-of-line (arg) + "defer to `move-end-of-line' or `end-of-visual-line'." + (interactive "^p") + (pcase erc-fill--wrap-movement + ('display (if (>= (point) erc-input-marker) + (move-end-of-line arg) + (end-of-visual-line arg))) + ('t (end-of-visual-line arg)) + (_ (move-end-of-line arg)))) + +(defun erc-fill-wrap-cycle-visual-movement (arg) + "Cycle through `erc-fill-wrap-movement' styles ARG times. +Go from nil to t to `display' and back around, but set internal +state instead of mutating `erc-fill-wrap-movement'. When ARG is +0, reset to value of `erc-fill-wrap-movement'." + (interactive "^p") + (when (zerop arg) + (setq erc-fill--wrap-movement erc-fill-wrap-movement)) + (while (not (zerop arg)) + (cl-incf arg (- (abs arg))) + (setq erc-fill--wrap-movement (pcase erc-fill--wrap-movement + ('nil t) + ('t 'display) + ('display nil)))) + (message "erc-fill-wrap-movement: %S" erc-fill--wrap-movement)) + +;; We could just override `visual-line-mode-map' locally, but that +;; seems pretty hacky. +(defvar erc-fill-wrap-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map visual-line-mode-map) + (define-key map [remap kill-line] #'erc-fill--wrap-kill-line) + (define-key map [remap move-end-of-line] #'erc-fill--wrap-end-of-line) + (define-key map [remap move-beginning-of-line] + #'erc-fill--wrap-beginning-of-line) + ;; This is redundant anyway (right?). + (define-key map "\C-c\C-a" #'erc-fill-wrap-cycle-visual-movement) + ;; Not sure if this is dumb because `erc-bol' takes no args. + (define-key map [remap erc-bol] #'erc-fill--wrap-beginning-of-line) + map)) + +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + (concat "WARNING: enabling default global module `fill' needed " + " by local module `fill-wrap'. This will impact all" + " ERC sessions. Add `fill' to `erc-modules' to avoid " + " this warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + ;; Set local value of user option (can we avoid this somehow?) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-movement (alist-get 'erc-fill--wrap-movement vars) + erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars) + erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars))) + (when (eq erc-timestamp-use-align-to 'margin) + (erc-timestamp--display-margin-mode +1)) + (setq erc-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center) + ;; + erc-fill--wrap-prefix + (or erc-fill--wrap-prefix + (list 'space :width erc-fill--wrap-value))) + (visual-line-mode +1) + (unless (local-variable-p 'erc-fill--wrap-movement) + (setq erc-fill--wrap-movement erc-fill-wrap-movement)) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-timestamp--display-margin-mode + (erc-timestamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-prefix) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (kill-local-variable 'erc-fill--wrap-movement) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of perceived nickname. +It should return an integer representing the length of the +nickname, including any enclosing brackets, or nil, to fall back +to the default behavior of taking the length from the first word.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn (skip-syntax-forward "^-") + (- (point) (point-min)))))) + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width ,(- erc-fill--wrap-value 1 len)) + ,erc-fill--wrap-prefix))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +Reset prefix to VALUE, when given." + (save-excursion + (when value + (setq erc-fill--wrap-value value + erc-fill--wrap-prefix (list 'space :width value))) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (pos-bol) (pos-eol)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (save-excursion + (save-restriction + (widen) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t) ; necessary? + (p (goto-char (point-min)))) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf (caddr erc-fill--wrap-prefix) arg) + (cl-incf erc-fill--wrap-value arg) + (while (setq p (next-single-property-change p 'line-prefix)) + (when-let ((v (get-text-property p 'line-prefix))) + (cl-incf (caddr v) arg) + (when-let + ((e (text-property-not-all p (point-max) 'line-prefix v))) + (goto-char e))))))) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. Note that misalignment may occur when +messages contain decorations applied by third-party modules. +See `erc-fill--wrap-fix' for a workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (let ((total (erc-fill--wrap-nudge arg)) + (start (window-start)) + (marker (set-marker (make-marker) (point)))) + (when (zerop arg) + (setq arg 1)) + (set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?= ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (set-window-start (selected-window) start) + (goto-char marker))))) + map) + t + (lambda () + (set-marker marker nil) + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (goto-char marker) + (set-window-start (selected-window) start))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." (fill-region (point-min) (point-max) t t) -- 2.38.1 --=-=-=--
Received: (at 60936) by debbugs.gnu.org; 18 Jan 2023 15:01:53 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jan 18 10:01:53 2023 Received: from localhost ([127.0.0.1]:41543 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pI9wn-0005b6-87 for submit <at> debbugs.gnu.org; Wed, 18 Jan 2023 10:01:53 -0500 Received: from mail-108-mta22.mxroute.com ([136.175.108.22]:33071) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pI9wl-0005at-9M for 60936 <at> debbugs.gnu.org; Wed, 18 Jan 2023 10:01:52 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta22.mxroute.com (ZoneMTA) with ESMTPSA id 185c5666c9b000011e.001 for <60936 <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Wed, 18 Jan 2023 15:01:42 +0000 X-Zone-Loop: 002ed58c0ca0759576229d9b90aebdbcfbf2a6c13ef6 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=+O8CzjMpf/thR9maQ+kjE4vMUieXVxaxFltRDS2QOpg=; b=HKcCtvEg0kBfH3sGQKLXfh7BbX jr7ieyQmNO6vXqPtWOzFCXQUQvgtJlZ/FCzXSNq+wNrCQCgbV/GeNDMo+y6DqnurymRbudgMA2ttb zgQ/U06yGKhiezKGcZFig4L8pbRb11teMecMeWkqn7qFkRIuS0QtCLaEn2+hhwpjvs6QmuXrpevnE IEEBJrUEHEGUhm4igtMeXTxxAsTjuzaEaSZnufYyvw9xKltdLPxeBQlGsAks/0lGZWGQAElYpz9sk J6MM22pu6056+nmRo+G5JREcdu0ZLCg8kKmIL6Ae5lbUmkz4exbw1Zjh/HVDgfyvqdH67Qpp7Q1SX AvGGlmQw==; From: "J.P." <jp@HIDDEN> To: 60936 <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <87tu0nao77.fsf@HIDDEN> (J. P.'s message of "Wed, 18 Jan 2023 06:53:48 -0800") References: <87tu0nao77.fsf@HIDDEN> Date: Wed, 18 Jan 2023 07:01:39 -0800 Message-ID: <87bkmvanu4.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 60936 Cc: emacs-erc@HIDDEN X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -1.0 (-) Brief demo (video/webm): https://debbugs.gnu.org/cgi/bugreport.cgi?filename=wrap_demo.webm;msg=6;bug=60936;att=1
bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.Received: (at 60936-quiet) by debbugs.gnu.org; 18 Jan 2023 14:58:17 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jan 18 09:58:17 2023 Received: from localhost ([127.0.0.1]:41531 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pI9tJ-0005Tj-Jn for submit <at> debbugs.gnu.org; Wed, 18 Jan 2023 09:58:17 -0500 Received: from mail-108-mta193.mxroute.com ([136.175.108.193]:42935) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pI9tG-0005TT-RC for 60936-quiet <at> debbugs.gnu.org; Wed, 18 Jan 2023 09:58:15 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta193.mxroute.com (ZoneMTA) with ESMTPSA id 185c56318e1000011e.001 for <60936-quiet <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Wed, 18 Jan 2023 14:58:04 +0000 X-Zone-Loop: 270d8c855336140cd8dcef8aadb269ce572c19286f70 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:To:From:Sender:Reply-To:Cc: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=GX++fUqAYj+Y685EkDDIWEFNieVxzMsHzriyO6cVfkU=; b=WRZhdmuLlKX23uh+t3l+rdT+LL 1BqZ7tttjijzenQ5y/utJ2SaE/U4fN8NMjXFXfQBxJo//EdKFZVQQ9LsiEbatGrKKxfIpXtW/vUHn rewM/Ygd8+BTReYMBzdnlyA3+6XdGc8Q8zHEnppm5HTVhmM1qiPuysHuUpoH2rUjyephhBsLUP8Tp upR6zUeCZ7mZqCOeJynzkx1IO/JRdX3cEoHWZb/TsiRxRt8YxFDQLFbA5VS/7QqS+7klhCCKtyVP3 3oENQRlAM9Qg+9R9kbMQkxwr0668ssErGejnJy7vIShSt1+8czYvpHF3eSwZKe2NBkN8zvgFaLG7C mTVYIhMA==; From: "J.P." <jp@HIDDEN> To: 60936-quiet <at> debbugs.gnu.org Subject: Re: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode In-Reply-To: <handler.60936.B.167405364619245.ack <at> debbugs.gnu.org> (GNU bug Tracking System's message of "Wed, 18 Jan 2023 14:55:02 +0000") References: <87tu0nao77.fsf@HIDDEN> <handler.60936.B.167405364619245.ack <at> debbugs.gnu.org> Date: Wed, 18 Jan 2023 06:57:57 -0800 Message-ID: <87mt6fao0a.fsf_-_@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN X-Debbugs-Envelope-To: 60936-quiet X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> --=-=-= Content-Type: text/plain Screenshot storage: --=-=-= Content-Type: video/webm Content-Disposition: attachment; filename=wrap_demo.webm Content-Transfer-Encoding: base64 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 --=-=-=--
Received: (at submit) by debbugs.gnu.org; 18 Jan 2023 14:54:06 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jan 18 09:54:06 2023 Received: from localhost ([127.0.0.1]:40005 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pI9pE-00050K-8Y for submit <at> debbugs.gnu.org; Wed, 18 Jan 2023 09:54:06 -0500 Received: from lists.gnu.org ([209.51.188.17]:43346) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pI9pB-0004zt-9g for submit <at> debbugs.gnu.org; Wed, 18 Jan 2023 09:54:03 -0500 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 <jp@HIDDEN>) id 1pI9pA-0000rr-Tu for bug-gnu-emacs@HIDDEN; Wed, 18 Jan 2023 09:54:00 -0500 Received: from mail-108-mta238.mxroute.com ([136.175.108.238]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <jp@HIDDEN>) id 1pI9p6-0005hm-Vc for bug-gnu-emacs@HIDDEN; Wed, 18 Jan 2023 09:54:00 -0500 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta238.mxroute.com (ZoneMTA) with ESMTPSA id 185c55f3b1c000011e.001 for <bug-gnu-emacs@HIDDEN> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Wed, 18 Jan 2023 14:53:50 +0000 X-Zone-Loop: c212311becb5345b165f876885012f326e10146e21a4 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:Subject:To:From:Sender: Reply-To:Cc:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=IQpZrkUQW/a9MLJdY2v6W8duyXffxJjcLlSWJiRvfOc=; b=SaP8tYw+iubLIst8IpnCS80L5V 3PCHGO1Iv6lF/OZXTQrvfoNiMILgzdC5fx9rSExVIXvRuvXNk8kLs6RxJvtVaSCqNMnlUCGLdWU4h EgxvBprELg7Y6B0RpgnVekRuzsYDPapmai3dv9TTVLAxqspSjTyTUKAbFjRwvwhBrnrWxfqkKAqIG G8tkC0Vy2q/zLSPx4yH8izfBB2UmrR0i0Gwe6aoA1vGNF10IMrRr/y8vIooG/yQmiJTcuKmOL2rU/ UltiOgQXJdpPbsoDx2p/WLHrxDQpBYWApimaHEAVRCv4Mzn5UD71ePlR/GNUzAgKNacHkRjLuYVgE 3ttGUUxw==; From: "J.P." <jp@HIDDEN> To: bug-gnu-emacs@HIDDEN Subject: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode X-Debbugs-CC: emacs-erc@HIDDEN Date: Wed, 18 Jan 2023 06:53:48 -0800 Message-ID: <87tu0nao77.fsf@HIDDEN> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Authenticated-Id: masked@HIDDEN Received-SPF: pass client-ip=136.175.108.238; envelope-from=jp@HIDDEN; helo=mail-108-mta238.mxroute.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.4 (-) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit <at> debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: <debbugs-submit.debbugs.gnu.org> List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe> List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/> List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org> List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help> List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe> Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> X-Spam-Score: -2.4 (--) --=-=-= Content-Type: text/plain Tags: patch This bug is broadly related to bug#51969: 29.0.50; Add command for refilling ERC buffers Hi people, Newcomers to ERC are sometimes disappointed to discover that messages are "filled" in the traditional sense, meaning white space is permanently added and removed to produce "folded" lines as if M-q'd in an editing mode. Unfortunately, much of IRC involves dealing with preformatted messages sent by bots or a server (think "figlet" banners in MOTD bursts or /msg NickServ help). While it's always been possible to turn off filling everywhere (`fill' is global module, remember), doing so necessarily means surrendering any and all filling, whose very purpose is to make it easy to distinguish between speakers at a glance. This patch aims to offer a compromise of sorts, assuming users are willing to tolerate some opinionated choices. The first is that, for now, per-message lefty timestamps are out. If you want timestamps, they must go on the right (except for the occasional dateline break). Moreover, right-hand timestamps basically look awful unless you accept a new paradigm that places them all in the right margin. (This can be toggled off when space is tight.) Yet another catch involves `visual-line-mode' itself, which is managed for you. Basically, users of modal editing packages may suffer from basic navigation issues without taking extra care to cope with its idiosyncrasies. An ancillary goal of this patch is to have this mode double as a reference implementation for a certain flavor of local module, namely one that's "tunably persistent" per buffer. Also on display will be an added degree of versatility in terms of activation. While users can still add `fill-wrap' to `erc-modules' or enable it manually via minor-mode toggle, they can also elect to allow the global `fill' module to control it transparently, as a child module, simply by setting `erc-fill-function' to `erc-fill-wrap'. If you'd like to try this, do the following after applying these patches and before connecting: (setopt erc-fill-function #'erc-fill-wrap erc-timestamp-user-align-to 'margin) Screenshots to follow (possibly). Thanks, J.P. P.S. These patches come bundled with the so-called "edge" edition of ERC, an alpha-quality hodgepodge of WIP patches available as an ELPA package ("https://emacs-erc.gitlab.io/bugs/archive/"). In GNU Emacs 30.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.24.35, cairo version 1.17.6) of 2023-01-17 built on localhost Repository revision: 281f48f19ecad706a639d57cb937afb0b97eded7 Repository branch: master Windowing system distributor 'The X.Org Foundation', version 11.0.12014000 System Description: Fedora Linux 36 (Workstation Edition) Configured using: 'configure --enable-check-lisp-object-type --enable-checking=yes,glyphs 'CFLAGS=-O0 -g3' PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig' Configured features: ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB Important settings: value of $LANG: en_US.UTF-8 value of $XMODIFIERS: @im=ibus locale-coding-system: utf-8-unix Major mode: Lisp Interaction Minor modes in effect: tooltip-mode: t global-eldoc-mode: t eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t tool-bar-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t line-number-mode: t indent-tabs-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t Load-path shadows: None found. Features: (shadow sort mail-extr emacsbug message mailcap yank-media puny dired dired-loaddefs rfc822 mml mml-sec epa derived epg rfc6068 epg-config gnus-util text-property-search mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils erc iso8601 time-date auth-source cl-seq eieio eieio-core cl-macs password-cache json subr-x map thingatpt pp format-spec cl-loaddefs cl-lib erc-backend erc-goodies erc-networks byte-opt gv bytecomp byte-compile erc-common erc-compat erc-loaddefs rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads dbusbind inotify lcms2 dynamic-setting system-font-setting font-render-setting cairo move-toolbar gtk x-toolkit xinput2 x multi-tty make-network-process emacs) Memory information: ((conses 16 64390 6319) (symbols 48 8639 0) (strings 32 23673 1623) (string-bytes 1 685926) (vectors 16 15259) (vector-slots 8 209777 7692) (floats 8 24 35) (intervals 56 232 0) (buffers 976 10)) --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Adjust-some-old-text-properties-in-ERC-buffers.patch From 9a619878c0f56c996fb2d7f5b6b63b03fb979071 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Thu, 16 Jun 2022 01:20:49 -0700 Subject: [PATCH 1/4] [5.6] Adjust some old text properties in ERC buffers TODO: because these have been around forever, we should mention their deletion in the misc-library section of ERC-NEWS for 5.6. * lisp/erc/erc.el (erc-display-message): Remove the confusing `rear-sticky' text property, which has been around since 2002. (erc-display-prompt): Make the `field' text property more meaningful to aid in searching, although this makes the `erc-prompt' property somewhat redundant. --- lisp/erc/erc.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ba7db15cf8c..ab2cd2be3a7 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2854,7 +2854,6 @@ erc-display-message (erc-display-line string buffer) (unless (erc-hide-current-message-p parsed) (erc-put-text-property 0 (length string) 'erc-parsed parsed string) - (erc-put-text-property 0 (length string) 'rear-sticky t string) (when (erc-response.tags parsed) (erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed) string)) @@ -4283,7 +4282,7 @@ erc-display-prompt (setq prompt (propertize prompt 'rear-nonsticky t 'erc-prompt t - 'field t + 'field 'erc-prompt 'front-sticky t 'read-only t)) (erc-put-text-property 0 (1- (length prompt)) -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Leverage-display-properties-better-in-erc-stamp.patch From f152137282edb9ecfab95ac647763b789c56e141 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Wed, 24 Nov 2021 05:35:35 -0800 Subject: [PATCH 2/4] [5.6] Leverage display properties better in erc-stamp (erc-timestamp-use-align-to): Enhance meaning of option to accept numeric value for dynamically aligned right-side stamps. Use `graphic-display-p' to determine default value even though, as stated in the manual, terminal Emacs also supports the "space" display spec. (erc-timestamp--display-margin-mode): Add internal minor mode to help other modules quickly ensure stamps are showing correctly. (erc-stamp--inherited-props): Add internal const to hold properties that should be inherited from message being inserted. (erc-insert-aligned): Deprecate function and remove from primary client code path. (erc-insert-timestamp-right): Account for new display-related values of `erc-timestamp-use-align-to'. * test/lisp/erc/erc-stamp-tests.el: New file. --- lisp/erc/erc-stamp.el | 66 ++++++++++-- test/lisp/erc/erc-stamp-tests.el | 177 +++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 test/lisp/erc/erc-stamp-tests.el diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..e9592448a33 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -217,14 +217,44 @@ erc-timestamp-right-column (integer :tag "Column number") (const :tag "Unspecified" nil))) -(defcustom erc-timestamp-use-align-to (eq window-system 'x) +(defcustom erc-timestamp-use-align-to (and (display-graphic-p) t) "If non-nil, use the :align-to display property to align the stamp. This gives better results when variable-width characters (like Asian language characters and math symbols) precede a timestamp. +This option only matters when `erc-insert-timestamp-function' is +set to `erc-insert-timestamp-right' or that option's default, +`erc-insert-timestamp-left-and-right'. If the value is a +positive integer, alignment occurs that many columns from the +right edge. If the value is `margin', the stamp appears in the +right margin when visible. + A side effect of enabling this is that there will only be one space before a right timestamp in any saved logs." - :type 'boolean) + :type '(choice boolean integer (const margin)) + :package-version '(ERC . "5.4.1")) ; FIXME update when merging + +;; If people want to use this directly, we can offer an option to set +;; the margin's width. +(define-minor-mode erc-timestamp--display-margin-mode + "Internal minor mode for built-in modules integrating with `stamp'." + :interactive nil + (if-let ((erc-timestamp--display-margin-mode) + (width (if erc-timestamp-last-inserted-right + (length erc-timestamp-last-inserted-right) + (1+ (length (erc-format-timestamp + (current-time) + erc-timestamp-format-right)))))) + (progn + (setq right-margin-width width + right-fringe-width 0) + (unless noninteractive + (set-window-margins nil left-margin-width width) + (set-window-fringes nil left-fringe-width 0))) + (kill-local-variable 'right-margin-width) + (unless noninteractive + (set-window-margins nil nil) + (set-window-fringes nil nil)))) (defun erc-insert-timestamp-left (string) "Insert timestamps at the beginning of the line." @@ -243,6 +273,7 @@ erc-insert-aligned If `erc-timestamp-use-align-to' is t, use the :align-to display property to get to the POSth column." + (declare (obsolete "inlined and removed from client code path" "30.1")) (if (not erc-timestamp-use-align-to) (indent-to pos) (insert " ") @@ -253,6 +284,8 @@ erc-insert-aligned ;; Silence byte-compiler (defvar erc-fill-column) +(defvar erc-stamp--inherited-props '(line-prefix wrap-prefix)) + (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. STRING is the timestamp to insert. This function is a possible @@ -304,12 +337,29 @@ erc-insert-timestamp-right ;; some margin of error if what is displayed on the line differs ;; from the number of characters on the line. (setq col (+ col (ceiling (/ (- col (- (point) (line-beginning-position))) 1.6)))) - (if (< col pos) - (erc-insert-aligned string pos) - (newline) - (indent-to pos) - (setq from (point)) - (insert string)) + ;; For compatibility reasons, the `erc-timestamp' field includes + ;; intervening white space unless a hard break is warranted. + (pcase erc-timestamp-use-align-to + ((and 't (guard (< col pos))) + (insert " ") + (put-text-property from (point) 'display `(space :align-to ,pos))) + ((pred integerp) ; (cl-type (integer 0 *)) + (insert " ") + (when (eq ?\s (aref string 0)) + (setq string (substring string 1))) + (let ((s (+ erc-timestamp-use-align-to (string-width string)))) + (put-text-property from (point) 'display + `(space :align-to (- right ,s))))) + ('margin + (put-text-property 0 (length string) + 'display `((margin right-margin) ,string) + string)) + ((guard (>= col pos)) (newline) (indent-to pos) (setq from (point))) + (_ (indent-to pos))) + (insert string) + (dolist (p erc-stamp--inherited-props) + (when-let ((v (get-text-property (1- from) p))) + (put-text-property from (point) p v))) (erc-put-text-property from (point) 'field 'erc-timestamp) (erc-put-text-property from (point) 'rear-nonsticky t) (when erc-timestamp-intangible diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el new file mode 100644 index 00000000000..a45f3531586 --- /dev/null +++ b/test/lisp/erc/erc-stamp-tests.el @@ -0,0 +1,177 @@ +;;; erc-stamp-tests.el --- Tests for erc-stamp. -*- 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/>. + +;;; Commentary: + +;;; Code: +(require 'ert) +(require 'erc-stamp) + +;; These display-oriented tests are brittle because many factors +;; influence how text properties are applied. We should just +;; rework these into full scenarios. + +(defun erc-stamp-tests--insert-right (test) + (let ((val (list 0 0)) + (erc-insert-modify-hook '(erc-add-timestamp)) + (erc-insert-post-hook '(erc-make-read-only)) ; see comment above + (erc-timestamp-only-if-changed-flag nil) + ;; + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (advice-add 'erc-format-timestamp :filter-args + (lambda (args) (cons (cl-incf (cadr val) 60) (cdr args))) + '((name . ert-deftest--erc-timestamp-use-align-to))) + + (with-current-buffer (get-buffer-create "*erc-stamp-tests--insert-right*") + (erc-mode) + (erc-munge-invisibility-spec) + (setq erc-server-process (start-process "p" (current-buffer) + "sleep" "1") + erc-input-marker (make-marker) + erc-insert-marker (make-marker)) + (set-process-query-on-exit-flag erc-server-process nil) + (set-marker erc-insert-marker (point-max)) + (erc-display-prompt) + + (funcall test) + + (when noninteractive + (kill-buffer))) + + (advice-remove 'erc-format-timestamp + 'ert-deftest--erc-timestamp-use-align-to))) + +(ert-deftest erc-timestamp-use-align-to--nil () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("nil, normal") + (let ((erc-timestamp-use-align-to nil)) + (erc-display-message nil 'notice (current-buffer) "begin")) + (goto-char (point-min)) + (should (search-forward-regexp + (rx "begin" (+ "\t") (* " ") " [") nil t)) + ;; Field includes intervening spaces + (should (eql ?n (char-before (field-beginning (point))))) + ;; Timestamp extends to the end of the line + (should (eql ?\n (char-after (field-end (point)))))) + + ;; The option `erc-timestamp-right-column' is normally nil by + ;; default, but it's a convenient stand in for a sufficiently + ;; small `erc-fill-column' (we can force a line break without + ;; involving that module). + (should-not erc-timestamp-right-column) + + (ert-info ("nil, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to nil) + (erc-timestamp-right-column 20)) + (erc-display-message nil 'notice (current-buffer) + "twenty characters")) + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field excludes leading whitespace (arguably undesirable). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + ;; Timestamp extends to the end of the line. + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--t () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("t, normal") + (let ((erc-timestamp-use-align-to t)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Exactly two spaces, one from format, one added by erc-stamp. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("t, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to t) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; Indented to pos (this is arguably a bug). + (should (search-forward-regexp (rx bol (+ "\t") (* " ") " [") nil t)) + ;; Field starts *after* leading space (arguably bad). + (should (eql ?\[ (char-after (1+ (field-beginning (point)))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--integer () + (erc-stamp-tests--insert-right + (lambda () + + (ert-info ("integer, normal") + (let ((erc-timestamp-use-align-to 1)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added because included in format string. + (should (search-forward "msg one [" nil t)) + ;; Field covers space between. + (should (eql ?e (char-before (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("integer, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 1) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +(ert-deftest erc-timestamp-use-align-to--margin () + (erc-stamp-tests--insert-right + (lambda () + (erc-timestamp--display-margin-mode +1) + + (ert-info ("margin, normal") + (let ((erc-timestamp-use-align-to 'margin)) + (let ((msg (erc-format-privmessage "bob" "msg one" nil t))) + (put-text-property 0 (length msg) 'wrap-prefix 10 msg) + (erc-display-message nil nil (current-buffer) msg))) + (goto-char (point-min)) + ;; Space not added (treated as opaque string). + (should (search-forward "msg one [" nil t)) + ;; Field covers stamp alone + (should (eql ?e (char-before (field-beginning (point))))) + ;; Vanity props extended + (should (get-text-property (field-beginning (point)) 'wrap-prefix)) + (should (get-text-property (1+ (field-beginning (point))) 'wrap-prefix)) + (should (get-text-property (1- (field-end (point))) 'wrap-prefix)) + (should (eql ?\n (char-after (field-end (point)))))) + + (ert-info ("margin, overlong (hard wrap)") + (let ((erc-timestamp-use-align-to 'margin) + (erc-timestamp-right-column 20)) + (let ((msg (erc-format-privmessage "bob" "tttt wwww oooo" nil t))) + (erc-display-message nil nil (current-buffer) msg))) + ;; No hard wrap + (should (search-forward "oooo [" nil t)) + ;; Field starts at leading space. + (should (eql ?\s (char-after (field-beginning (point))))) + (should (eql ?\n (char-after (field-end (point))))))))) + +;;; erc-stamp-tests.el ends here -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Convert-erc-fill-minor-mode-into-a-proper-module.patch From 3a73c80f3043b46398269b777c2ec545c9f38bf7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Sun, 24 Apr 2022 02:38:12 -0700 Subject: [PATCH 3/4] [5.6] Convert erc-fill minor mode into a proper module * lisp/erc/erc-fill.el (erc-fill-mode, erc-fill-enable, erc-fill-disable): Use API to create these. (erc-fill-static): Save restriction instead of caller's match data. --- lisp/erc/erc-fill.el | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e10b7d790f6..caf401bf222 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -38,30 +38,18 @@ erc-fill :group 'erc) ;;;###autoload(autoload 'erc-fill-mode "erc-fill" nil t) -(define-minor-mode erc-fill-mode - "Toggle ERC fill mode. -With a prefix argument ARG, enable ERC fill mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - +(define-erc-module fill nil + "Manage filling in ERC buffers. ERC fill mode is a global minor mode. When enabled, messages in the channel buffers are filled." - :global t - (if erc-fill-mode - (erc-fill-enable) - (erc-fill-disable))) - -(defun erc-fill-enable () - "Setup hooks for `erc-fill-mode'." - (interactive) - (add-hook 'erc-insert-modify-hook #'erc-fill) - (add-hook 'erc-send-modify-hook #'erc-fill)) - -(defun erc-fill-disable () - "Cleanup hooks, disable `erc-fill-mode'." - (interactive) - (remove-hook 'erc-insert-modify-hook #'erc-fill) - (remove-hook 'erc-send-modify-hook #'erc-fill)) + ;; FIXME ensure a consistent ordering relative to hook members from + ;; other modules. Ideally, this module's processing should happen + ;; after "morphological" modifications to a message's text but + ;; before superficial decorations. + ((add-hook 'erc-insert-modify-hook #'erc-fill) + (add-hook 'erc-send-modify-hook #'erc-fill)) + ((remove-hook 'erc-insert-modify-hook #'erc-fill) + (remove-hook 'erc-send-modify-hook #'erc-fill))) (defcustom erc-fill-prefix nil "Values used as `fill-prefix' for `erc-fill-variable'. @@ -130,7 +118,7 @@ erc-fill (defun erc-fill-static () "Fills a text such that messages start at column `erc-fill-static-center'." - (save-match-data + (save-restriction (goto-char (point-min)) (looking-at "^\\(\\S-+\\)") (let ((nick (match-string 1))) -- 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Add-erc-fill-style-based-on-visual-line-mode.patch From a108605cad5c054a68c0ddbe2f576094d6eaa526 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@HIDDEN> Date: Fri, 13 Jan 2023 00:00:56 -0800 Subject: [PATCH 4/4] [5.6] Add erc-fill style based on visual-line-mode * lisp/erc/erc-common.el (erc--features-to-modules): Add mapping for local module `fill-wrap'. * lisp/erc/erc-fill.el (erc-fill-function): Add new value, `erc-fill-wrap'. (erc-fill-static-center): Extend meaning of option to also affect `erc-wrap-mode'. (erc-fill-wrap-mode, erc-fill--wrap-prefix, erc-fill--wrap-value): New minor mode and variables to support it. (erc-fill-wrap): New function implementing `erc-fill-function' (behavioral) interface. (erc-fill-wrap-nudge, erc-fill--wrap-nudge): New command and helper for growing and shrinking visual fill prefix. --- lisp/erc/erc-common.el | 1 + lisp/erc/erc-fill.el | 159 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 9eb4f1a9000..456d2bc204d 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -96,6 +96,7 @@ erc--features-to-modules (erc-page page ctcp-page) (erc-sound sound ctcp-sound) (erc-stamp stamp timestamp) + (erc-fill fill-wrap) (erc-services services nickserv)) "Migration alist mapping a library feature to module names. Keys need not be unique: a library may define more than one diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index caf401bf222..95b388cbf84 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -79,16 +79,27 @@ erc-fill-function These two styles are implemented using `erc-fill-variable' and `erc-fill-static'. You can, of course, define your own filling function. Narrowing to the region in question is in effect while your -function is called." +function is called. + +A third style resembles static filling but \"wraps\" instead of +fills, courtesy of `visual-line-mode' mode, which ERC +automatically enables when this option is `erc-fill-wrap' or +`erc-fill-wrap-mode' is active. Set `erc-fill-static-center' to +your preferred initial \"prefix\" width. For adjusting the width +during a session, see the command `erc-fill-wrap-nudge'." :type '(choice (const :tag "Variable Filling" erc-fill-variable) (const :tag "Static Filling" erc-fill-static) + (const :tag "Dynamic word-wrap" erc-fill-wrap) function)) (defcustom erc-fill-static-center 27 "Column around which all statically filled messages will be centered. This column denotes the point where the ` ' character between <nickname> and the entered text will be put, thus aligning nick -names right and text left." +names right and text left. + +Also used by the `erc-fill-function' variant `erc-fill-wrap' for +its initial leading \"prefix\" width." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 @@ -155,6 +166,150 @@ erc-fill-variable (erc-fill-regarding-timestamp)))) (erc-restore-text-properties))) +(defvar-local erc-fill--wrap-prefix nil) +(defvar-local erc-fill--wrap-value nil) + +(define-erc-module fill-wrap nil + "Fill style leveraging `visual-line-mode'. +This local module depends on the global `fill' module. To use +it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. You can also manually +invoke one of the minor-mode toggles." + ((let (msg) + (unless erc-fill-mode + (unless (memq 'fill erc-modules) + (setq msg + (concat "WARNING: enabling default global module `fill' needed " + " by local module `fill-wrap'. This will impact all" + " ERC sessions. Add `fill' to `erc-modules' to avoid " + " this warning. See Info:\"(erc) Modules\" for more."))) + (erc-fill-mode +1)) + (unless (eq erc-fill-function #'erc-fill-wrap) + (setq-local erc-fill-function #'erc-fill-wrap)) + (when-let* ((vars (or erc--server-reconnecting erc--target-priors)) + ((alist-get 'erc-fill-wrap-mode vars))) + (setq erc-fill--wrap-value (alist-get 'erc-fill--wrap-value vars) + erc-fill--wrap-prefix (alist-get 'erc-fill--wrap-prefix vars))) + (when (eq erc-timestamp-use-align-to 'margin) + (erc-timestamp--display-margin-mode +1)) + (setq erc-fill--wrap-value + (or erc-fill--wrap-value erc-fill-static-center) + ;; + erc-fill--wrap-prefix + (or erc-fill--wrap-prefix + (list 'space :width erc-fill--wrap-value))) + (visual-line-mode +1) + (when msg + (erc-display-error-notice nil msg)))) + ((when erc-timestamp--display-margin-mode + (erc-timestamp--display-margin-mode -1)) + (kill-local-variable 'erc-button--add-nickname-face-function) + (kill-local-variable 'erc-fill--wrap-prefix) + (kill-local-variable 'erc-fill--wrap-value) + (kill-local-variable 'erc-fill-function) + (visual-line-mode -1)) + 'local) + +(defvar-local erc-fill--wrap-length-function nil + "Function to determine length of perceived nickname. +It should return an integer representing the length of the +nickname, including any enclosing brackets, or nil, to fall back +to the default behavior of taking the length from the first word.") + +(defun erc-fill-wrap () + "Use text props to mimic the effect of `erc-fill-static'. +See `erc-fill-wrap-mode' for details." + (unless erc-fill-wrap-mode + (erc-fill-wrap-mode +1)) + (save-excursion + (goto-char (point-min)) + (let ((len (or (and erc-fill--wrap-length-function + (funcall erc-fill--wrap-length-function)) + (progn (skip-syntax-forward "^-") + (- (point) (point-min)))))) + (erc-put-text-properties (point-min) (point-max) + '(line-prefix wrap-prefix) nil + `((space :width ,(- erc-fill--wrap-value 1 len)) + ,erc-fill--wrap-prefix))))) + +;; This is an experimental helper for third-party modules. You could, +;; for example, use this to automatically resize the prefix to a +;; fraction of the window's width on some event change. + +(defun erc-fill--wrap-fix (&optional value) + "Re-wrap from `point-min' to `point-max'. +Reset prefix to VALUE, when given." + (save-excursion + (when value + (setq erc-fill--wrap-value value + erc-fill--wrap-prefix (list 'space :width value))) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t)) + (goto-char (point-min)) + (while (and (zerop (forward-line)) + (< (point) (min (point-max) erc-insert-marker))) + (save-restriction + (narrow-to-region (pos-bol) (pos-eol)) + (erc-fill-wrap)))))) + +(defun erc-fill--wrap-nudge (arg) + (save-excursion + (save-restriction + (widen) + (let ((inhibit-field-text-motion t) + (inhibit-read-only t) ; necessary? + (p (goto-char (point-min)))) + (when (zerop arg) + (setq arg (- erc-fill-static-center erc-fill--wrap-value))) + (cl-incf (caddr erc-fill--wrap-prefix) arg) + (cl-incf erc-fill--wrap-value arg) + (while (setq p (next-single-property-change p 'line-prefix)) + (when-let ((v (get-text-property p 'line-prefix))) + (cl-incf (caddr v) arg) + (when-let + ((e (text-property-not-all p (point-max) 'line-prefix v))) + (goto-char e))))))) + arg) + +(defun erc-fill-wrap-nudge (arg) + "Adjust `erc-fill-wrap' by ARG columns. +Offer to repeat command in a manner similar to +`text-scale-adjust'. Note that misalignment may occur when +messages contain decorations applied by third-party modules. +See `erc-fill--wrap-fix' for a workaround." + (interactive "p") + (unless erc-fill--wrap-value + (cl-assert (not erc-fill-wrap-mode)) + (user-error "Minor mode `erc-fill-wrap-mode' disabled")) + (let ((total (erc-fill--wrap-nudge arg)) + (start (window-start)) + (marker (set-marker (make-marker) (point)))) + (when (zerop arg) + (setq arg 1)) + (set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?+ ?= ?- ?0)) + (let ((a (pcase key + (?0 0) + (?- (- (abs arg))) + (_ (abs arg))))) + (define-key map (vector (list key)) + (lambda () + (interactive) + (cl-incf total (erc-fill--wrap-nudge a)) + (set-window-start (selected-window) start) + (goto-char marker))))) + map) + t + (lambda () + (set-marker marker nil) + (message "Fill prefix: %d (%+d col%s)" + erc-fill--wrap-value total (if (> (abs total) 1) "s" ""))) + "Use %k for further adjustment" + 1) + (goto-char marker) + (set-window-start (selected-window) start))) + (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." (fill-region (point-min) (point-max) t t) -- 2.38.1 --=-=-=--
"J.P." <jp@HIDDEN>
:emacs-erc@HIDDEN, bug-gnu-emacs@HIDDEN
.
Full text available.emacs-erc@HIDDEN, bug-gnu-emacs@HIDDEN
:bug#60936
; Package emacs
.
Full text available.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997 nCipher Corporation Ltd,
1994-97 Ian Jackson.