X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: emacs-erc@HIDDEN, bug-gnu-emacs@HIDDEN Resent-Date: Wed, 18 Jan 2023 14:55:02 +0000 Resent-Message-ID: <handler.60936.B.167405364619245 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: report 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN X-Debbugs-Original-To: bug-gnu-emacs@HIDDEN X-Debbugs-Original-Xcc: emacs-erc@HIDDEN Received: via spool by submit <at> debbugs.gnu.org id=B.167405364619245 (code B ref -1); Wed, 18 Jan 2023 14:55:02 +0000 Received: (at submit) by debbugs.gnu.org; 18 Jan 2023 14:54:06 +0000 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> 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-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 --=-=-=--
Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) Content-Type: text/plain; charset=utf-8 X-Loop: help-debbugs@HIDDEN From: help-debbugs@HIDDEN (GNU bug Tracking System) To: "J.P." <jp@HIDDEN> Subject: bug#60936: Acknowledgement (30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode) Message-ID: <handler.60936.B.167405364619245.ack <at> debbugs.gnu.org> References: <87tu0nao77.fsf@HIDDEN> X-Gnu-PR-Message: ack 60936 X-Gnu-PR-Package: emacs X-Gnu-PR-Keywords: patch Reply-To: 60936 <at> debbugs.gnu.org Date: Wed, 18 Jan 2023 14:55:02 +0000 Thank you for filing a new bug report with debbugs.gnu.org. This is an automatically generated reply to let you know your message has been received. Your message is being forwarded to the package maintainers and other interested parties for their attention; they will reply in due course. As you requested using X-Debbugs-CC, your message was also forwarded to emacs-erc@HIDDEN (after having been given a bug report number, if it did not have one). Your message has been sent to the package maintainer(s): bug-gnu-emacs@HIDDEN If you wish to submit further information on this problem, please send it to 60936 <at> debbugs.gnu.org. Please do not send mail to help-debbugs@HIDDEN unless you wish to report a problem with the Bug-tracking system. --=20 60936: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D60936 GNU Bug Tracking System Contact help-debbugs@HIDDEN with problems
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 18 Jan 2023 15:02:01 +0000 Resent-Message-ID: <handler.60936.B60936.167405411321524 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.167405411321524 (code B ref 60936); Wed, 18 Jan 2023 15:02:01 +0000 Received: (at 60936) by debbugs.gnu.org; 18 Jan 2023 15:01:53 +0000 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> 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-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
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 25 Jan 2023 14:12:01 +0000 Resent-Message-ID: <handler.60936.B60936.16746558903217 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16746558903217 (code B ref 60936); Wed, 25 Jan 2023 14:12:01 +0000 Received: (at 60936) by debbugs.gnu.org; 25 Jan 2023 14:11:30 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Fri, 27 Jan 2023 14:32:02 +0000 Resent-Message-ID: <handler.60936.B60936.167482992118774 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.167482992118774 (code B ref 60936); Fri, 27 Jan 2023 14:32:02 +0000 Received: (at 60936) by debbugs.gnu.org; 27 Jan 2023 14:32:01 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 31 Jan 2023 15:29:02 +0000 Resent-Message-ID: <handler.60936.B60936.167517893210232 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.167517893210232 (code B ref 60936); Tue, 31 Jan 2023 15:29:02 +0000 Received: (at 60936) by debbugs.gnu.org; 31 Jan 2023 15:28:52 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 01 Feb 2023 14:28:01 +0000 Resent-Message-ID: <handler.60936.B60936.167526167829701 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.167526167829701 (code B ref 60936); Wed, 01 Feb 2023 14:28:01 +0000 Received: (at 60936) by debbugs.gnu.org; 1 Feb 2023 14:27:58 +0000 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> 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-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 iVBORw0KGgoAAAANSUhEUgAAApIAAAGdCAYAAAChNpMuAAAABHNCSVQICAgIfAhkiAAAABl0RVh0 U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AACAASURBVHic7N13fFRV2sDx37T03iENQg+s NAWkqICswCoosvqqgAWQooKCssqCCOKiK6IILiIiilIUBMQGukjvAhKQnoR00vtk+rx/DBnIBpLJ ZDSU55vPfjbOueec5547YZ4599x7FdryMitCCCGEEELUkbqwqLihYxBCCCGEENchZUMHIIQQQggh rk+SSAohhBBCCKdUSSQtFssf2tkf3f71avLkyRw9erShwwDAbDbz6aefotfrXd62M8dfr9czevRo Ro8ezZAhQ66Zcbpceno633zzTUOHIYQQQvzp7Ink+fPnmTFjxh/W0R/dfkNLSkpi9erVALzxxhsN HI3z3nnnHXx9fXF3d3dpu84ef3d3d5YsWcKSJUto2rSpS2Ny1IkTJ5g2bRpPPfUUI0eOZP369VXK GzVqxMmTJ9m4cWODxCeEEEI0FHsiWVJS8od29Ee339AuXLhAeHg4AFbr9Xkh/M6dOzEYDDz44INX LE9JSSE/P9+ptq/n45+QkMDw4cP55JNPmDlzJqtWreL48eP2cpVKxQsvvMCmTZtIT09vwEiFEEKI P5e6qKiI6dOnU1JSQllZGaNHjwYgIiKC119/HbCd7vzqq6/Yvn07APHx8YwePRpPT08A8vPzWbhw IWlpaajVapo3b86wYcOIiIjAVe2/8cYbzJgxg6VLl/Lbb78RGxtrr18brVbL0qVLOXLkCGq1mrvv vpuhQ4eiVNry6MmTJzN+/HjWrl1LQkICERERvPTSS0RERDjU/vr169m8eTMajYaff/6ZlJQUPvnk E5566in7Njt27ODrr7+muLiYwMBAHnnkEbp06VIlxrfeeuuK/aemprJ27VrOnTtHWVkZnTt3Zvz4 8Wg0GpfEX2nDhg1MnDjxquXbt2+nefPmdO/evcrrNfXvyPGvr9rGx2g0snDhQk6fPk12djZKpZKg oCDGjh1L586dAdt7cNKkScTFxVUbg//7v/+z/x4VFUWrVq2qJcbu7u4MGTKE77//njFjxrhkv4QQ QohrnTIgIIAFCxYwZswY4uPj7acRL/+Qr5yBeffdd1m0aBHe3t4sX77cXv7ll18SHh7OkiVLWLRo Eb169bInga5oH6CwsJB33nmHbt268dFHH/H88887vJMLFixAoVCwZMkS5s2bx8GDB/n222+rbLNw 4UKGDh3Khx9+iL+/P2vWrHG4/QceeIDOnTszbdo0nn32Wfr06VMlidy1axfLly/n+eef59NPP2Xy 5MnV1iCuWrXqqv1nZWXRs2dPFixYwJIlS0hNTeXHH390WfwABQUFlJeXExMTU6d6tfXvyPGvr9rG Z/369ej1ej744AMWLFiARqPh/ffftyeRAAaDgQsXLpCamnrFPqxWK0VFRfzwww+UlpZy2223Vdum W7du7Nu3z2X7JYQQQlzrHLpq+7vvvmPEiBF4enqiUCgYOnQoBw4csJcHBwfz+++/8/vvv2OxWOja tSv+/v4OB1Fb+2CblXzooYfo3r07Hh4eBAcHO9R2eXk5e/fu5amnnkKlUuHj48Njjz3G5s2bq2w3 bNgwmjVrhq+vL7169arzKcr8/HyCgoIoKCioFts333zDiBEj7Gv8oqKi6NWrV5VtHn/88av237Vr V7p06YLBYCA1NZXIyEjOnj3r0vhzcnJo1KjRFctee+01Jk+ezJYtW+yJ8CeffOLS/uujtvFJTU2l Q4cOqFQqoqKi8PPzIzc3t0obnp6eLF26lDfffPOKfezbt48JEyawcuVKnnvuOfts5+V8fHzQ6/WY TCbX7qAQQghxjVLXtkFJSQkVFRXMnz+/yus+Pj723//+97/j4+PDZ599RkZGBrfddhsjRoxwKNlz pH2wfdC3a9eu1vb+V3Z2Nn5+fnh5edlfa9SoEdnZ2VW2U6svDYW/v3+dkoF58+Zx/PhxZs2aRXFx MWazmYCAAO666y4AMjMza53pq6n//Px8lixZQkVFBS1atECpVKLVal0WP4DJZEKlUl2x7LXXXgNg +fLlVzy17Yr+66O28enQoQObNm2iQ4cOnD17FovFQmRkZLV2/vc9d7nbb7+d22+/nQsXLvDvf/+b Bx54oNqXAbCtlzQajVXGQwghhLhR2T/t3NzcKC0trbaBr68vHh4ezJw5k9DQ0Cs2olQq+dvf/sbf /vY3ysrK+PDDD/nPf/7D9OnT7dvUp/36CAsLsyerlafbL1y4QFhYmMv6mDRpEq+//jrTp0/nq6++ on379rRq1cpeHh4eTkZGBk2aNHGq/blz53LffffZE7hffvnF5adQg4ODycvLc2mbl7va8a8rs9lc 7bXaxicyMhK1Ws0XX3yBl5cXs2fPvmLSrNVqcXNzqzEJjIiIoG/fvuzdu7daImk0GrFYLPb3mRBC CHGjs5/ajo6OJiUlxX7Kr7jY9uhEhULBgAEDWLRokX2Wp6ioiKSkJHsjX3zxhX1tmbe3N9HR0dWu XK5P+/Xh4+NDt27dWLZsGRaLBa1Wy8qVK+nXr59L2gfb/RErL9zJz88nJCSkSvmAAQNYvny5/XRv Tk4O69atc7j9nJwcFAoFYJvd3LRpk4sivyQiIgKtVkthYeFVt2nbtu0VZ/IccbXjX8lqtTJlypSr nloG25eCw4cPY7VaKSsrs79e2/j8/PPP9OnThxdffJHx48df8SIknU7HyJEjmTp1apXXy8rK+Pe/ /01mZiZgm+HetWsXLVq0qNbGkSNH6NChQ03DIIQQQtxQ7FMv4eHhjBgxgldeeQU3NzdCQ0N59dVX UalUDB8+nDVr1vDiiy+iUCjw8vLi4YcfJi4uDoAWLVrw8ccfk5ubi8VioXHjxowdO7ZKR/Vpv76e e+45Pv74Y0aPHo1KpaJ3797cf//9LmkbbIlvQEAAYLsoqPL3Sv369cNisTBnzhx0Oh3+/v4MHTrU 4fbHjBnDl19+yYoVK4iNjWXAgAHs3bvXZfGDLaHv378/69atY+TIkVfc5vKLU+qqpuNfSaVSsW/f PkpLS/H19a3WxsMPP8zbb7/NU089Rbt27Zg8eTJQ+/j06NGDmTNnsmLFCtzc3HB3d7ffGaByraNG oyEsLKzaOlEfHx+6dOnC+++/T05ODlarlT59+jB48OAq21mtVtatW8ewYcOcHiMhhBDieqPIyMi4 Pm96KFzObDYzZcoUHnvsMTp16vSn9280Ghk+fDiff/75FS9mcdbUqVMZO3asfZ1qYWEhU6ZMYdy4 cS7bz6+++oqcnByeffZZl7QnhBBCXA/kWdvCTqVSMX36dL799ts/5BGJtVmzZg09evRwaRJpNpvJ ysoiNzeXsrIytFotJ06cQKPR0LJlS5f0kZKSQkpKCuPGjXNJe0IIIcT1QmYkxTXh0KFDnDx5kkcf fdS+3tRVzp8/z3fffUdmZiYeHh60aNGCAQMGVFuCIIQQQoi6kURSCCGEEEI4RX2lixouV1u5EEII IYS4uSQkJACyRlIIIYQQQjhJEkkhhBBCCOEUSSSFEEIIIYRTJJEUQgghhBBOkURSCCGEEEI4RRJJ IYQQQgjhFEkkhRBCCCGEUySRFEIIIYQQTpFEUgghhBBCOEUSSSGEEEII4RRJJIUQQgghhFMkkRRC CCGEEE6RRFIIIYQQQjhFEkkhhBBCCOEUSSSFEEIIIYRTJJEUQgghhBBOkURSCCGEEEI4RRJJIYQQ QgjhFEkkhRBCCCGEUySRFEIIIYQQTpFEUgghhBBCOEUSSSGEEEII4RRJJIUQQgghhFMkkRRCCCGE EE6RRFIIIYQQQjhFEkkhhBBCCOEUSSSFEEIIIYRTJJEUQgghhBBOkURSCCGEEEI4RRJJIYQQQgjh FEkkhRBCCCGEUySRFEIIIYQQTpFEUgghhBBCOEUSSSGEEEII4RRJJIUQQgghhFMkkRRCCCGEEE6R RFIIIYQQQjhFEkkhhBBCCOEUSSSFEEIIIYRTJJEUQgghhBBOkURSCCGEEEI4RRJJIYQQQgjhFEkk hRBCCCGEUySRFEIIIYQQTpFEUgghhBBCOEUSSSGEEEII4RRJJIUQQgghhFMkkRRCCCGEEE6RRFII IYQQQjhFEkkhhBBCCOEUSSSFEEIIIYRTJJEUQgghhBBOkURSCCGEEEI4xeFEcjGLUVz2M5/5f0hA 5ZSjQEELWvwh7f+vfPJRoKANbf6U/q5Hj/BIlWN/lKMNHZIQQgghrgF1npEsoggTJiYwAYAoolCg oIQS+zanOY0CBUMZ6rpIazCc4VUSHQUKNGj+lL4dcYxjvMEbxBGHAgWnOV2n+t/wDT3piR9+tKY1 K1hRpbycckYxijDCiCOOf/EvrFgdqm/FynKW04Uu+OBDE5owgxlV6q9gBSZMbGazkyMghBBCiBtR nRNJNWpUqFCgAKAJTQBbglmplFIAoomuc0CV7Trjr/yVJy7+jGCE0+242jKWMZe5pJFW57oZZPAY j6FFy6M8Si65jGAEhzls32YsY1nGMh7gAdrSln/yTxaxyKH6WrS8yZtYsDCSkShQMItZLGGJvX0l SlQXf4QQQgghKtV7jWRlIllMMX3owyAG2RPJGGIAW2L5PM8TRRShhDKc4RRQYG/jFKfoSU/88Wcs Y51OJqcwhWUXf5ay1P56bf0DGDDwIA/ijz+96MU5zjkVw5XMYx6FFNKTnnWuG0kku9nNAQ7wIR8y nelYsPALvwBQQAErWclQhrKYxWxkI01owkIWOlTfG2+2s50DHGA+85nJTACSSXbR3gshhBDiRqWu bwOViWQuuexnP954209zV85IPs7jrGc9gxhEGGEsYxlatHzN15gwcT/3c5rT3MEdJJNc5bSqK9TU f6UkkogmmuY0Zxe7eJzH2c1ul8bhrPa0t/+uRw9AYxoDkEgiFiy0pz096UlHOnILt/AjP2LBghJl jfUBQgnlKEf5mZ9ZxCKiieYJnvgT9kwIIYQQ1zOXJZK72EU44SSTzHGOA7ZEMpVU1rOeKKIYxzgU KDjAATayESNGDnDAnkRuZztllOGLr1Ox3M3d9t/f4z0mMrHW/ivFEcc2tmHGjB9+7GEPhRQSSKDz g+NieeTxHu/RiEYMZjBwKTFUo6aCCnTo0KDBhAkzZpSXTTpfqX6ltaxlNrMBmMEMmtL0T9orIYQQ QlyvXJZIHuc4LWhBKaUkkADYTm1XXliSTjoDGFClbhllnOc8AG1pC9R/jWTlTFs88YBtprGm/iu5 4QaAChXNaU4CCeSRd80kkjp0PMRD5JHHt3yLN97ApZnFAgo4xCEA7uROwgircsHR1epXmslMnuEZ PuRDZjKTNNKqLA8QQgghhPhfLlsjeYITNKUpccRxjGNo0BBOuP02PnHEYcCA9bKfQAIJJxy4tCbv 8lnCurp8jWQ/+gHU2n+lytPpOnSkkIIKlX2NZ0PToeNBHmQrW1nCEvrT314WTTTBBNvXPJZRxkEO 0oEODtUH22yyEiURRDCMYQDsY9+fsGdCCCGEuJ7Ve0YyhhiUKDnFKcYyFiNGPuVT++uRRDKUoaxl LXdyJ3dzN2c4Q3e6M4EJdKc74YSziU30pz955Lliv+xq67/SGc4wlKFkk00xxTzGY7jj7pIY/sE/ sGAhkUQA3uItgglmDnNQ13IIyijjPu5jG9toRjMOc5jd7MYddxayEA0aRjOaN3mTYQwjjTQqqGA8 4x2qv5/93MEddKITHenIVrYC0JveLtl3IYQQQty46p1IuuFGIxqRQQZtaYsRIxYsVW79s4xlxBLL WtYyj3m0oQ2DGASAF16sYx3jGMd+9vMQD2HEiBZtfUNzqP9KwxlOJpkc4xgP8RALWOCy/ucxDxOm KvEAzGZ2rYnkIQ6xjW2A7cKayrh88LFfmf06r1NOOV/yJT748AEf2Pevtvqd6cwsZvE1X7OSlQQT zGQm8wZvuGz/hRBCCHFjUpSUlNR4ibSvr+3Cl8UsZixjKaOs2vo6cXPYwhbu5m5+47cqV4ILIYQQ 4uaSkGC7HqbOayR98PlDH5Eorj2Vj0i8/Kp4IYQQQgiHZySFEEIIIYSAesxICiGEEEIIAZJICiGE EEIIJ0kiKYQQQgghnCKJpBDiumA0WDh7shSj0dIg9YUQQlQniaQQN7HyMhPPPHaYWS+daOhQarXi 41Tem32Wrz9Pb5D6jjDoLTzz2GFem/S7S9q71o/Pwd0FPPPYYfv/vvos7U/t/1ofH3FzWMxiFJf9 XE93tam8K0vlz1GO1rkNSSSFaEBrlqfzzGOH+eXHHPtrny9O4ZnHDnNob2EDRnbtiY3zwsdPTXRT rwapL6prFO1J//sj6NAloF7t5GbrOXeqDIDD+wrR6cyuCE+IP1URRZgwVXlq3jGO8QZvEEccChSc 5rS9zIqV5SynC13wwYcmNGEGM+yPbK6Ld3nXngwe4pD99VxyeYiHCCSQMMIYxzgMGOzlK1iBCROb 2ezkXksiKYRdUaGR8jLTH1Z+JX0GhKFUKtj1i+3RoLoKM4f3FRIU4kbHen4414VC8ad15bTe/cN4 a9Et9Ogd0iD1G9K1enyiYjy57++NufX2oHq1c2hvIQd3F2A0WvhkYTLWOq4+uFbHR9xc1KhRoULB pTfkMpYxl7mkUX22XouWN3kTCxZGMhIFCmYxiyUsqbZtTcnlWc7yT/6JL9Vv1/gCL7CGNbzIiwxh CB/yYZUn9ylRorr446x6PyJRiBvFuhXpxMZ503dg2B9SfiXBoW507BrAob2FJJ0pJyOtAoPBYksw VbZ/jEpLTKxbkc7vv5Xg7q7ktp5BDHygEWqNgtRkLW9NO0W7jv6Me7EZpcVGXh5/jKhYT175VxuH 43BzU7JuRTq/7ilEpVYw7OlYWrW1/aN05EAhu37JIyOlArMF2rb34+EnovH0UrF1Uw5rP0/ngUci ufvecABWL0tj539zeWlmK5o090anM/PdmiyO7C/EZLIS396PocOj8PZx7J+f50YcwWK+9I9o//sj uO/vje3/XdP41Fa/vMzElDEJ3NEvFLVawaG9hag1Ch4bfWn/a4s/O1PHF0tSyUyr4JbO/nVOaqxW 2Lcjn62bcsjN1hMU4kavvqHcdU9ovY9Pbfvniv2vr/TUClKTtXj7qjl+pBi1RknuBT0xcV4NPj5C 1Ne8iz+96W1/XHElb7zZznaCCUaJks505nEeJ5nkKtsd4QgP8AAhhLCFLfjjby+zYOFJniSMMAYy kEUsqlL3LGcJJpgpTEGBgk/4hBRSXLqPMiMpbnonE0qo0JrRlpnRlpsoKjSSeLrMZeW16XcxAdu/ M5992/Px9FLR/S7brJnVCovnJXJgVwHNWnrjF6hh8zcXWL/Stev8UpO1HDtSjF+AhoI8A2svW0e4 b0cBuRf03NI5AB9fFQd3F/DtmkwAOnULRKGAY4eL7dsfP1JMUIgbTZrbHqW6fFEKWzflENPUi1tu DeDXPYWs/DjV4dgGPhDB3x5sxC2d/KuVOTI+NdWvtOPnXI7/Ztv//Nyq+19T/BazlcXzkkg6U0ZU rCf5uQasdTwr9d/vs/nioxRKiox07haIl5eK/Fx9lW2cPT6O7F999t8VPlmQzNFfi9izNY+P5ydj NFh4f87Za2p8hPijhBLKMY4xl7nMZCbRRPMET1TZZh3rSCGFQxyqlozOZz672c1/+A/qK8wNDmEI +eRzP/fzNm+jRMkwhrl0H2RGUtzUdDozG1ZnkJmmQ6GEc6fL2PzNBTrfHkizVj71LndEdBMvWrX1 Zf9O26m9ewZF4O5h+46Xmqwl+Ww50U28GDO5GQa9hRdHH2XnljweeCzKZeMQEKThn3PiAZg08jcu ZOqwWm2nDB9+Mho/Pw1qjYL0lArmTD3JqeOlAPgHaGgZ78vZk2WUl5kozDdSmG+wz04W5Bs4+msR AUEaet0dikIBKYnlJBwuxmy2olLVPn034IFGAOzZlk/CZQmrI+OjVitqrF/b/hcW1Bz/+cRysrN0 NG/twwvTW6LXWZg08jeHx91qhc3fXEClUvDSrNYEh7rZX3ckvtqOT23167v/jhy/2rz6djzTJhxn 1ISmnE8s59ypMkZNjLsmxkdOmYs/w1rWMpvZAMxgBk1pWqX87/ydr/maEELoTW/765WntB/ncQYy kB/5sVrbz/Eci1jEDxd/7uRO/sJfXBq/JJLipubhoeKVf7Vh88YLbPwyEzNWJv6zBS3jfV1S7qh+ 94az8K1zqNQK7rzslF1etm3mJSrWEwA3dyUh4e5kZ+ooyjdcsS1nuHuo7KeCvX3UlBQbsVqtKBQK SotNrF2ezunjJeh0tsVrxQWX+r719kBO/17KiYQSCnJtr3fuFghAfo4t/qICIx/8+1yVPvU6C17e zq/LgdrHJyTc3aF2rrb/tcVfub+Nomz91zXxKCsxUqE1ExCosSdJV2qnPsenpvr13f/6Hr/KpRgA b8+4dBHCx/OTGDUxrsHHRyGZpPgTzGQmz/AMH/IhM5lJGmksZam9/BZu4Xd+r7L2EuBjPqaCCj67 +FPpVm5lG9u4kzsZwAACCWQ963mf9/mUTxnDGJaz3GXxSyIpbnomk5X9Owro2iuYrIwKdm/Nq5II 1rfcEZWngYOC3fAP0NhfDw6zfXhmpFYAtnsh5mXrUakUBAS7YTDoACgpNl78/7pd7FMbXYWZ92af ISBQw/gpzWkc7cnL4xKqLPvu0CWQ1Z+mcTKhlMKLyVvMxSujQyM8AAgJc+fVufEumcG6XG3jU1+1 xe/rbztWladazea6ndf28dPg5q6kqNBIZloFjaNtCalBb8HNvfaVR44cn/pw9PhVxlpax/efl4+a x8c1YdUnqTz7cnPWrcigRWsfbr8zGLj2x0eI+trFLnrSkwgiGMYwZjKTfeyrsk3lGslQQtnCFvzw A6A//Qni0oVu3/ANe9nLszxLHHEkk8wOdvASL9GRjixjGbvZzXd859J9kERS3PQyUisICnXj0VEx lJWa+Pi9JCq0Zjy9VC4pr4/YOG+aNvcm+Vw5S+YnUVJkwmy2cudfbRcHBIW4oVYrSEvWsuDNs2Sk Vrj0dFxpiQmD3oJeZ+H3oyV8uyYLk8mKSn2pEy9vFfG3+HEioZiKcjN9/xZuLwsI1NCxSwBHDhTx 7utnaN3Ol5wsPXEtvbnrHscvSrqa2sanvmqLP66FN77+ak4cLWHhW+coL61bIqVQQO97wti88QIf vHWOdp38uZBu+3Lw/PSWtdZ35PjUh6PHLyrGE5VKQcKhIpZ/eB7/AA2D/y+y1vZVKgX+gRoCg9xo 1tIHk9FC89Y+hDe2JbDX+vgIUZt/8A8sWEgkEYC3eItggpnDHA5xiDu4g050oiMd2cpWgCqnr+HS GskUUtjKVgYz2L7d5dumk85e9vIETxBNNGWU4Ycfy1hGBBGUUcZZztKNbi7dR7nYRtz0YuO8ePYf zVGrFQQEanhxZqsqSWB9y+tDoYAxk+K4rXsQZ06UUZCn56+DIhjyqG19pIenigcejcLLW01BroHB D0faZ21cITTcnYFDGmE0Wji4q4C4Ft60/kv12dbbugdRWmzCZLLaT2tXGj6mCX0HhlFcaGTLDznk 5ujx9nXiO+wVrmKpbXxcoab43dyVPP18MyJjPDl/rpyYpl5ExtRt/O8d2ogHHonEzUPJgZ0FVFSY ua2nY7fTcfT41Icjx88/UMMjI2Pw8VNz7HAxqee1Dl90VFRgJCDINrNbVGjEP1BTpfxaHx8hajKP eVVu/1N5OyAzZjrTmVnMwoyZlazEgIHJTOYd3qnSxlCG0opWdKc7d3Knw3374MMP/EBrWjODGSxg AUMYwmpWu3QfFSUlJTX+ufv6yh+dEKLhfbsmk00bLjB0WBS9B9R/NlMIIVxhMYsZy1jKKMMb74YO xylb2MLd3M1v/EZ72jtUJyEhAZAZSSHENay8zMTCt87x1adp7Piv7abtLeT+fkKIa5APPtftIxLv 5m6n25AZSSHENSv5bDlfr0gnM62CgCA3+t0bbr8QQwghRMOpnJGURFIIIYQQQtSJnNoWQgghhBD1 IomkEEIIIYRwiiSSQggh/nBGg4WzJ0sxGi0NHYoQwoXkhuRCiBtWeZmJKWMSCG/swatvxzd0OHVW 3/j/6P0/uLuAT/9z3v7fd/41lIcej77itis+TuXg7gJ69Q3h/56KcXksQoiGITOSQjSgrHQdzzx2 mAVzztpf++dzx5g08rcGjOrak5ut59ypMgAO7ytEpzM3cESuY7XCT99mM3vKCV4cfZT/vH2OogLX PUf9j9Qo2pP+90fQoUtArdvGxnnh46cm+uLjM/9Mc3Ny8Tx6jBM63XXZvhDXMkkkhbioqNBIednV H3FX33LhvEN7Czm4uwCj0cInC5Ox1vHsqCsfG3k1jj7J5X+tWZ7Gj+uz6DMgjPEvNUevs/DZohTX BvcHiYrx5L6/N+bW22t/0kzv/mG8tegWevQO+RMiqypRb0Bnsf5hz9j+o9sX4lomp7aFuGjdinRi 47zpO/DKT02pb7mzcrP1rP08naQzZShVCmKbetH3b+G0unhjbp3OzHdrsjiyvxCTyUp8ez+GDo/C 28f25/3Duiy+/zqL199vx7ZNORzaW4jGTcm0f8ejVitqbb82pSUm1q1I5/ffSnB3V3JbzyAGPtAI tUZhP7V6Rz/bs68P7S1ErVHw2OhYh9tPT60gNVmLt6+a40eKUWuU5F7QExNnm9myWmHfjny2bsoh N1tPUIgbvfqGctc9ofY23NyUrFuRzq97ClGpFQx7+lL/Rw4UsuuXPDJSKjBboG17Px5+IhpPL5XD 8aed1/LRu0n4+KqZMLWFw4/IzMvWs3NLHo+OjLHfH3PgkEa8/6+z6HWXsmWzycqS95I4dbyUyBhP ho+JJTTcvdbxd6R+bWoaH0c8N+IIFvOlFKv//RHc9/fG9v+u7fjV9v6uyarCIkalpqO12May3ckz AERpNKS1awNAqdnC9KwLrC0qRm+11+4/dwAAIABJREFU0t/Pl/lRjQlS2fbvnF7PCxlZ7C4rR61Q cKuXJ5PDQunr6+OS9mdeyOa1rGxS2rbh/dw8VhcW4alU8HubVrj9Gd+AhKgnmZEUN72TCSVUaM1o y8xoy00UFRpJPF3msvL6Wr7oPMePFNP9rhB63BVCXq6B3Gz9ZeUpbN2UQ0xTL265NYBf9xSy8uPU au189sF5tm3OJSTMnUZRHqjVCofar4nVCovnJXJgVwHNWnrjF6hh8zcXWL8yvcp2O37O5fhvxfgF aMjPNbD28/SrtFjdJwuSOfprEXu25vHx/GSMBgvvX7YU4L/fZ/PFRymUFBnp3C0QLy8V+blV409N 1nLsiK3/gryq/e/bUUDuBT23dA7Ax1fFwd0FfLsms07x/3awiII8A6nJWs6edPzYnzlRiptGwW09 bDN6+bkGstJtp0dLi4327fJy9JSXmQgNdyfxdBnLF50HHB//q9V3hCPjU5OBD0TwtwcbcUsn/yuW 13b8HH1/X0m8hztTwkNp4uYGwPiQYF5rFM6ksEtfMh5PTWN+bh6dvTy539+PVYVFjE69NH6Pp6Tx XXEJI4ODGBUcRLLBQKLe4LL2Kw1LSeX93Dzi3N1o6+EhSaS4bsiMpLip6XRmNqzOIDNNh0IJ506X sfmbC3S+PZBmrXzqXe6SGCtssx2lJSY6dgmg//0RuLnbvgMW5Bs4+msRAUEaet0dikIBKYnlJBwu xmy2olJd+jDKzdHz2ry2BIW4Odx+bVKTtSSfLSe6iRdjJjfDoLfw4uij7NySxwOPRdm3CwjS8M85 tos9Jo38jQuZOqxWx045v/p2PNMmHGfUhKacTyzn3KkyRk2MA2yJ1OZvLqBSKXhpVmuCQ93sr1+u pv4ffjIaPz8Nao2C9JQK5kw9yanjpQ7XB+jUNZDfDhbh46OmZbzjxz03x0BwmDtqtYJvVmfw83fZ uHtUn+kLCXPn+WktsVisTB55lKSz5WjLzeRm6x0a/6vV9/KufVbRkfGpyYAHGgGwZ1s+CYeLq5TV dvzq8v6+kvaenrT39GRbaTnnDQbGhwbT1sPDXp5qMLK+qJgojYZxIcEogANaLRuLSzBarWgUCkrM tr+PXJOJBwP8mRYRhpdS6bL2KyXqDZyNb0WsW9W/TyGudZJIipuah4eKV/7Vhs0bL7Dxy0zMWJn4 zxa0jPd1SXltLn4eYblszZ/VAkrlpQ+YR0fFsHzxefbvzGf/znw8PFU8/EQ0XXoGkZ9jm7kpKjDy wb/PVWlbr7NUSRT69A+rlkTW1n5t8i7OXEbFegLg5q4kJNyd7EwdRfkGPC/27+6hsp9q9fZRU1Js xGq1oqglkywtNvLy+GMAvD3jtP31j+cnMWpiHGUlRiq0ZgICNfYkBKonqDX1X1psYu3ydE4fL0F3 8XRy8f9c7FJb/JExnkx7K77OazGNBgu+fmqys3T89G02fx8RTXQTT+bNOlNlO9XF2WOlUkFohDsZ qRWUlZocHv+r1XckkXRkfJxV2/Gry/vbGUkGW/vpRiMDEpOrxmaxEKhS8VFMFE+kpPFZQSGfFRTi p1KyMCqS4UGBLmm/0vNhIZJEiuuSJJLipmcyWdm/o4CuvYLJyqhg99a8KolgfctrEhBk++DITK/A arV9sBYXGWkc5WnfJiLSgxlz25KRWkHC4WK+X5vJl8tS6dIziNAI2+xHSJg7r86Nr3GGxsPzyh+6 NbVfm+AwW/wZqRWALTHKy9ajUikICHZDX8+rq7181Dw+rgmrPknl2Zebs25FBi1a+9jXE/r4aXBz V1JUaCQzrYLG0bZxM+gtDs2q6irMvDf7DAGBGsZPaU7jaE9eHpdQ54sm7Gsk/dRMnNriqmP9v4JD 3DhzotT+xcFktLB/Z0H1DS8GZDRaKMgzoFQqCAp2Q1tuu7ir1vG/Sv3aODo+lWNdWly3i81qO351 eX/XxFdliy9Jb6gyY9jC3bZONM7NjVPxrarMEFZq4+HO6fhWJFTo2FhcwoysCzyTllElkaxP+5X8 lLLSTFyfJJEUN72M1AqCQt14dFQMZaUmPn4viQqt2X4xQX3La+LuoaT1X3w5dayU2f84gU5r++C/ 5VbbejJtuZnXXzpBeGMPWsb7XDydqsD/YgIaEKihY5cAjhwo4t3Xz9C6nS85WXriWnpz1z21X/RT W/u1iY3zpmlzb5LPlbNkfhIlRSbMZit3/tV2cYpjKy2vTqVS4B+oITDIjWYtfTAZLTRv7UN4Y9uH tUIBve8JY/PGC3zw1jnadfLnwsU1hs9Pb1lr+6UlJgx6C3qdhd+PlvDtmixMJqt9Bs9RlWskC/IM nDlRxi2dr7we8H8Fh7uTm63HP0DDbT2C2PTNBbrdEcy/PvgLvn5qKi6+H3Iu6FgyP4nSYhMVWjO3 9QhCrVE4PP5Xq++q8YmK8USlUpBwqIjlH57HP0DD4P+LrLX92o5ffd/flW739uLb4hKeT89kW1k5 ZRYzi6OjiNRoGBrgz9qiYu48m8jdvr6c0evp7u3FhNAQCs1m4k+eprW7B719vTFf/PuIdNO4pH0h bgTyFUjc9GLjvHj2H81RqxUEBGp4cWarKklgfctrM2JME9rfGkBJkRGLBXrdHUr/wRGA7WrjgQ82 wmyy8MuPOWz/KZf49n48/Xycvf7wMU3oOzCM4kIjW37IITdHj7evY98RHWm/JgoFjJkUx23dgzhz ooyCPD1/HRTBkEejaq/soKICIwFBtg/uokIj/oFVP8TvHdqIBx6JxM1DyYGdBVRUmLnNgdlUgNBw dwYOaYTRaOHgrgLiWnjT+i+OzSZfrmPXQMIbeRDXwpsWbRxfI9nmL754eKjYvTWPJ8Y3Ye6S9gwd HoV/gKbK8oYuPYPQac1kplXQqVug/abfjo7/1erXxtHx8Q/U8MjIGHz81Bw7XEzqea3Dt0Oq7fjV 5/1daWJoCE8GB1JqsfBZQQEndXr7ldbLYqOZHBZKptHEvJxcEvV6QtS29r2USmZEhGOwWpiXk8cH eXn09/VhXdMmLmlfiBuBoqSkpMY/d1/fuv+jKoQQwjG7t+bx5bI07nuoMa3ifbmQqSMw2K1OCakQ QvzZEhISADm1LYQQDapH7xDc3VX89/tsfliXRWi4u/1KZyGEuNbJjKQQQgghhKiTyhlJWSMphBBC CCGcIomkEEIIIYRwiiSSQgghhBDCKZJIipuG3qTncNZvGMyueSqHEEIIcbOTRFJc1zYn/sztS++0 /++dvfOvuu2cXW/zzA8TeW/fwj8xQvFH0mq1NG3alKZNm+Lu7s6WLVsaOiQhhLipSCIprmtxgU15 ssMIeje5s9Zt24S2JsAjgFYhtT/x5M82NycXz6PHOKHTXZftNxQvLy+Sk5NJTk7mlltuaehwavTy yy+zevXqhg5DCCFcSu4jKa45y5Ytw8PDg0ceeaTWbVsENadFUHO2nt/O1vPba9z24bZDebjtUFeF affGG2/Qo0cP7rrrLqfbSNQb0FmsdX7G87XSvqhdQUEBWq22ocMQQgiXkhlJcc3Iysri3nvvZcuW LfTv39/++i/J25i4aTIDV97PPV/cx2vbZlNqKHO43Z7L+lQ5/f3RoaVVyq1Y+fbMD4xYP5I+n93D I1+PYM2Jr+3lWqOW9/YtYNCqBxmwYhAzt79Bib7EXv7QQw8xffp0XnjhBSoqKuq0z6sKi/A+epwP 8/IBaHfyDIojCUQfP2nfptRs4fn0TKKOnyT02AmGp6RRYDbby8/p9dyXdJ6ghN8JO3aCgYnJbCkt c1n7My9koziSQKrByIsZWUQdP0mLE6cwOPoMvBp07NiRnTt3AmAymTBf7Hfp0qWMHz/e/vprr71G q1ataNmyJU899RSlpaV16mfVqlV07NiRyMhIOnfuzMaNG+1lxcXFjBo1ipiYGJo1a8bs2bPtcWzf vp1BgwbRt29fmjdvznfffUdcXFyV96ej8Xl4eODp6Vm3ARJCiGucJJLimrB69Wr69u3LqFGj+OKL LwgMDLSXfX92E2nF6dwR04MAD382J/5cLRmsyVMdHmdUpyfpFdPjiuUrElbzr51vkVeRT9+4Pvi6 +ZJZmmUvn7X9X3z5+1pah7Tijthe/JT4X+bsette3qJFC7Zv307jxo25/fbb2b9/v8OxxXu4MyU8 lCZubgCMDwnmtUbhTAoLtW/zeGoa83Pz6Ozlyf3+fqwqLGJ0avql8pQ0visuYWRwEKOCg0g2GEjU G1zWfqVhKam8n5tHnLsbbT08cFMoqm1TV507d7bf1HbAgAE8++yzgO1Gtx07dgRg5syZ7Nixg0OH DnH69Gn8/f2ZOnWqw3189dVXvPLKKyxbtoyMjAxWrFhRZWZw9OjRKBQKEhMTOXjwIN9//z3z519a a/vTTz/x/vvv07VrV958800OHDjAgQMHSEtLq1N8Hh4eeHh41H2QhBDiGiantkWDW7p0KYsWLWLH jh2EhIRUK5/S/QUCPYNwU2k4m3+OERtGcjDjV4fbf6rj4wB8e+Z7dqburlJmxcpnR79ArVTz8X2L aOxrezSdxWoBILssm+0pOwnzDmVIm8EoUHAi9yQ7U3djsphQK21/QkqlkpdeeomBAwfSp08ffv75 Z4fW7LX39KS9pyfbSss5bzAwPjSYtpclG6kGI+uLionSaBgXEowCOKDVsrG4BKPVikahoMRsizXX ZOLBAH+mRYThpVS6rP1KiXoDZ+NbEXsxKXWFTp06kZCQgNlsRq/Xs2fPHgCOHj3K8OHDAViwYAGb Nm3Cx8f27OmpU6dy6623smDBAof6ePfdd5kzZw4dOnQAoHXr1rRu3RqAoqIi1q1bR35+PhqNhqCg IGbNmsWECROYNGkSAG3atKFt27a0aNGC+Ph4QkJCiImJISkpiejoaIfjk0RSCHEjkkRSNLh+/fqx YsUKpk2bxty5c+0fyJUKKgqZt28Bv2YeQmu0zSTlavNc0ndhRRFlhjJCvULsSSSAUmFLxDIuzkzm lOfywuYpVepWGCvwdb/0CNHU1FQmTpzIoEGDaNasmUviSzLoAUg3GhmQmFylrMxiIVCl4qOYKJ5I SeOzgkI+KyjET6VkYVQkw4MCr9Rknduv9HxYiEuTSLAlkl988QXHjh2jVatW7Ny5k4KCAk6ePEm7 du3Iy8ujpKSEJ598skq9oKAgh/s4e/Ysbdu2vWJZcnIyISEh+Pv7219r3rw5ycnJ1bZVXJZUV/5e l/iioqLqFLcQQlwPJJEUDS4mJoYtW7awYMECunbtysKFC+nduzcA5cZynvlhIiFeIcy75980C4xj 4MrB/O9lIx5q20xPQUVBnfoO9AzAU+1BrjaPxMIkmgXGAaAz6fBQexDtFwVAY9/GfDn0c/sM5P9a unQpc+fOZd68eQwYMKBOMQD4qmyJa5LeUGXGsIW7OwBxbm6cim9VZYawUhsPd07HtyKhQsfG4hJm ZF3gmbSMKolkfdqv5Kd0/UqY9u3bc+rUKfbs2UP37t3R6/WsW7eO8PBwPDw8cHd3x8fHh82bNxMT E1NjW0qlEpPJVO31Jk2acPr06SvOEMfGxpKXl0dpaSm+vrYvBUlJSTRp0sSh+IODgx2O7+mnn3ao TSGEuJ7IGklxTVAoFEyYMIENGzbw6quvsmHDBsA2Y1hh0qE1VbA3bR//+O9UjGZjtfotgpqhVqrZ mbqbWdv/xX8OLnasXxT8/eKV3C9seom3dr/DuO+f44XNL2HFSqh3CH2a3kVmaSbjvp/AksOfMH3r TL76/dLFONOnT2fbtm3s3bvXqSQS4HZvLwCeT89kckYWY9JsaxQjNRqGBviTZDBw59lEXs3K5v/O 29YqAhSazbQ5eZreZ5PYUFyM0WpFoVAQ6aZxSfuOslqt9OjRg6FD63ZVvKenJ5GRkaxfv54uXbrQ s2dPVq5caV8fqVAoGDt2LOPHj6e4uBiAnJwcjhw5Uq2t2NhYfvzxR6xWKwUFl75QjBs3jqlTp3Lq 1CkAUlJSePtt2xrXoKAgBg8ezJQpUzCbzRQXFzNjxgxGjhzpUPyOxme1WunatSvPPfdcncZHCCGu dZJIimtK5YUrXbp0ASDKL5KRHZ/AYDawKfFn2oW1o0vkrdXqhXiFMKXHZAI9AtiVtofT+WeqzVpe zdOdnuLZLmPx1Hiy6dxPlBnKuafZX7FevCp5Wq+XefQvD5OnzWPVsS/JKMkgwOPSqdAxY8bw+eef ExAQ4PR+TwwN4cngQEotFj4rKOCkTo/WYlv7uCw2mslhoWQaTczLySVRrydEbZsZ9VIqmRERjsFq YV5OHh/k5dHf14d1TZu4pP26UKlUrF+/nvz8/DrV69SpE/v376dNmzb07NmTbdu22RNJsN1eqUuX LnTr1o34+HgGDx5MZmZmtXamTZvGTz/9RExMTJWEbeTIkbz44osMGTKE2NhYHnzwQeLi4uzlS5cu RafTERcXR6dOnejXr599faQjHI1PCCFuRIqSkpIaP20rT/cIIURNdDodERERZGdn437xlLkQQogb U+UdN2RGUgjhEnPmzGHo0KGSRAohxE1EEkkhRL1t2rQJi8XC4sWOrU0VQghxY5BT20IIIYQQok7k 1LYQQgghhKgXSSSFEEIIIYRTJJEUQgghhBBOkURS3NCKCyvo0Wwej/710wapL/5YWq2Wpk2b0rRp U9zd3dmyZUtDhySEEDcVSSSFuAbMzcnF8+gxTuh012X7DcXLy4vk5GSSk5Ov+AjEa8nLL7/M6tWr GzoMIYRwKUkkxQ1n2bJlrFq16k/r74033mDbtm31aiNRb0BncfRZPNde+6J2BQUFaLXahg5DCCFc ShJJccPIysri3nvvZcuWLfTv379KmdFgZur4b/lr+4WMe/hL0lOK7GWF+VpmTf6RgZ3/w5BeS1j8 zm6MBrPD9R966CGmT5/OCy+8QEVFRZ1iXlVYhPfR43yYZ3usYLuTZ1AcSSD6+En7NqVmC8+nZxJ1 /CShx04wPCWNAvOl+M7p9dyXdJ6ghN8JO3aCgYnJbCktc1n7My9koziSQKrByIsZWUQdP0mLE6cw WOuflnbs2JGdO3cCYDKZMF/sd+nSpYwfP97++muvvUarVq1o2bIlTz31FKWlpXXqZ9WqVXTs2JHI yEg6d+7Mxo0b7WXFxcWMGjWKmJgYmjVrxuzZs+1xbN++nUGDBtG3b1+aN2/Od999R1xcXJX3l6Px eXh44OnpWbcBEkKIa5wkkuKGsHr1avr27cuoUaP44osvCAwMrFKemVZMSVEFUbEBJPyawewXNwFg sVh5ecw3bN5wkr/cGklwmA/L/7OfhXN2OFQfLj0fvHHjxtx+++3s37/f4bjjPdyZEh5KEzc3AMaH BPNao3AmhYXat3k8NY35uXl09vLkfn8/VhUWMTo1/VJ5ShrfFZcwMjiIUcFBJBsMJOoNLmu/0rCU VN7PzSPO3Y22Hh64KRQO7+fVdO7c2X4vsgEDBvDss88CtvuTVT5ve+bMmezYsYNDhw5x+vRp/P39 mTp1qsN9fPXVV7zyyissW7aMjIwMVqxYUWVmcPTo0SgUChITEzl48CDff/898+fPt5f/9NNPvP/+ +3Tt2pU333yTAwcOcODAAdLS0uoUn4eHBx4eHnUfJCGEuIapGzoAIepr6dKlLFq0iB07dhASEnLF bRpH+7Nw5UNYzFb6tV/AscOZlBbrSE8p4viRLFq1DeOtxYPRVRi5p8MHbFh5lGen3lFrfV9/W2Kg VCp56aWXGDhwIH369OHnn392aM1ee09P2nt6sq20nPMGA+NDg2l7WbKRajCyvqiYKI2GcSHBKIAD Wi0bi0swWq1oFApKzBYAck0mHgzwZ1pEGF5Kpcvar5SoN3A2vhWxF5NSV+jUqRMJCQmYzWb0ej17 9uwB4OjRowwfPhyABQsWsGnTJnx8fACYOnUqt956KwsWLHCoj3fffZc5c+bQoUMHAFq3bk3r1q0B KCoqYt26deTn56PRaAgKCmLWrFlMmDCBSZMmAdCmTRvatm1LixYtiI+PJyQkhJiYGJKSkoiOjnY4 PkkkhRA3IpmRFNe9fv364efnx7Rp0ygrK7viNho3FQBKlYKoWNtsZVFhBRmpxQA0b2ObofPw1BAZ G4DJZCEnq7TW+pdLTU1l4sSJDBo0iGbNmrlk35IMegDSjUYGJCbTPzGZhAodJquVMostgfwoJoqW 7u58VlDIoKTzNDp+gs8LCl3WfqXnw0JcmkTCpUTy2LFjtGrVCr1eT0FBASdPnqRdu3bk5eVRUlLC k08+SZs2bWjTpg133HEHQUFBDvdx9uxZ2rZte8Wy5ORkQkJC8Pf3t7/WvHlzkpOTq22ruCyprvy9 LvFFRUXVKW4hhLgeyIykuO7FxMSwZcsWFixYQNeuXVm4cCG9e/euso314no+g97EhYwSlCoFEY39 KC22JVLnTuUBoNeZyEgpQq1WEtbIF22Zocb6lZYuXcrcuXOZN28eAwYMqPM++Kps3+mS9IYqM4Yt 3N0BiHNz41R8qyozhJXaeLhzOr4VCRU6NhaXMCPrAs+kZTA86NLp/fq0X8lP6frvne3bt+fUqVPs 2bOH7t27o9frWbduHeHh4Xh4eODu7o6Pjw+bN28mJiamxraUSiUmk6na602aNOH06dNXnCGOjY0l Ly+P0tJS++Ngk5KSaNKkiUPxBwcHOxzf008/7VCbQghxPZEZSXFDUCgUTJgwgQ0bNvDqq6+yYcOG KuVpyYX885lvmTjia8pK9dx9b2s0bipa/yWcth0bcfp4Nv985lueH7EWk8nC4EdvQaNR1VofYPr0 6Wzbto29e/c6lUQC3O7tBcDz6ZlMzshiTJptjWKkRsPQAH+SDAbuPJvIq1nZ/N9521pFgEKzmTYn T9P7bBIbiosxWq0oFAoi3TQuad9RVquVHj16MHTo0DrV8/T0JDIykvXr19OlSxd69uzJypUr7esj FQoFY8eOZfz48RQX22aPc3JyOHLkSLW2YmNj+fHHH7FarRQUFNhfHzduHFOnTuXUqVMApKSk8Pbb bwMQFBTE4MGDmTJlCmazmeLiYmbMmMHIkSMdit/R+KxWK127duW5556r0/gIIcS1ThJJcUOpvPCl S5cuVV7vf3885aV6kk7n0WdgSybNsM1YKpUK3vxwMP0GtebwvjQuZJQyfGwXnnvlTofqA4wZM4bP P/+cgIAAp+OeGBrCk8GBlFosfFZQwEmdHu3FU8vLYqOZHBZKptHEvJxcEvV6QtS2kwleSiUzIsIx WC3My8njg7w8+vv6sK5pE5e0XxcqlYr169eTn59fp3qdOnVi//79tGnThp49e7Jt2zZ7Igm22yt1 6dKFbt26ER8fz+DBg8nMzKzWzrRp0/jpp5+IiYmpkrCNHDmSF198kSFDhhAbG8uDDz5IXFycvXzp 0qXodDri4uLo1KkT/fr1s6+PdISj8QkhxI1IUVJSUuM9PCpP9wghRE10Oh0RERFkZ2fjfvGUuRBC iBtT5R03ZEZSCOESc+bMYejQoZJECiHETUQSSSFEvW3atAmLxcLixYsbOhQhhBB/Ijm1LYQQQggh 6kRObQshhBBCiHqRRFIIIYQQQjhFEkkhhBBCCOEUSSSFuI6Vl5l45rHDzHrpREOH4hIGvYVnHjvM a5N+b+hQhBBCOEASSSGuAbnZes6dsj0n/PC+QnQ6cwNHJFzpv99n8/wTv5GVoWvoUIQQwqUkkRTi oqJCI+Vl1Z/V7KrymhzaW8jB3QUYjRY+WZiM1VK3+jU8IltcZK3x/hS1O/prEYlnypyqm5etx2i0 QD1jEEKIa03dn4MmxA1q3Yp0YuO86Tsw7A8pv5r01ApSk7V4+6o5fqQYtUZJ7gU9MXG252NbrbBv Rz5bN+WQm60nKMSNXn1DueueUHsbbm5K1q1I59c9hajUCoY9HUurtrZbdx05UMiuX/LISKnAbIG2 7f14+IloPL1UlJeZmDImgTv6haJWKzi0txC1RsFjoy/Vr8n6lRns3JLLXX8NY8/2PIY8GsV/v8/G YrYy+bVWeHqpKC0xsW5FOr//VoK7u5LbegYx8IFGqDW27Dc7U8cXS1LJTKvgls7+1ZJinc7Md2uy OLK/EJPJSnx7P4YOj8Lbx/bPV262nrWfp5N0pgylSkFsUy/6/i28Svxp57V89G4SPr5qJkxtgaeX irr6YV0WTZt706ylj/212sbv1z2FrFiSgsFg+2Yw+x+2JQgBQRreWPCXOscghBDXGpmRFDe9kwkl VGjNaMvMaMtNFBUaSTxd5rLy2nyyIJmjvxaxZ2seH89Pxmiw8P6cs/by/36fzRcfpVBSZKRzt0C8 vFTk5+qrtJGarOXYkWL8AjQU5BlY+3m6vWzfjgJyL+i5pXMAPr4qDu4u4Ns1VZ8FvePnXI7/Zquf n1u1fm30OgtHDhSi01r4/KMUzGYrWRk6Ek+XYbXC4nmJHNhVQLOW3vgFatj8zQXWr7S1bzFbWTwv iaQzZUTFepKfa6g2c7h8UQpbN+UQ09SLW24N4Nf/Z++8w6K6tof9DjAUASlSBWkiTa8V7GJiicYb y41+GkuKLRrN1ZjqtSTqtaSYqvfmZ6LJ1VgSNWosUSwRS4JK1EAURSkKokgZYGjDMHC+PyacOKHM UCwx+30enodz1l57r732KWt2OfunPDavTbtDfo0L5wvo+YgLvR5xISdbS/ZtQ//8EpuPKkdLWmoJ Vy81rFexLmrzn4e3NQOHutPC1RKAyIGu/H2kJ/2HuDe5DQKBQHA/ED2Sgr80Gk0Fu77O4Ga6BoUZ JCUWEfVdJl16ONE62K7RclN4870wFsy6wJRZ/lxLLibpchFTZgcA+t7IqO8yMTdX8NqSEDkg+WOw 5eisZP6KMABenvwLmTc1SJJ+yHvMxFY0b67EQqngxvVSVsy7xOULhSbrm8Kop73Zs+0WtvbmdOvd gvWfXuP2LQ32DkpSrxbTyq8SZC1uAAAgAElEQVQZ015pjbasklenxnHiSA7/GO/N9ZRibt/SEBhi x5yFQZRpKnl58i9yvqpcLXE/5+PorKTPAFcUCrieXEz8uQIqKiTMzRVoSvW9fYVqHZ26OjJ4hAeW Voa/kTt3c+KX2Hzs7CwICjOtXQAKC8qZO+NX+fjG9VJOHMmhhaslSz5qZ9R/3j42ePvYcCWhiNxs LZEDXPH0tja5fIFAIHjQEYGk4C+NtbU5/1oeStTuTHZ/c5MKJGbPb0NQmH2TyI1xZ6Dy3luJ8vm1 H6cwZXYARepySksqcHRSykEkVA/wrKzN5aFiWzsL1AXlSJKEQqGgsEDH9g03SLygRqPRB10FKq3J +qZgoTRDYQYWFmYGtuX81jPo7WsDgKWVGS7uVty+qSE/V4sqW2+Hp7dNjfXKzdLr56vK+c+7SQay Mk0lzWzNGTfFhw1rrnH6RC6nT+RibWPOmOda0bW3s5zWy8eGBe+E1XsuqXUzc56b4QfA7m9u4uph RY++LaoFqo31n0AgEPxZEYGk4C+PTidx+riKbn1acCujlB+P5hgEgo2V10UzOwuefcGPLV+k8eLc QHZsyqBNiB09+rYAwK65EksrM/LzyrmZXkrLVvqAS1tWWS2YqQlNaQUfLb2Co5OSGa8H0rKVDXNf iL9naz5auOmD34y0UgDKtZXk3C7D3FyBYwtL7H8LJKuG6isqDC1z9dD33rm4WfHmyjDMzasHZh5e 1ry1si0ZaaXEnytg3/abfPNlmkEgKc+RbG7B7HltsLYxbY6kUmlGRC99Pof33cbNw0o+rg/WNvq2 yskqEz2SAoHgoUIEkoK/PBlppTi7WjJuig9FhTrWfpRCaUmFvCCjsfK6MDdX4OCkxMnZktZBdujK KwkMscO9pT7YUCjg0UFuRO3O5D/vJNGuswOZN/SfkHlpYZDR/AvVOrRllZRpKrkYp2bPtlvodBLm Fvemp8w3wBb/QFtSk4r5/OMU1Pk6Kiok+j6mX5wS0MYWewcLEuLUrH4nieJCw1Xvjk5KOnV15PyZ fD789xVC2tmTdauMgCBbHhnkRklxBf9+LQH3ltYEhdn9NhyvwMHZ0iCfqjmSqhwtVxKKaN/Fod51 8Qmwxc2zYUGgfxtbfj1XwPavbnD1UiFlmkrGTvZpUF4CgUDwICEW2wj+8vgGNOPFNwKxsFDg6KTk 1cXBBkFgY+XGyFeV4+is1P+fV46Dk9JA/sQoT/4x1gtLazPOnFBRWlpBRG/TesVc3a0Y8qQn5eWV xJ5UEdDGlpC/mdZb2hQoFDDt5QAiejpzJaEIVU4Zjw3z4Mlx3oB+qPv5l1rj5WPDtaRifPyb4eVj Y5DH09P86D/EjYK8co58n0V2Vhm29vrfwJaWZgwZ6UmFrpIf9mdx7GA2YR2a8/xLAQZ5dOrmhLun NQFtbGkTavocyTsZP8WHfo/Xb0V+FY8OcqNH3xZoNBWcOq4iM0ODtqye33gSCASCBxCFWq2uc5TL 3v7evXQEAoFAIBAIBA8+8fHxgOiRFAgEAoFAIBA0EBFICgQCgUAgEAgahAgkBQKBQCAQCAQNQgSS AoFAIBAIBIIGIQJJgUAgEAgEAkGDEIGkQCAQCAQCgaBBiEBSIPgTU1ykY+b4cyx5LeF+myJoArRl lcwcf45FL1+836YIBAKBSYidbQSCB4Ds22UU5JUTGGLHuVN5hHVsjrW16R81F9xfDu+7zd5tt3hj WQieXg/XFojxZws4tPc2N9NKcHCy5PF/eBhsE6ktq2TbhnTizxVgZWVGr0ddeGyYh7yveV36kgRn Tqo4djCLWxka7Owt6B7ZgiFPepq8L3pjym+K/G+mlxJ/toCfonPIzdby5sow3OuxA5Ix/cbav/2r Gxw9kGVw7rFhHgwf0xKAIrWOb/6XzqVf1ZhbKOgU4cioZ1phYeLuV8b8U8UP+7P4duMNAN5YGoKP fzOT6yB4sBE9kgLBb+TnlVNcpLtr8ro4G5NH7I8qyssr+WJ1KlI9Nz0x9aUruDvk3C6jvLySe7aJ +T0iP6+cL/+TSrm2kvBezhQW6lj/6TXSr5XIabZ8kUbMsVw6hjvi6W3D7q03OXE42yT9cm0lB/dk IknQ8xEXFAr4fsctfjyaY7KNjSm/sfkDxBzL5fC+2+Spyk3O807q0q+P/VIt116ZpgKAzt2c6B7Z gu6RLfDx/333qO0bb3DudB4D/u5OxwhHThzJ4djBrGr51Ja/Mf8AZGWWsXvrTaytRcjxMCJ6JAWC 39ix6Qa+Abb0H1LzNniNldfGjbRS0lJLsLW34ML5AiyUZmRnluEToP/FLklw6nguRw9kkX27DGcX S/r0d+WRQa5yHpaWZuzYdIOff8rD3ELBhOd9CW6r35Xq/Jk8Tv6QQ8b1UioqoW2H5ox5rhU2zcwp LtLx+rR4Igfq974+G5OHhVLB+Km/69fFwlkXKC7W8cG6jvK5QrWOuS/E06W7E5P+6V9n+aDvjd3+ 1Q1SrhRhZq7A178Z/f/ublL5pvjn+x232PftLf79STuiD2RxNiYPpaUZC94Nw8JCgUZTwd5ttzh/ Og+dTiKsQ3NGPe2NrZ2FUf/9/FMemz6/jlarj/yXvqGfYuDorGTZqr8BGM3/9k0NGz9P42Z6Ke27 ONT7R0GhWseOTTe4+IsaKyszIno7M+QfnlgoFY1uX0cnJa8sCqallzVm5go8PK3ZvvEGiRcLaeXX jOIiHbE/qujUzYmxk32QJHhrzgWOHcomcqCrUX1LKzPmLAjC1t4ChQJ8/Jux4f+ukZutNanujS2/ sfkDjJzgzcgJ3ny09CpXLxWaZPed1KVvqv3p10r47MMU7OwtmDWvjcEWrRqN/tp8epovllbVA7ns zDJs7SwYONQdBRATnYvqD/6vLX9T/CNJ8NWa69g3t6BtR4dqQabgz4/4eSD4y3MpXk1pSQUlRRWU FOvIzysnObGoyeTG+GJVKnE/5/PT0RzWfqzvffhkxVVZfnjfbTZ+dh11fjldujvRrJk5udllBnmk pZbw6/kCmjsqUeVo2f7VDVl26riK7Mwy2ndxxM7enNgfVezZdtNA//ihbC78otfPzTbUrwu3llaU aSopLtKx5LUEVr19lXyV/iXk6mFlUvkbPr3GhfMF9HzEhV6PuJCTrSX7dlmN5dWEKf4BWP+fa0RH ZePiZoWnt7U8dLfh0+scPZCFj38z2oc78vNPeWxem2aS/zy8rRk41J0WrpYARA505e8jPek/xP2O +tWef2WFxJoPUki5UoS3rw252dpae35qQpJgzQfJnDmponWQLc2dlER9l8nOzYbt19D2BfD2scHM XO+rcp3euKr94HOy9PZ6+9jw/uIrbNuQjlcrG7Izy+R61KUPYNfcgoz0Ug7vu833O27h1MKS7pGm Dd02RfmNzf9uY4r9v8Tmo8rRkpZawtVLhs+eslJ9j+TiVy/y6tQ4/vffa5SWVMjyDhGOFBfpWPNB Mof23UahgIjeziblb4p/jh7IIuVKEU9NbIW5iDgeSkSPpOAvjUZTwa6vM7iZrkFhBkmJRUR9l0mX Hk60DrZrtNwU3nwvjAWzLjBllj/XkotJulzElNkBgD5QiPouE3NzBa8tCZEDlj++xBydlcxfEQbA y5N/IfOmBknSD3mPmdiK5s2VWCgV3Lheyop5l7h8odBk/bpw97Dm8q+F3LqhoUClpaRIR16ufojO 1V0fSBorX1Oq7zEpVOvo1NWRwSM8auw5qQlT/QOQnVXGog/a4uxiKZ9T5WqJ+zkfR2clfQa4olDA 9eRi4s8VUFEhYW6uqNN+bx8bvH1suJJQRG62lsgBrnh6W5uc/7XkYm7f0hAYYsechUGUaSp5efIv JtUd9D8gUq8W08qvGdNeaY22rJJXp8Zx4kgO/xjvLadraPveSVGhjqP7s3BwVNKhiyMAunJ925mZ KyjXVlJeLmFmoaCyUqKyUu+/uvSrOH86jwO7MgEY8qQnLVz1105hQTlzZ/xazZYWrpYs+ahdo8tv yvzvNnX5r3M3J36JzcfOzoKgMMPnTufuTtg1V+If2IxTJ1TE/qjC2tqMpyb5APDIY66cOJzNxV/U XPxFTZtQO7xa2ZiUvzH/5GZr2b31Jt36tKBtRwcuxqnvhmsE9xkRSAr+0lhbm/Ov5aFE7c5k9zc3 qUBi9vw2BIXZN4ncGHe+yN57K1E+v/bjFKbMDqBIXU5pSQWOTko5SILqAYCVtTkWSv1JWzsL1AXl SJKEQqGgsEDH9g03SLygloe5ClRak/Xrws1T/8K/fEGNh5cN6ddKuHFdP3+rKpA0Vv64KT5sWHON 0ydyOX0iF2sbc8Y814quvY33SpnqH4B+g90MgkiA3Cx9z2W+qpz/vJtkICvTVNLM1twk/9WGsfyr hhA9vW1qtbsucn7rufX21etbWpnh4m7F7Zsa8nO12NjqhyAb2r5VlJdXsu6TVIqKdLzwSms50K/q GSsp0jF3WQgAH/77CnbNLQyCrNr0q3hiVEv6DnTlxJEcvt9xi7xcLROe98W6mTnPzfCrZk9Tld9U +d9tjPnPy8eGBe+E1Xj9VM2LBAhqa8+SVxO4ckev4n/eTaKZrTnPzwkhOiqbU8dz2bwujWdf8DOa vzH//HQ0h3JtpXxvV/HOgsu8tCCINqGm/dgWPNiIQFLwl0enkzh9XEW3Pi24lVHKj0dzDALBxsrr opmdBc++4MeWL9J4cW4gOzZl0CbEjh599Q9+u+ZKLK3MyM8r52Z6KS1/6ynQllWa1GunKa3go6VX cHRSMuP1QFq2smHuC/FNtiakanVpypViHFsoUecrSb6if0m5uluZVL6HlzVvrWxLRlop8ecK2Lf9 Jt98mWZSIFkf/1jbVF8F7+qht9/FzYo3V4ZVCw5M9Z+1jb6snKwygx5JY/nbO+hfxFVD8RUV9WuZ Fm76wDgjrRTQL17JuV2GubkCxxaW8kKLxlBeXsnnH6VwJaGQp6f5EtahuSxzamGJrZ0FiRf1PbRl mkqup5QQGGJnkj5AcmIRrYPtaO6opGtvZ77fcYtrScUAKJVmda5Qbmz5TZH/3caY/+COOYzNLZg9 r43BtZ54sZCgMHsUCv0KbYBmv/3AyM3WknS5iAFPuNPKrxlPT/Ml5UoRF84XmJS/Mf+EdWhOM7vf w4z4s/mkXi2m72OuuLgZ/qgT/HkRgaTgL09GWinOrpaMm+JDUaGOtR+lUFpSIU8ob6y8LszNFTg4 KXFytqR1kB268koCQ+xwb6kPQBQKeHSQG1G7M/nPO0m06+xA5g0NAC8tDDKaf6Fah7askjJNJRfj 1OzZdgudTsLcxE97GMPtt0AyNamYvgNdKS2uIOVKMZZWZjR3VJJ9u6zO8kuKK/j3awm4t7QmKMzu t+FWBQ7Opr1kjPnHWIebo5OSTl0dOX8mnw//fYWQdvZk3SojIMiWRwa5mew//za2/HqugO1f3eDq pULKNJWMnexjNP+ANrbYO1iQEKdm9TtJFBfWb9W/b4At/oG2pCYV8/nHKajzdVRUSPR9TL+4xvSZ pjVTpqnk05XJXL1UiIu7FempJSRfKUZpoWD0c60wN1fQq58LB3dn8r//XiMvV0u5tlJeaGFM/1pS MR/++wqt/Jrh7deMKwn6gMTUH2KNLb+x+QPs2pKBJOl/RAAc2nMbWzsLho9pKc9trIu69MvLJZPs r5rDqMrRciWhiPZdHAD9p4VWrbiKl48NXj428tByRE998Gxnb4G1jTmnjuXS3EFJmaaCrMwy/ANt DWysLX9j/gkKszdoy3yVltSrxXSPbIFTCxFIPiyIQFLwl8c3oBkvvhEI6AOLVxcHN6ncGPmqchyd 9T1T+Xnl1SbSPzHKk2a25vwYncOZEypcPawMXmR14epuxZAnPYmOyiL2pIqIXs6YW0Dq1eJ62Vgb zi6WWFgo0JZV4t7SGm1ZJYkXC/HysTGpfEtLM4aM9OTMiVx+2J+FmZmCsA7N+cdYL5NtaIx/AJ6e 5oezy03On8nnyPdZeHhZ87ffXpSm+u/RQW5kZ5bx6/kCTh1X4ellLfeK1pW/pZUZz7/Umq+/TONa UjFdujtRUSGhLTPt+08KBUx7OYBvN2ZwMV6NpaWCx4Z58PcnPU2uf13oF1fog7uc22VEH9SvuLWy NpMDmaGjPNFqKjh7Kg8ra/20hPadHUzS9/Fvxt9HteSXM3n8/KMKW3sL+g9xY9ho09u/MeU3Nn+A I/uzqLyjJznmmH4Id+j/a4mZCZ+CrUvfVPs7dXPi/Ol8bO3MDYaLPb1tGDnBm59/yuOX2HzsmysZ +IS7fH9YWZsx4/XWfPf1TfZ9exOl0oyOEY6MnPD7/Nq68jfFP4KHH4Vara5zLMXe3rRfhgKBQCAQ CASCvwbx8fGA+PyPQCAQCAQCgaCBiEBSIBAIBAKBQNAgRCApEAgEAoFAIGgQIpAUCAQCgUAgEDQI EUgKBAKBQCAQCBqECCQFgoeEMl0Z5279grbCtF1XBAKBQCBoLCKQFDzUFOSV0qv1B4x77H/3Rb+x RCUfose6vvLf+zEf15p2xcn3mPn9bD46tfoeWvjwUFlp2rcbH9by7xYREREcOXLkfpvRaOLi4vD0 9CQ2NrZGeVpaGgMHDsTDw4OOHTsSFRV1jy0UCO4PIpAUCB5gApz8mdjxGR7162s0bahrCI7WjgS7 GN/x5n4QEBDA2LFj77cZNRIfH8+gQYP+suULjOPp6cnIkSPx9vauUf7aa68RHBzMtWvXiImJoU+f Pibl+8QTT+Dq6oqVlRV2dna4urqyYMGCpjRdILiriJ1tBA8dX375JdbW1vcsaFm2bBm9evXikUce afK82zgH0sY5kKPXjnH02rE6045pO4oxbUc1uQ1Nwblz5+jQoQOxsbGUlZVhZWV1v00yICcn5y9d vsA4bm5urF5de29/fHy8/OypD3v37gVg7NixdO/endmzZzfKToHgXiN6JAUPDbdu3eKJJ57gyJEj DB482EBWrq1g3ow9PNZhNS+M+YYb1/NlWV5uCUte2c+QLv/lyT6fs+b9HynXVpisP3r0aBYuXMic OXMoLS2tt90/pEYz+8ArDNk8gkEbh7IoeimF2iKT9Xt/2c9g+Puzs+sM5BISe658zzM7J9Nv/SDG fvsM2xK+leUl5SV8dGoVw7aM5PFNw1h8bBnqMrVBHjqdjk6dOjFx4sR61w9gx44d/P3vf6dXr14c PnzYQBYREcG5c+cYPXo0Li4uREREkJycbHLeFy9eZMKECYSGhuLh4cHEiRPRaDQGabZs2UKnTp3w 8vKiS5cu7N69G4CsrCzat2/P+PHjOXnyJP7+/vj7+zNgwABZt6CggClTpuDj40Pr1q1ZunQpFRW/ Xx8ZGRmEh4eTnZ3NhAkTcHd3N9Cvi6Yo35jcGBEREWzatInevXvj7u7OsGHDDAJbnU7HokWLCA4O JigoiEmTJlFYWFiv+qvV6lrb11j7GbMvIyODIUOG4OfnR3BwMOPGjSMlJcXk+htjwIABcrtYWFhw 8eJFA/lrr71GSEgISUlJjBw5slr73W2M1d9Y+xmTm0Jt9xcYb1+FQkFubq58XPUsbar6Ce4+IpAU PBR8/fXX9O/fnylTprBx40acnJwM5DfTC1Dnl+Lt60j8zxksffUAAJWVEnOnfUfUrkv8LdyLFm52 bPjvaVavOG6SPkCbNm04duwYLVu2pEePHpw+fbpetu+7eoD0ghtE+vTC0dqBqORD1YLBupjU8Vmm dJ5IH59eNco3xX/N8hPvkFOaS/+Afthb2nOz8JYsX3JsOd9c3E6ISzCRvn04mHyYFSffM8hDo9GQ nJxMQkJCvepWxY4dO3j88ccZMmQIO3bsqCafOnUqc+fOJTExEXd3d1asWGFy3klJSYwZM4b4+HhS UlJISEhgzZo1snzr1q3861//4ssvvyQjI4NNmzZRUlIC6HuZ4uPjWb16Nb179yY1NZXU1FSDYHfq 1KkoFAqSk5OJjY1l3759fPyx4VzVzMxMxo8fz4gRI0hJSWH9+vUm2d4U5ZtinzHWr1/Ptm3bSE9P x9LSktdff12WLV68mOPHj3P27FkSExNxcHBg3rx59ar/okWLam1fY+1nzL4lS5bg7+9Pamoqly9f ZsyYMU26te/hw4fldnF1rb6H+3vvvcfly5fx8/Pj+++/r9Z+dxtj9TfWfqa0b13UdX+Bae17N+sn uAeo1Wqprj+B4EFn7dq1UpcuXaTs7OxqsnxVidQz4H1pVN+1kiRJUoWuUurX9mOpZ8D7kjq/VEqI uyX1DHhfmjj0K0mSJKm0RCtFBn0oRQZ9KGm1OqP6f+TChQuSm5ubFBcXZ7L9mYWZUplOK0mSJF3J uSp1Xxspjdk2wSDND6nRUve1kdLKnz6qNZ/diXul7msjpTU/r5XPVUqV0oANQ6TeX/STMtQ35fMV lRVy2d3XRkrDtoyUYtJPSafST0sTdkyUen3xqFReUW6Qf25urlRaWr3Oxrh06ZLUuXNnSZIkKT8/ X/L09JR0Op0sDw8Pl/bv3y8fr1+/XurVq1e9y1Gr1VJsbKw0fvx4ady4cfL57t27S5s3b65Td/v2 7dKAAQOqnc/Ly5PMzc2l/Px8+dzBgwelkJAQ+fjGjRsSIB09erTeNje2fFPsM0Z4eLh0+PBh+Xj3 7t2Sh4eHfOzg4CDFxMTIx1lZWZKPj498bKz+prZvbe1nzL4lS5ZI7dq1k6KjoyWtVmtirRuGh4eH dOHChRplgYGB0i+//NLgvJ966inpo49qv79rw1j9jbWfMbkxTLm/JKn29gWknJwc+XjBggXSSy+9 1GT1E9w94uLipLi4OEnMkRT86Rk4cCCbNm1iwYIFrFy5Ejs7u2pplJbmAJiZK/D2dSLpcjb5eaVk pBUAEBiq72mwtlHi5evI9WQVWbcKsbO3qlPf3uH3+VBpaWnMnj2bYcOG0bp1a5PtV5Xm8cGpVfx8 8ywl5fpf8tklTTNnLq80nyJtEa7NXGhp7ymfN1PoByMyfuuZzCrOZk7U6wa6peWl2Fv9/svf2dm5 QTbs3LmTq1ev0qZNGwCys7M5ceKEwZxSpVIp/+/u7k5ZWZnJ+WdkZDBr1iyKiooIDw/HwsKCgoIC WX716lXatm3bINtTU1NxcXHBwcFBPhcYGEhqaqpBOjs7u7syR9ZY+abaVx/atm2LSqUC9HM31Wp1 tSkNf7wWjNW/rvY11n512Qcwb948nJ2d5R7PoUOHsnz5cry8vEyq75+duupvrP1Mbd+6MHZ/1bd9 m7J+gnuDGNoW/Onx8fHhyJEjhIWF0a1bN44ePVotjSRJAGjLdGRmqDEzV+DRsjktW+lfwEmX9YFb mUZHxvV8LCzMcPO0N6pfxbp16xg0aBCvvPIKn3/+Oba2tibZXlxezMzvZ5Oal8oHg97l0NPfozRX IiEZpLO20AesqlJVTdnUipONIzYW1mSX5JCc9/u8Io1OP0epVXP9CtSW9i05MfEIMZOPyX93BpGg n4un1db/G5U7duzg+PHjXL16latXr/Luu+/WOLzdUMaOHcvYsWOJiopi2bJlPProowZyPz8/EhMT 68zD2traYJ5WFb6+vuTk5BjMuUpJScHPz69JbG9s+XfDvqSkJPz9/QFo0aIFdnZ2REVFcenSJfnv /PnzDc7/jxhrv7rsAzA3N2fmzJnExMSQlJREeXk506dPbzL7HnTqqr+x9muK9jV2fxlrX0tLS7Kz s+XjPz5jGlO/O2no80tgHBFICh4KFAoFs2bNYteuXbz55pvs2rXLQJ6emsf8mXuY/cy3FBWWMeCJ EJSW5oT8zZ22nTxJvHCb+TP38NIz29HpKhk+rj1KpblRfdBPDo+OjiYmJobHH3+8XnbnleZTqtNQ oislJv0UbxyeR3lFebV0bZxbY2FmwYm0H1lybDn/jTVtjpECBf/vt5Xccw68xjs/vs8L+/7JnKjX kJBwtXWhn/8j3Cy8yQv7ZvH5uS9YeHQxWy9+a5BPcXExfn5+9e51S0tLIy0tjQ4dOsjnBg4cyM6d O+XgvLFcv34dc3N9W1y9erXa/KsXXniBefPmcfnyZTn9e+8ZzgENCwvjwoULpKWlAcgvNmdnZ4YP H87rr79ORUUFBQUFvPXWW0yePLlJbG9s+U1l37Zt29BoNBQUFLB48WImTZoE6O+r6dOnM2PGDLkX KSsrq0kDSWPtV5d9APPnz5cXwDg5OREaGlrt2pIkiV69ejFq1IP5VYPGUFf9jbVfU7SvsfvLWPsG BQWxYcMGNBoNe/fuZePGjU1Wvyoa+vwSmIYIJAUPFVULX7p27WpwfvCIMIoLy0hJzKHfkCBefkv/ q9jMTMHb/zecgcNCOHcqncyMQp6e3pV//quvSfoA06ZN46uvvsLR0bHe9no392Jyp+fQVmg5kHyI dm7t6OoVXi2dSzMXXu/1Ck7WjpxM/4nE3CvVei1r4/nOk3ix63RslDYcSDpIkbaYQa0fkx/GC/rM ZdzfxpBTksOWX78hQ52Bo7WDQR6Wlpb4+vrKw9OmsnPnTvr3749CoZDPtWvXjoqKilo/7FxfVq1a xdtvv027du1YuHBhtd6oyZMn8+qrr/Lkk0/i6+vLyJEjCQgIMEjj7+/P8uXLiYyMJDQ0lAkTJqDT 6QB9b7NGoyEgIIDOnTszcOBAXn755SaxvSnKbwr7mjVrRteuXQkLC6Nnz54Gq2aXLVtG165d6d69 O2FhYQwfPpybN282TcUx3n7G7OvatStz5swhJCSEoKAgYmJiavxMj7m5OTt37qyx5/d+UvUdyR07 djB//vx6f0fSWP2NtV9j29fY/WWsfT/88EO2bNlCYGAghw4dYvny5U1aP2j480tgGgq1Wl3n26gp V78JBAKB4MEiIiKCd955h379+t1vU2qkqezTaDR4eHhw+/btB+47pgLBn5H4+HhA9EgKBALBX56m mmZwt2gK+1asWMGoUZrzsX8AACAASURBVKNEECkQNDEikBQIBALBQ82BAweorKys1/cLBQKBaYih bYFAIBAIBAJBvRBD2wKBQCAQCASCRiECSYFAIBAIBAJBgxCBpOAvQ5mujHO3fkFbIT5KKxAIBAJB UyACScGfmqjkQ/RY11f+ez/m41rTrjj5HjO/n81Hp6p/Y+5+UZBXSq/WHzDusf/dF/2HgYiICI4c OdLofCorK++KflPZZyrLli3jn//8Z5PnGxcXh6enp8H3P0tKSvD398ff3x8rK6tG1bOh/p84cSIf f1z7ff+gY6r9Nflf8Odv/4cBEUgK/tQEOPkzseMzPOrX12jaUNcQHK0dCXYJugeWPTw4OTmxdOlS +fi7776r9w4+Dzrx8fEMGjTovun/GfD09GTkyJF4e3vL55o1a0Zqaiqpqam0b9++wXn/FfzXWGry v0DwICACScEDx5dffsmWLVtMStvGOZDnu0xmYOv+RtOOaTuK/eO/Y3jwE4010YBly5YRHR3dpHk+ SFhYWLB+/XqKi4vvtyl3jZycnPuq/2fAzc2N1atX4+np2eR5/xX811jupv8FgsYgAknBA8OtW7d4 4oknOHLkCIMHD5bP/5AazewDrzBk8wgGbRzKouilFGqLTM6395f9DIa/Pzu7zkAuIbHnyvc8s3My /dYPYuy3z7At4fe9pkvKS/jo1CqGbRnJ45uGsfjYMtRlalk+evRoFi5cyJw5cygtLW1Q3cu1Fcyb sYfHOqzmhTHfcON6vizLyy1hySv7GdLlvzzZ53PWvP8j5doKk/UBdDodnTp1YuLEifW2TafTMXTo UD777LMa5RcvXmTChAmEhobi4eHBxIkT0Wg0sszHx8dg2DI/Px93d3c5TVNw7tw5+vTpg7u7O8OH DzcITBQKhcG2eFVtBfp9edu3b8/48eM5efKkPEw7YMAAk8o1VV+tVjN69GhcXFyIiIggOTlZlul0 OhYtWkRwcDBBQUFMmjSJwsJCk+uuUql46qmncHd3p0ePHiQkJBjI68r/8uXLeHl5GbRPVlYWLVu2 pLxcv+f7gAED5HpZWFjI+x43Bab4r67rqyZmzZrF+PHj5Y+YN8a/x44dY9iwYfTv35/AwED27t1L QECAwfOpoKCAKVOm4OPjQ+vWrVm6dCkVFYb355YtW+jUqRNeXl506dKF3bt3m2y/Mf9HRERw7ty5 Wq8vjUbDs88+S1BQEEqlEhsbG/z9/dm/f7+cpjHPh4yMDIYMGYKfnx/BwcGMGzeOlJQUA/s2bdpE 7969cXd3Z9iwYQb3p7H2aWz7C+4+IpAUPBB8/fXX9O/fnylTprBx40acnJxk2b6rB0gvuEGkTy8c rR2ISj5ULRisi0kdn2VK54n08elVo3xT/NcsP/EOOaW59A/oh72lPTcLb8nyJceW883F7YS4BBPp 24eDyYdZcfI9WV61v3fLli3p0aMHp0+frnf9b6YXoM4vxdvXkfifM1j66gEAKisl5k77jqhdl/hb uBct3OzY8N/TrF5x3CT9KjQaDcnJydWCDFOZNGkSH3/8MVpt9YVKSUlJjBkzhvj4eFJSUkhISJA/ /Ny2bVsCAgI4cOB3e3bs2MHQoUOxtrZukC01cejQIbZu3Up6ejpKpZI33njDJD03Nzfi4+NZvXo1 vXv3lodpDx8+3KT6ixYtYu7cuSQmJuLu7s6KFStk2eLFizl+/Dhnz54lMTERBwcH5s2bZ3Ldp06d ilKpJC0tjd27d5ORkWEgryv/kJAQ/Pz8+OGHH+T0W7ZsYfTo0SiVSgAOHz4s18vV1dVku0zBFP/V dX39kSVLlpCYmMj//vc/eX/3xvr34MGDfPLJJ3Tr1o23336bM2fOcObMGdLT0wG9/xUKBcnJycTG xrJv3z6DOXtbt27lX//6F19++SUZGRls2rSJkpISk+03xf9Tp06t9fpauXIlRUVFJCQk8Ouvv2Jl ZUV8fLzB9JTGPB+WLFmCv78/qampXL58mTFjxlT7/vT69evZtm0b6enpWFpa8vrrr8syY+3T2PYX 3APUarVU159AcLdZu3at1KVLFyk7O7tGeWZhplSm00qSJElXcq5K3ddGSmO2TTBI80NqtNR9baS0 8qePai1nd+JeqfvaSGnNz2vlc5VSpTRgwxCp9xf9pAz1Tfl8RWWFXHb3tZHSsC0jpZj0U9Kp9NPS hB0TpV5fPCqVV5RXK+PChQuSm5ubFBcXZ1Ld81UlUs+A96VRffU2VegqpX5tP5Z6BrwvqfNLpYS4 W1LPgPeliUO/kiRJkkpLtFJk0IdSZNCHklarM6p/J7m5uVJpqeE5U3B0dJQyMzOlZ599VlqzZo20 a9cuafDgwdXSqdVqKTY2Vho/frw0btw4+fzWrVulESNGyMf9+/eXoqOj621HbYSHh0uHDx+Wj3fv 3i15eHjIx4CUk5MjHy9YsEB66aWXDPLYvn27NGDAgAbbUJd+eHi4tH//fvl4/fr1Uq9eveRjBwcH KSYmRj7OysqSfHx8TCpXpVJJZmZmkkqlks8tXbpUevHFF03Of+3atdKzzz4rH3fp0kU6f/58jeV5 eHhIFy5cqFH2x3aoD6b4v7br67nnnpM++ugjafXq1VLbtm2loqIiA73G+Dc6Olrq2LGjJEmS9NZb b0lLly6VJEmSOnToIEVHR0t5eXmSubm5lJ+fL+scPHhQCgkJkY+7d+8ubd68udYyjNl/JzX539j1 NXbsWOnTTz+VjwMCAqSLFy9Wy7uhz4clS5ZI7dq1k6KjoyWtVltNbuz+NLV9Gtr+grtHXFycFBcX J1nc70BWIBg4cCCbNm1iwYIFrFy5Ejs7OwO5qjSPD06t4uebZykp1/+Szy5pmjlVeaX5FGmLcG3m Qkv73+cemSn0nfUZv/VMZhVnMyfqdQPd0vJS7K1+/+WdlpbG7NmzGTZsGK1bt66XHUpLc3255gq8 fZ1IupxNfl4pGWkFAASG6nsirG2UePk6cj1ZRdatQuzsrerUt3f4vdfP2dm5Xjb9kblz5zJ06FA+ +eQTg/MZGRnMmjWLoqIiwsPDsbCwoKCgQJaPGDGCV199lVu3bqFQKEhJSSEyMrJRttRF27ZtUalU dy3/hlDVuwfg7u5OWVkZoJ8bqFarqw0pmtpWVb1Ud/bg34kp+Y8ePZr58+dTUlLC9evXKS8vp2PH jiaVfy8wdn2Bvpc7KysLtVrN7du3CQgIABrv3zu5s4er6v/U1FRcXFxwcHCQZYGBgaSmpsrHV69e pW3btnXmXZv9plLb9QX65+uaNWt47LHHOHPmDBUVFbRp06ZaHg19PsybNw9nZ2e5R3To0KEsX74c Ly+vGtPfeX+a0j6NaX/BvUEEkoL7jo+PD0eOHGHVqlV069aN1atX8+ijjwJQXF7MzO9n49LMhQ8G vUtrpwCGbB6OhOH8F2sLfcCkKq1fAOFk44iNhTXZJTkk56XQ2kn/ANLoNFhbWNOquX6FZEv7lnwz 6isszGq+ZdatW8fKlSv54IMPGrSiWfptPo+2TEdmhhozcwUeLZtTWKB/ISRd1gfOZRodGdfzsbAw w83TnpIibZ36d1JQUICNjQ2Wlpb1tg/0w6AdO3bk6NGjBufHjh3LrFmzGDVqFKAfxtq1a5csVyqV TJw4kQ0bNmBra8vYsWPv6rBTcnKywYvE0tKS7OxsWrRoAVDj8Ly1tbXBPMr60lD9Fi1aYGdnR1RU FD4+PvXWd3NzQ6VSodFoapwqYEr+9vb2DB48mD179nDx4kWee+65etsBYGZmhk6na5BuXf4zdn2B PqD78ccfiYqKYuLEiURHR6NQKBrtX2P4+vqSk5NDYWGhPJybkpKCn5+fnMbPz4/ExMQ6V7XXZn9T UDU3csGCBTg4OHDkyBGDwLOKhj4fzM3NmTlzJjNnzkSlUvHiiy8yffp09uzZU2P6pKQk/P39AdOu z8a0v+DeIOZICh4IFAoFs2bNYteuXbz55pvygyKvNJ9SnYYSXSkx6ad44/A8yivKq+m3cW6NhZkF J9J+ZMmx5fw3tuY5NNXKRcH/a6t/QM058Brv/Pg+L+z7J3OiXkNCwtXWhX7+j3Cz8CYv7JvF5+e+ YOHRxWy9+PtinIULFxIdHU1MTEyDP4uTnprH/Jl7mP3MtxQVljHgiRCUluaE/M2dtp08Sbxwm/kz 9/DSM9vR6SoZPq49SqW5Uf0qiouL8fPz45FHHmmQfVXMmzePDRs2GJy7fv065ub6sq5evVrj/KXn n3+er776im3btvH0009Xk0uSRK9eveSXRX359ttv0Wg0qNVqFi9ebNDDERQUxIYNG9BoNOzdu5eN GzdW0w8LC+PChQukpaUBkJ2dXa/yG6qvUCiYPn06M2bMkHtZsrKyOH/+vEn63t7etG/fnqVLlyJJ EklJSWzevLne+U+aNIlvvvmGXbt2MW7cOJPK/iO+vr7s378fSZLq3SNcl/9Mub7mzJlDq1atmDJl CtbW1vIcxcb61xjOzs4MHz6c119/nYqKCgoKCnjrrbeYPHmynOaFF15g3rx5XL58Wa7Pe++9Z5BP bfY3BevWrePZZ59l8+bNfPrppzWOljTm+TB//nx5AZCTkxOhoaHVFrps27YNjUZDQUEBixcvZtKk SYBp7dOY9q+isc8XQd2IQFLwQFG1cKVr164AeDf3YnKn59BWaDmQfIh2bu3o6hVeTc+lmQuv93oF J2tHTqb/RGLulWq9lrXxfOdJvNh1OjZKGw4kHaRIW8yg1o/JD8MFfeYy7m9jyCnJYcuv35ChzsDR +vehrGnTpvHVV1/h6OjY4HoPHhFGcWEZKYk59BsSxMtv6XtkzcwUvP1/wxk4LIRzp9LJzCjk6eld +ee/+pqkX4WlpSW+vr41DmnVh06dOtGlSxeDc6tWreLtt9+mXbt2LFy4kOnTp1fTa9myJaGhoZSU lBASElJj3ubm5uzcubNBPXv+/v5069aN0NBQunfvLq/KBvjwww/ZsmULgYGBHDp0iOXLl9eov3z5 ciIjIwkNDWXChAn16l1rjP6yZcvo2rUr3bt3JywsjOHDh3Pz5k2Ty96yZQvHjx/H29ub2bNnVwvU Tck/MjKShIQEfH19cXd3N7nsO1mwYAEHDx7Ex8en3h9Er8t/plxfZma/v8o+//xz3n77ba5cuQI0 3r/GWLduHRqNhoCAADp37szAgQN5+eWXZfnkyZN59dVXefLJJ/H19WXkyJHVhl7rsr+xjBo1iqlT p+Lp6Ym/vz/t2rVj2rRpBiufG/N86Nq1K3PmzCEkJISgoCBiYmJYvdpw04dmzZrRtWtXwsLC6Nmz p8H9aax9Gtv+VTTm+SKoG4Vara7zbfvH1VcCgUDQEF544QXatWvHzJkza5RrNBo8PDy4ffs2VlZW 99g6geDhpG/fvnz66aeEhYUB+s+s9erVi08//fSefAQ+IiKCd955h379+t31supCPF+anvj4eED0 SAoEgntAdHQ00dHRTJ06tdY0K1asYNSoUeIhLxA0ETqdjuTkZK5fv45KpUKtVnPy5EmsrKyIiIi4 Z3b8caj7fiCeL3cPsdhGIBDcNaqGsps3b84XX3xR60T+AwcOUFlZWev34QQCQf2xsLDg+++/Z9Wq Vbz77rvY2toSHh5OdHR0o7/i8GdCPF/uLmJoWyAQCAQCgUBQL8TQtkAgEAgEAoGgUYhAUiAQCAQC gUDQIEQgKRAIBAKBQCBoECKQFAgeMpYtW1av7/hFRERw5MiRu2jRg0V9/VNFZWXlXbDmwSEuLg5P T09iY2PrTNdQ/wkEgocTEUgKBAKBEeLj4+/JN/fuJ56enowcORJvb+/7bYpAIPgTIT7/IxAIBEbI ycm53ybcddzc3KrtSCIQCATGED2SAsF9JiMjgyFDhuDn50dwcDDjxo0jJSVFll+8eJEJEyYQGhqK h4cHEydONNjeTKVS8dRTT+Hu7k6PHj1ISEiotw3nzp2jT58+uLu7M3z4cIPAKSMjg/DwcLKzs5kw YQLu7u4MGDBAlhcUFDBlyhR8fHxo3bo1S5cupaKiAtBvqXjixAlA/3HkqvPr1q1jxowZJtlmrP4R ERGcO3eO0aNH4+LiQkREBMnJyU3in6ysLNq3b8/48eM5efIk/v7++Pv7G9TfmH8UCoXBtmwLFy40 2CJOp9OxaNEigoODCQoKYtKkSRQWFppk37Fjxxg2bBj9+/cnMDCQvXv3EhAQwODBg03234ABA+R6 WVhYyPsmN4X/BALBw48IJAWC+8ySJUvw9/cnNTWVy5cvM2bMGIPvtyYlJTFmzBji4+NJSUkhISHB 4MO6U6dORalUkpaWxu7du8nIyKi3DYcOHWLr1q2kp6ejVCp54403DOSZmZmMHz+eESNGkJKSwvr1 6w3KVygUJCcnExsby759+/j4448B6NKli/ytsccff5wXX3wR0A8Vd+rUySTbjNW/yoa5c+eSmJiI u7s7K1asaBL/uLm5ER8fz+rVq+nduzepqamkpqZy+PBhk/1jjMWLF3P8+HHOnj1LYmIiDg4OzJs3 z2T9gwcP8sknn9CtWzfefvttzpw5w5kzZ0hPTweM++/w4cNyvVxdXavl3xTXl0AgeHgRQ9sCwX3G 29ubrVu3cvz4cXr27Mnw4cMN5FXHhYWFJCYm0qZNG86cOQNAXl4eu3btIicnBysrK1xdXRk4cCCZ mZn1suGNN97A09MTgGeffZbnn3/eQJ6RkcHGjRt55JFHALC1tQUgPz+fHTt2kJubi1KpxNnZmSVL ljBr1ixefvllOnfuTHx8PBUVFZSVlfHTTz8B+oUdTz/9tEm21VX/KpYtW0bnzp0BGD16NJ999lmT +scYtfnHFFatWsWBAwews7MDYN68eYSHh7Nq1SqT9ENDQ2nbti1t2rQhLCwMFxcXfHx8SElJoVWr Vib5rzbulf8EAsGfFxFICgT3mXnz5uHs7Cz3qA0dOpTly5fj5eUF6IOUWbNmUVRURHh4OBYWFhQU FADIvUhOTk5NZk/btm1RqVQG5+zs7OQg6U5SU1NxcXHBwcFBPhcYGEhqaioAnTt3ZuPGjfz6668E Bwdz4sQJVCoVly5dol27dibZU1f9q1AqlfL/7u7ulJWVyfY1tX9qojb/GCMnJwe1Ws3EiRMNzjdk +zqFQlHj/6b4rzbulf8EAsGfFzG0LRDcZ8zNzZk5cyYxMTEkJSVRXl7O9OnTZfnYsWMZO3YsUVFR LFu2jEcffVSWubm5oVKpDOa8NZbk5GQCAgJMSuvr60tOTo7BnL6UlBT8/PwA6NChA5cvX+ann36i Z8+edO3alR07duDu7o61tbVJZdRVf2M0lX+sra0N5jnWB0tLS7Kzs+VjrVYr/9+iRQvs7OyIiori 0qVL8t/58+cbZe+d3Cv/FRQUGNRNIBD8NRCBpEBwn5k/f768wMHJyYnQ0FAkSZLl169fx9zcHICr V68azG/z9vamffv2LF26FEmSSEpKYvPmzfW24dtvv0Wj0aBWq1m8eHG1HrLacHZ2Zvjw4bz++utU VFRQUFDAW2+9xeTJkwGwsbHBy8uLnTt30rVrV3r37s3mzZtNnh8JddffGE3ln7CwMC5cuEBaWhqA QWBojKCgIDZs2IBGo2Hv3r1s3LhRlikUCqZPn86MGTPkXsKsrKwmDSTvhf+Ki4vx8/NrUK+sQCD4 cyMCSYHgPtO1a1fmzJlDSEgIQUFBxMTEGHyGZdWqVbz99tu0a9eOhQsXGvRWAmzZsoXjx4/j7e3N 7NmzTZ57eCf+/v5069aN0NBQunfvbrCq2Bjr1q1Do9EQEBBA586dGThwIC+//LIs79y5M6dPnyY0 NJTevXsTHR1dr0DSWP2N0VT+Wb58OZGRkYSGhjJhwgR0Op1Juh9++CFbtmwhMDCQQ4cOsXz5cgP5 smXL6Nq1K927dycsLIzhw4dz8+bNettYG/fCf5aWlvj6+tKmTZumMlsgEPxJUKjVaqmuBHeuHhUI BAKBQCAQCKq+yCF6JAUCgUAgEAgEDUIEkgKBQCAQCASCBiECSYFAIBAIBAJBgxCBpEAgEAgEAoGg QYhAUiAQCAQCgUDQIEQgKRA8JJTpyjh36xe0FeKj0AKBQCC4N4hAUvBQU5BXSq/WHzDusf/dF/3G EpV8iB7r+sp/78d8XGvaFSffY+b3s/no1Opa0zxslJSU4O/vj7+/P1ZWVhw5cqTWtHFxcXh6ehIb G3sPLXz4iYiIqNPvVTTU/6bmL/hzsGzZMv75z3/ebzMETYgIJAWCB5gAJ38mdnyGR/36Gk0b6hqC o7UjwS5B98Ay08jNzUWhUPDpp5/K55555pkm+3B1s2bNSE1NJTU1lfbt29eZ1tPTk5EjR+Lt7d0k ZQvqh/C/QPBwIgJJwUPHl19+yZYtW+5ZecuWLSM6Ovqu5N3GOZDnu0xmYOv+RtOOaTuK/eO/Y3jw E3fFlobSokULtm3bBuj3mT5z5sx9scPNzY3Vq1fj6el5X8r/qyP8LxA8nIhAUvDQcOvWLZ544gmO HDnC4MGDDWTl2grmzdjDYx1W88KYb7hxPV+W5eWWsOSV/Qzp8l+e7PM5a97/kXJthcn6o0ePZuHC hcyZM4fS0tJ62/1DajSzD7zCkM0jGLRxKIuil1KoLTJZv/eX/QyGvz87u85ALiGx58r3PLNzMv3W D2Lst8+wLeFbWV5SXsJHp1YxbMtIHt80jMXHlqEuUxvkodPp6NSpk8l7cN+Jk5MTWVlZZGVlcejQ IYKDg2XZxYsX8fHxobKyUj6Xn5+Pu7s7Go2m3mXVxIABA+ThbwsLC3lf8yp0Oh2LFi0iODiYoKAg Jk2aRGFhoSzXaDQ8++yzBAUFoVQqsbGxwd/fn/3795uk3xhM8U9BQQFTpkzBx8eH1q1bs3TpUioq fr9+FQoFubm58nHVtVpFRkYG4eHhZGdnM2HCBNzd3RkwYEC97FSr1YwePRoXFxciIiJITk6WZcb8 b8y/xvKPiIjg3LlztcqNtU9GRgZDhgzBz8+P4OBgxo0bR0pKislyYxizr67269SpEydOnJDrUXV+ 3bp1zJgxw2jZx44dY9iwYfTv35/AwED27t1LQECAwfPx4sWLTJgwgdDQUDw8PJg4caJ8bTXF/alS qXjqqadwd3enR48eJCQkGMiNXb+Nrd/dvD8FekQgKXgo+Prrr+nfvz9Tpkxh48aNODk5Gchvpheg zi/F29eR+J8zWPrqAQAqKyXmTvuOqF2X+Fu4Fy3c7Njw39OsXnHcJH2ANm3acOzYMVq2bEmPHj04 ffp0vWzfd/UA6QU3iPTphaO1A1HJh6oFg3UxqeOzTOk8kT4+vWqUb4r/muUn3iGnNJf+Af2wt7Tn ZuEtWb7k2HK+ubidEJdgIn37cDD5MCtOvmeQh0ajITk5udpLwBSKiop48skn2blzJ9u3b2fQoEGy rG3btgQEBHDgwO/+3LFjB0OHDsXa2rreZdXE4cOH5eFvV1fXavLFixdz/Phxzp49S2JiIg4ODsyb N0+Wr1y5kqKiIhISEvj111+xsrIiPj6exx9/3CT9xmCKf6ZOnYpCoSA5OZnY2Fj27dvHxx/XPpe2 JjIzMxk/fjwjRowgJSWF9evX10t/0aJFzJ07l8TERNzd3VmxYoUsM+Z/Y/41ln+VD2qTG2ufJUuW 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/ sdTln9TUVFxcXHBwcJDTBwYGkpqaWq8y7OzseOSRRxpso1KplP93d3enrKzMZN26/Gtq/rXJTWmf efPm4ezsLPcYmPLJmAAAIABJREFUDh06lOXLl+Pl5WWS3BRqs89Y+3Xu3JmNGzfy66+/EhwczIkT J1CpVFy6dIl27dqZXD7opzjU9H9GRgazZs2iqKiI8PBwLCwsKCgokOWNuT+reqH/OEJ0p7wprt8/ 1qnq/3txfwpABJKCPz0+Pj4cOXKEVatW0a1bN1avXs2jjz5qkEaSJAC0ZToyM9SYmSvwaNmcwgL9 Az3psj5wK9PoyLiej4WFGW6e9pQUaevUr2LdunWsXLmSDz74wGBIzhjF5cXM/H42Ls1c+GDQu7R2 CmDI5uFISAbprC30AauqVFUf1+Bk44iNhTXZJTkk56XQ2ikAAI1Og7WFNa2a61fQtrRvyTejvsLC rPZHQkFBATY2NlhaWtbLhiq+/vprnJ2d5SGnKpRKJRMnTmTDhg3Y2toyduxYg5eCqZiZmaHT6eql 06JFC+zs7IiKisLHx6fGNFVz9xYsWICDgwNHjhyRAwNT9BtLXf7x9fUlJyeHwsJCebg1JSUFPz8/ Wd/S0pLs7GxatGgB6Bc8PUjU5d/GYkr7mJubM3PmTGbOnIlKpeLFF19k+vTp7NmzxyR5YzDWfh06 dODy5cv89NNP9OzZk7KyMnbs2IG7u3uTTf0YO3Yss2bNYtSoUQCsX7+eXbt2yfLG3J9ubm6oVCo0 Gk2N9ppy/TaGe3F/CsQcScFDgkKhYNasWezatYs333zT4EEIkJ6ax/yZe5j9zLcUFZYx4IkQlJbm hPzNnbadPEm8cJv5M/fw0jPb0ekqGT6uPUqluVF90C9eiI6OJiYmpl5BJOh7DEt1Gkp0pcSkn+KN w/Moryivlu7/s3ff4U1V/x/A32mSNl10Lxq66KYUKaUUgQJCRVCoCoIsEQFBQBAHIkPGtwVUVBSU HwIqguBEZJchZZYhYAsUCh1077RNR0aT3N8fsRdi2+SmgzI+r+fp87Q595x7zsm5yafn3OFn3xkC EwFOZZ/BihMr8fXFjdz6BTy81EX7BTHv0Hv46MyneGP/m5gX/x4YMHCydMRT3gOQX5WPN/bPwabL 32LJ8eX45frvOuXU1NTAy8urRbNWvr6+Tc4EvP7669i2bRt+/fVXTJw4sVnle3p64uDBg2AYBhIJ t4Cbx+NhxowZmDlzJjsLU1xcjCtXrrDbbNmyBZMmTcKOHTuwYcMGndlmLvkB7T8iffr0Yb+sjdVU /9jb2yMmJgbz58+HWq1GZWUlli5diilTprDb+Pv744cffoBcLse+ffuwffv2ZtWhrejr35bi8v4s WrSIvQDIzs4OQUFB7D+OXNJbwtD7Z25uDnd3d/zxxx+IiIhA3759sWPHDs7nR3KRlZUFPl/7WXb7 9m32/Mh7Nff4FIvFCA0NRWxsLBiGQVpaGnbs2MGmcxm/LcH1+CQtQ4EkeaTUX/gSERGh8/ozzwej pkqBjNRSPDXMH28v1c5YmpjwsPr/YhA9IhCXz+WgMK8KE2dE4M0P+nPKDwDTp0/Htm3bYGtra3R9 xR3cMaX7q1CqlTiUfgQhziGIcA9vsJ2jhSPm93kHdiJbnM45i9SyWw1mLZvyethrmB0xA+ZCcxxK O4xqZQ2GdH6a/TJc3G8BxnUdg9LaUuy8+jPypHmwFdnolGFqagpPT89Wu//jf3Xs2BFBQUGora1F YGBgs8pYvHgxDh8+DA8PD6NueBwXF4eIiAhERkYiODgYMTExyM/PZ9NHjRqFadOmwc3NDd7e3ggJ CcH06dPZq1YN5a/H5/Pxxx9/6FxBzZW+/tmyZQvkcjl8fHwQFhaG6OhovP3222z6559/jp07d8LX 1xdHjhzBypUrjd5/WzLUvy1l6P2JiIjAvHnzEBgYCH9/fyQmJmL9+vWc01vK0PsXFhaG8+fPIygo CH379kVCQkKrBpLr1q3D6tWrERISgiVLlmDGjBkNtmnJ8blz506cPHkSYrEYc+fObRCIGmp/S3E9 Pknz8aRSqd5vI2OvTiOEkOZ44403EBISglmzZrV3VXT0798fGzZsQHBwMADtbab69OmDDRs26FyB bohcLoerqyuKiopgZmZmdD0e1P5pqdbqX9K2HtXxR5qv/o4CNCNJCGl3CQkJSEhIwLRp09q7KjpU KhXS09ORlZUFiUQCqVSK06dPw8zMDD179jSqrFWrVmHUqFHNCiIf1P5pqdbsX9J2HtXxR1oHXWxD CGk39UtlHTp0wLffftvsC3naikAgwIEDB7Bu3Tp8/PHHsLS0RHh4OBISEoy68vPQoUPQaDSNnn+m z4PePy3VWv1L2sajPv5I66ClbUIIIYQQYhRa2iaEEEIIIS1CgSQhhBBCCGkWCiQJIYQQQkizUCBJ yGMmLi7OqPssEkIIIU2hQJIQQgghhDQLBZKEEEIIIaRZKJAkpJ3J5XJMmjQJ/v7+EAqFMDc3h7e3 Nw4ePAgAqKysxNSpU+Hh4YHOnTsjNjYWarWazW8oXSKR4OWXX4aLiwt69+6NlJSU+95GQgghjya6 ITkh7WzNmjWorq5GSkoK0tLSEBkZieTkZPYertOmTYONjQ3S09NRVVWFZ599FhYWFuzzaLmkW1hY IDs7G1KpFC+99BLd7JkQQkiroBuSE9LOxo0bh6ioKMyYMQMA0LlzZ+zduxfBwcGoqKiAo6MjysrK YGNjAwA4cuQI5syZgxs3bhhMLy8vh6OjI0pLS2FnZwdAe7FNYWEh1q1b1z4NJoQQ8tCjG5IT8oCI jo7G999/j4yMDPz0009Qq9Xw8/MDAGRmZsLR0ZENEgHA19cXmZmZnNOdnJzYIJIQQghpTbS0TUg7 qz83cvHixbCxscGxY8cgFAoBAJ6enigtLUVVVRW7OpCRkQEvLy9O6c7OzpBIJJDL5RCJRHrrUVlZ CXNzc3qeLiGEEM5oRpKQdrZlyxZMmjQJO3bswIYNG9C5c2c2zd7eHjExMZg/fz7UajUqKyuxdOlS TJkyhVO6WCxGaGgoYmNjwTAM0tLSsGPHjgZ1qKmpgZeXFwYMGHBf2kwIIeTRQIEkIe1s1KhRmDZt Gtzc3ODt7Y2QkBBMnz4dcrkcgDbQlMvl8PHxQVhYGKKjo9kLabik79y5EydPnoRYLMbcuXMxceLE BnUwNTWFp6cnu6ROCCGEcEEX2xDSzvr3748NGzYgODgYAFBQUIA+ffpgw4YNGDJkSDvXjhBCCGmo /mIbOkeSkHakUqmQnp6OrKwsuLq6QiAQ4PTp0zAzM0PPnj3bu3qEEEKIXhRIEtKOBAIBDhw4gHXr 1uHjjz+GpaUlwsPDkZCQQPd6JIQQ8sCjpW1CCCGEEGIUuo8kIYQQQghpEQokCSGEEEJIs1AgSR4b CpUClwv+gVKtbO+qEEIIIY8ECiTJQy0+/Qh6b+nP/nya+EWT2646/QlmHZiLtefW38ca6ldZLkOf zp9h3NPft0v+R11tbS28vb3h7e0NMzMzHDt2zKj0B1FcXBzefPNNzttPnjwZX3zR9HHxsOvZs+dD 8b61lZa0/1E6PjQaTXtX4bFFgSR5qPnYeWPyE69goFd/g9sGOQXCVmSLAEf/+1CzR0d8fDwEAgGc nJzYn/pHMD7oLCwskJmZiczMTISGhhqdfq8FCxbgp59+alY9vv32W4SFhcHe3h4DBgzA+fPnm1UO Ia2pNY+P9pScnEz33G1HdPsf8sD57rvvIBKJMHbsWIPb+tn7ws/eF8fvnMDxOyf0bjumyyiM6TKq tarJiouLQ58+fR7pxwt27doVV65cae9qtCuJRILa2lqj83366af49ttvsW3bNoSGhuLs2bNIT09H r1692qCWhDx+SktL27sKjzWakSQPjIKCAjz33HM4duwYnnnmGfb1vzITMPfQOxi243kM2T4cyxJi UaWs5lxu3++e0ln+/ubSFp10Bgz23jqAV/6Ygqe2DsHY31/Brym/s+m1dbVYe24dRuwciaE/jsDy E3GQKqRs+ujRo7FkyRLMmzcPMpmsWW2vU6qxcOZePN1tPd4Y8zNysyrYtPKyWqx45yCG9fgaL/bb hI2fnkGdUs05P6C98Xn37t0xefLkZtVPn+vXr2PChAkICgqCq6srJk+ezD7eEQDy8vIQHh6OkpIS TJgwAS4uLhg8eLBO3ZYtW4aAgAD4+/vjtddeQ1VVFQCge/fuOHXqFLudWq1t95YtWzBz5kyD+VuT SCSCubm5UXlqa2uxYsUKbNu2DWFhYRAIBIiKisK4cePYbSorKzF16lR4eHigc+fOiI2NZdsJaAPY l19+GS4uLujduzdSUlJa1I45c+Zg/PjxYBjtnd969uyJy5cvY/To0XB0dETPnj2Rnp7OqX5c3p+8 vDwMGzYMXl5eCAgIwLhx45CRkcGprlzKBwCpVNpk/Q2ND0Ptb2n9Wjo+ufSfvvYbOj7b0okTJzBi xAgMGjQIvr6+2LdvH3x8fHQ+3w31j7704uJihIaGYvz48Th9+jS7DH/v5wtpexRIkgfCTz/9hEGD BmHq1KnYvn077Ozs2LT9tw8hpzIXUR59YCuyQXz6kQbBoD6vPTEJU8Mmo59Hn0bTf0z+CStPfYRS WRkG+TwFa1Nr5FcVsOkrTqzEz9d/Q6BjAKI8++Fw+lGsOv0Jm+7n54cTJ06gY8eO6N27d7OWLfNz KiGtkEHsaYvkv/MQ++4hAIBGw2DB9D8Rv/sGuoa7w8HZCj98fR7rV53klL+eXC5Henp6i4OQxqSl pWHMmDFITk5GRkYGUlJSsHHjRp1tCgsLMX78eDz//PPIyMjA1q1b2bTly5fj5MmTuHTpElJTU2Fj Y4OFCxcCAHr06MHeq2zo0KGYPXs2AO1SVvfu3Q3mb00ikQgikcioPKmpqRCJRAgLC2tym2nTpoHH 4yE9PR0XL17E/v37dc5pnDZtGoRCIbKzs7Fnzx7k5eU1uw0rVqxAamoqvv/+e/B4PJ19LFiwAKmp qXBxccGqVas41Y/L+7NixQp4e3sjMzMTN2/exJgxYzjfn5hL+QCwbNmyJuvPZXzoa39L69fS8cml //S1n8vx2ZYOHz6ML7/8Er169cLq1atx4cIFXLhwATk5OQAM94++dGdnZyQnJ2P9+vXo27cvuwx/ 9OjR+9Y+AkAqlTL6fghpa5s3b2Z69OjBlJSUNJpeWFXIKFRKhmEY5lbpbSZycxQz5tcJOtv8lZnA RG6OYtacXdvkfvak7mMiN0cxG//ezL6mYTTM4B+GMX2/fYrJk+azr6s1anbfkZujmBE7RzKJOeeY cznnmQm7JjN9vh3I1KnrGuzj2rVrjLOzM5OUlMSp7RWSWuZJn0+ZUf21dVKrNMxTXb5gnvT5lJFW yJiUpALmSZ9PmcnDtzEMwzCyWiUT5f85E+X/OaNUqgzmv1dZWRkjk+m+xsWhQ4cYPp/PODo6sj97 9uxpsJ1UKmUuXrzIjB8/nhk3bhz7em5uLgOAOX78eKPl29jYMImJiezfxcXFjIeHB8MwDPPVV18x 06dPZ1QqFdOvXz8mNDSUYRiG6d+/P3Px4kWD+e8VHh7OHD16tMl2GkpfsmQJc+DAgSbTG3P48GEm ICCA/Xv48OGMWCxmunbtyjAMw5SXlzN8Pp+pqKjQyRMYGMgwDMNIJBLGxMSEkUgkbHpsbCwze/Zs znV49dVXmbVr1zLr169nunTpwlRXV+ukh4eHMwcPHmT/3rp1K9OnTx9O9ePy/qxYsYIJCQlhEhIS GKVSybneXMvXV3+GMTw+DOVvaf24js+mGOo/rvVv6vi8t5yWHB+NSUhIYJ544gmGYRhm6dKlTGxs LMMwDNOtWzcmISGBYRjD/cOl/3777Tdm8ODBRtWNtFxSUhKTlJTE0DmSpN1FR0fjxx9/xOLFi7Fm zRpYWVnppEtk5fjs3Dr8nX8JtXXac9RKalvnnJhyWQWqldVwsnBER2s39nUTnnayPu/fmcnimhLM i5+vk1dWJ4O12d2ZgezsbMydOxcjRoxA586djaqH0JSv3S+fB7GnHdJulqCiXIa87EoAgG+QEwBA ZC6Eu6ctstIlKC6ogpW1md781jZ3Z9Ba8shFfedI5uXlYc6cOaiurkZ4eDgEAgEqKyt1trGysmr0 HNLS0lJIpdIGS+71dQ0LC8P27dtx9epVBAQE4NSpU5BIJLhx4wZCQkIM5m9NYrHY6HK9vLyQl5cH hmHA4/GwZ88elJWVITAwEACQmZkJR0dH2NjYsHl8fX2RmZnJpjs5OenM0DfHrl27UFxcDKlUiqKi Ivj4+OikC4VC9ncXFxcoFApO9TP0/gDAwoULYW9vz86YDR8+HCtXroS7u7vBenMpX1/9uY6PpvK3 tH6tMT659J+++nM5Pu+He2fA63831D/38/gmzUeBJGl3Hh4eOHbsGNatW4devXph/fr1GDhwIACg pq4Gsw7MhaOFIz4b8jE62/lg2I4YMNB9sqdIoA2YJDKJUfu2M7eFuUCEktpSpJdnoLOd9gtWrpJD JBChUwcxAKCjdUf8PGobBCaNHzJbtmzBmjVr8Nlnn2Ho0KFG1QEAe76aUqFCYZ4UJnweXDt2QFWl 9gsh7aY2cFbIVcjLqoBAYAJnN2vUViv15r9XZWUlzM3NYWpqanT99Bk7dizmzJmDUaO0FzJt3boV u3fv5pTXwcEBVlZWiI+Ph4eHR4P0bt264ebNmzh79iyefPJJKBQK7Nq1Cy4uLhCJRDAzM9Ob/14m JiZQqVTNTn/99dc5tele3t7e6NChA44cOYKnn366QbqnpydKS0tRVVXFLldmZGSwV8U7OztDIpFA Lpcbvax+r8zMTJw5cwbx8fGYPHkyEhISdL7Ym2KofobeHwDg8/mYNWsWZs2aBYlEgtmzZ2PGjBnY u3evwf1zKV8fQ+OrpVpzfDalJf0HcD8+W3p8NIeh94fr+ycSiVBWVtaqdSPc0TmS5IHA4/EwZ84c 7N69Gx9++CH7QVcuq4BMJUetSobEnHN4/+hC1KnrGuT3s+8MgYkAp7LPYMWJlfj6IrdzgHjg4aV/ r+Sed+g9fHTmU7yx/03Mi38PDBg4WTriKe8ByK/Kxxv752DT5W+x5Phy/HL97sU4S5YsQUJCAhIT E5sVRAJATmY5Fs3ai7mv/I7qKgUGPxcIoSkfgV1d0KW7G1KvFWHRrL1465XfoFJpEDMuFEIh32D+ ejU1NfDy8mqTK8uzsrLA52v3dfv2baPOv+LxeJgxYwZmzpzJzpIUFxezs5/m5uZwd3fHH3/8gYiI CPTt2xc7duxgzz8zlP9enp6eOHjwIBiGgUTS8B8OfekMw6BXr15G3b8RAAQCAZYvX47p06fj0qVL 0Gg0uHDhAptub2+PmJgYzJ8/H2q1GpWVlVi6dCmmTJkCQDsLGhoaitjYWDAMg7S0NOzYscOoOgDA vHnz0KlTJ0ydOhUikYjzfSUN1c/Q+wMAixYtwvXr1wEAdnZ2CAoKYv/xMYRL+foYMz6aozXHZ1Na 0n8A9+OzJcdHcxnqH679FxwcjGvXriE7OxsAUFJS0ir1I9xQIEkeKPUXrkRERAAAxB3cMaX7q1Cq lTiUfgQhziGIcA9vkM/RwhHz+7wDO5EtTuecRWrZrQazlk15Pew1zI6YAXOhOQ6lHUa1sgZDOj/N flgv7rcA47qOQWltKXZe/Rl50jzYiu4u9U2fPh3btm2Dra1ts9v9zPPBqKlSICO1FE8N88fbS7Uz siYmPKz+vxhEjwjE5XM5KMyrwsQZEXjzg/6c8tczNTWFp6cn/Pz8ml3Hpqxbtw6rV69GSEgIlixZ ghkzZhiVPy4uDhEREYiMjERwcDBiYmKQn5/PpoeFheH8+fMICgpC3759kZCQoBNIGMpfb/HixTh8 +DA8PDwaDQgNpTfX1KlTsWzZMkyZMgWOjo5YsWIFvv/+ezZ9y5YtkMvl8PHxQVhYGKKjo/H222+z 6Tt37sTJkychFosxd+5cTJw40eg6mJjc/ajftGkTVq9ejVu3bnHKa6h+ht6fiIgIzJs3D4GBgfD3 90diYiLWr+f+UABD5RvCdXw0V2uNz6a0tP+4Hp/tdXwY6h8u/eft7Y2VK1ciKioKQUFBmDBhQqvP npKm8aRSqd5vW65X1xFCCCGEkMdD/R0LaEaSEEIIIYQ0CwWShBBCCCGkWSiQJIQQQgghzUKBJCGE EEIIaRYKJAkhhBBCSLNQIEkIIYQQQpqFAklCHhNJSUlwc3PDxYsX27sqhBBCHhEUSBLymHBzc8PI kSMhFovbuyqEEEIeEXRDckIIIYQQYhS6ITkhD4jr169jwoQJCAoKgqurKyZPngy5XM6my+VyTJo0 Cf7+/hAKhTA3N4e3tzcOHjzIKf/gwYPh7e0Nb29vCAQC9rm99Xr27InLly9j9OjRcHR0RM+ePZGe nn5/Gk8IIeShRoEkIe0sLS0NY8aMQXJyMjIyMpCSkoKNGzey6WvWrEF1dTVSUlJw9epVmJmZITk5 GUOHDuWU/+jRo8jMzERmZiacnJwarcO0adOwYMECpKamwsXFBatWrWrbRhNCCHkkCNq7AoQ87mJi YgAAVVVVSE1NhZ+fHy5cuMCmp6SkIDo6GgKBAIGBgXBwcEBOTg6Cg4M55eciLi4OYWFhAIDRo0fj m2++aY2mEUIIecRRIElIO8vLy8OcOXNQXV2N8PBwCAQCVFZWsunR0dHYuHEjnn76aVy4cAFqtRp+ fn6c83MhFArZ311cXKBQKFreMEIIIY88WtompJ2NHTsWY8eORXx8POLi4jBw4ECd9PpzIxcvXowT J07g2LFjOoGfofytpbKyEkqlsk3KJoQQ8nCiGUlC2llWVhb4fD4A4Pbt29i4cSNcXFzY9C1btmDS pEmYOnVqs/K3hpqaGnh5eSEoKAhnz55t1bIJIYQ8vGhGkpB2tm7dOqxevRohISFYsmQJZsyYoZM+ atQoTJs2DW5ubvD29kZISAimT5/OXpltKH9rMDU1haenp86SOiGEEEL3kSTkAde/f39s2LCBvbim oKAAffr0wYYNGzBkyJB2rh0hhJDHUf19JGlpm5AHmEqlQnp6OrKysuDq6gqBQIDTp0/DzMwMPXv2 bO/qEUIIecxRIEnIA0wgEODAgQNYt24dPv74Y1haWiI8PBwJCQmwt7dv7+oRQgh5zNHSNiGEEEII MQo9IpEQQgghhLQIBZKEEEIIIaRZKJAk5BGhUClwueAfKNV003BCCCH3BwWS5JFWWS5Dn86fYdzT 37dL/paKTz+C3lv6sz+fJn7R5LarTn+CWQfmYu259fexhm2rtrYW3t7e8Pb2hpmZGY4dO2ZU+v2U lJQENzc3XLx4Ue92cXFxePPNN+9LnZrTP/ezflxMnjwZX3zR9Lgn3Gg0mvauAicP2vgjhlEgScgD zMfOG5OfeAUDvfob3DbIKRC2IlsEOPrfh5pxExYWhk2bNjV4/e2338asWbMM5rewsEBmZiYyMzMR GhpqdPr95ObmhpEjR0IsFrdrPe71IPXPo+q5556Dk5MTzMzMYGVlBScnJyxevLi9q6UjOTmZ7jlL 2gzd/oc8cr777juIRCKMHTv2vuwvLi4Offr0wYABA1q9bD97X/jZ++L4nRM4fueE3m3HdBmFMV1G tXodWsLPzw/Z2dkNXs/NzUVkZGQ71KjtODs7Y/36R2c2mHCzb98+ANpn3kdGRmLu3LntXKOGSktL 27sK5BFGM5LkkVFQUIDnnnsOx44dwzPPPKOTVqdUY+HMvXi623q8MeZn5GZVsGnlZbVY8c5BDOvx NV7stwkbPz2DOqWac/7Ro0djyZIlmDdvHmQymdH1/iszAXMPvYNhO57HkO3DsSwhFlXKas75+373 lM7y9zeXtuikM2Cw99YBvPLHFDy1dQjG/v4Kfk35nU2vravF2nPrMGLnSAz9cQSWn4iDVCHVKUOl UqF79+6YPHmyUW3z8/NDTk4OAGDEiBGYPXs2ACAnJwedO3dmy162bBkCAgLg7++P1157DVVVVUbt pyXy8vIwbNgweHl5ISAgAOPGjUNGRgabfv36dUyYMAFBQUFwdXXF5MmT2cdTAsDgwYPZ5WOBQIDr 16/rlC+RSPDyyy/DxcUFvXv3RkpKSqvWv7KyElOnToWHhwc6d+6M2NhYqNVqwxlboX4nTpzAiBEj MGjQIPj6+mLfvn3w8fHROf641G/nzp3o3r073N3d0aNHD+zZs6fJfc6ZMwfjx48Hw2jvXGdo/OTl 5SE8PBwlJSWYMGECXFxcMHjwYJ0ymzu+W4pL//F4PJSVlbF/13/W1NM3fouLixEaGorx48fj9OnT 7Dj9b/v16dmzJy5fvozRo0fD0dERPXv2RHp6OptuqP8NpRsaf4aOT9L+KJAkj4SffvoJgwYNwtSp U7F9+3bY2dnppOfnVEJaIYPY0xbJf+ch9t1DAACNhsGC6X8ifvcNdA13h4OzFX74+jzWrzrJKT+g DZZOnDiBjh07onfv3jh//rxRdd9/+xByKnMR5dEHtiIbxKcfaRAM6vPaE5MwNWwy+nn0aTT9x+Sf sPLURyiVlWGQz1OwNrVGflUBm77ixEr8fP03BDoGIMqzHw6nH8Wq05/olCGXy5Genm50EFQfSDIM g7S0NJw9exaAdkayPpBcvnw5Tp48iUuXLiE1NRU2NjZYuHChUftpiRUrVsDb2xuZmZm4efMmxowZ o3P/3LS0NIwZMwbJycnIyMhASkoKNm7cyKYfPXqUXT52cnJqUP60adMgFAqRnZ2NPXv2IC8vr1Xr P23aNPB4PKSnp+PixYvYv3+/UecUtrR+hw8fxpdffolevXph9erVuHDhAi5cuMD+A2Gofr/88gs+ +OADfPfdd8jLy8OPP/6I2traRve1YsUKpKam4vvvvwePxwPAbfwUFhZi/PjxeP7555GRkYGtW7fq pDd3fLcGQ/1niL7x6+zsjOTkZKxfvx59+/Zlx+nRo0eNquO0adOwYMECpKamwsXFBatWrWLTDPW/ oXRD48/v1P5oAAAgAElEQVTQ8UkeAFKplNH3Q8iDbvPmzUyPHj2YkpKSBmkVklrmSZ9PmVH9NzMM wzBqlYZ5qssXzJM+nzLSChmTklTAPOnzKTN5+DaGYRhGVqtkovw/Z6L8P2eUSpXB/P917do1xtnZ mUlKSuJc/8KqQkahUjIMwzC3Sm8zkZujmDG/TtDZ5q/MBCZycxSz5uzaJsvZk7qPidwcxWz8ezP7 mobRMIN/GMb0/fYpJk+az76u1qjZfUdujmJG7BzJJOacY87lnGcm7JrM9Pl2IFOnrtMpv6ysjJHJ GrZZnzNnzjB+fn7MtWvXmJiYGMbLy4spLy9nBAIBU1NTwzAMw9jY2DCJiYlsnuLiYsbDw6NBWeHh 4czRo0eb3Jeh9KasWLGCCQkJYRISEhilUtnkdlKplLl48SIzfvx4Zty4cY1u4+rqyly7do39WyKR MCYmJoxEImFfi42NZWbPnm10PRtTXl7O8Pl8pqKign3t8OHDTGBgYINtG+ufltYvISGBeeKJJxiG YZilS5cysbGxDMMwTLdu3ZiEhARO9YuMjGR27NjR5D5effVVZu3atcz69euZLl26MNXV1TrphsZP bm4uA4A5fvy43rY0Z3zf6+WXX2bWrm36+GyMof5jGIYBwJSWlrJ5Fi9ezLz11lvs31zG72+//cYM HjzYqLrVCw8PZw4ePMj+vXXrVqZPnz7s34b6X186l/HH9fgk919SUhKTlJTE0DmS5KEXHR2NH3/8 EYsXL8aaNWtgZWXVYBuhKR8AYMLnQexph7SbJagolyEvuxIA4BuknUkSmQvh7mmLrHQJiguqYGVt pje/tY2I3Ud2djbmzp2LESNGsLNtXEhk5fjs3Dr8nX8JtXXamZiS2tY5p6lcVoFqZTWcLBzR0dqN fd2Ep12MyPt3ZrK4pgTz4ufr5JXVyWBtdvc//+Y8krF+RvL06dPo1q0bNBoN9uzZAycnJ1hYWKC0 tBRSqbTBkuL9fPzjwoULYW9vz864DB8+HCtXroS7uzsA7dLanDlzUF1djfDwcAgEAlRWVnIqu36W 8r8z5K0lMzMTjo6OsLGxYV/z9fVFZmbmfa9f/Qzhvb9zqd/t27fRpUsXvWXv2rULxcXFkEqlKCoq go+PDwBwHj9WVlYGz2Fu70eONtZ/XBgav61BKBSyv7u4uEChUAAw3P+G0rmMv/vRPtIytLRNHnoe Hh44duwYgoOD0atXLxw/frzBNsy/51MpFSoU5klhwufBtWMHdOyk/YJLu6kN3BRyFfKyKiAQmMDZ zdpg/npbtmzBkCFD8M4772DTpk2wtLTkVPeauhrMOjAXmeWZ+GzIxzgy8QCEfCEY6D65VCTQBqwS mYRrtwAA7MxtYS4QoaS2FOnld88rkqu05/h16qC9wrijdUecmnwMiVNOsD/3BpGA9lw3pdK4e1TW X836119/oVevXujVqxcOHjzIBtoODg6wsrJCfHw8bty4wf5cuXKlQVkmJiZQqVRN7stQelP4fD5m zZqFxMREpKWloa6uDjNmzGDTx44di7FjxyI+Ph5xcXEYOHAg57KdnZ0hkUh0zqlsTZ6enigtLdU5 5ywjIwNeXl4Ntm2sfx6E+nl5eSE1NVVvOZmZmTh8+DCWL1+OyZMns8ejMePHkOaM7/vB1NQUJSUl 7N//raOh8QsAIpFI5zzL1mKo/w2lcxl/XNpH2hcFkuSRwOPxMGfOHOzevRsffvghdu/erZOek1mO RbP2Yu4rv6O6SoHBzwVCaMpHYFcXdOnuhtRrRVg0ay/eeuU3qFQaxIwLhVDIN5gf0J78npCQgMTE RAwdOtSoepfLKiBTyVGrkiEx5xzeP7oQdeq6Btv52XeGwESAU9lnsOLESnx9cWMjpTXSL+DhpX+v 5J536D18dOZTvLH/TcyLfw8MGDhZOuIp7wHIr8rHG/vnYNPlb7Hk+HL8cv13nXJqamrg5eXVrCvT /fz8cOrUKURERCAyMhKnTp1iA0kej4cZM2Zg5syZ7CxfcXFxo4GAp6cnDh48CIZhIJE0DKgNpTdl 0aJF7AUydnZ2CAoKYgMVAMjKygKfr32vb9++rXN+pCFisRihoaGIjY1lzxPdsWNHg+0YhkGfPn0w apRxV93b29sjJiYG8+fPh1qtRmVlJZYuXYopU6Y02Lax/uFav+biUr833ngDCxcuxM2bNwFo+/uT T3TP0Z03bx46deqEqVOnQiQSsedYGjN+9GnJ+G5r/v7++OGHHyCXy7Fv3z5s375dJ93Q+AWA4OBg XLt2jb2Dwr2BaUsY6n9D6VzGH5f2kfZFgSR5pNRf+BIREaHz+jPPB6OmSoGM1FI8Ncwfby/VziqZ mPCw+v9iED0iEJfP5aAwrwoTZ0TgzQ/6c8oPANOnT8e2bdtga2trdH3FHdwxpfurUKqVOJR+BCHO IYhwD2+wnaOFI+b3eQd2IluczjmL1LJbDWYtm/J62GuYHTED5kJzHEo7jGplDYZ0fpr9MF7cbwHG dR2D0tpS7Lz6M/KkebAV2eiUYWpqCk9PT/j5+RndRj8/P1haWrJXfBYUFOgs/cfFxbFBZnBwMGJi YpCfn9+gnMWLF+Pw4cPw8PBo9IbFhtKbEhERgXnz5iEwMBD+/v5ITEzUuY3PunXrsHr1aoSEhGDJ kiVGz4bs3LkTJ0+ehFgsxty5czFx4sRGt+Pz+fjjjz+MnjnasmUL5HI5fHx8EBYWhujoaLz99tsN tmuqf7jWr7kM1W/KlCl499138eKLL8LT0xMjR45kl67rmZjc/aratGkTVq9ejVu3bgHgPn70acn4 rr+P5K5du7Bo0aJWv4/k559/jp07d8LX1xdHjhzBypUrddINjV8A8Pb2xsqVKxEVFYWgoCBMmDCh WbP3jTHU/4bSDY0/Lu0j7YsnlUr1fhvR1VGEENL25HI5XF1dUVRUBDMzs/auDiGE6JWcnAyAZiQJ IeSBsGrVKowaNYqCSELIQ4UCSUIIaWeHDh2CRqMx6vxLQgh5ENDSNiGEEEIIMQotbRNCCCGEkBah QJIQQgghhDQLBZKEEEIIIaRZKJAkpJ317NkTx44da/P9ZGdnIzo6Gq6urnjiiScQHx9vVP6kpCS4 ubnh4sWLbVRDrbi4OKPuA9laDLVPo9E0+nprvX9tXT4hhLQFCiQJeUy89957CAgIwJ07d5CYmIh+ /foZld/NzQ0jR46EWCxuoxq2L33tS05OxpAhQ9ps321dPiGEtBVBe1eAEHJ/JCcn47vvvoNIJGpW fmdn50f6iRL62ldaWtqm+27r8gkhpK3QjCQhD4DLly+jX79+cHFxQUxMjE5goVKpsGzZMgQEBMDf 3x+vvfYaqqqqOJf93nvvITAwEGlpaRg5ciS8vb0xePBgNj0vLw/h4eEoKSnBhAkT4OLiopM+ePBg eHt7w9vbGwKBgH3uLdf69ezZE5cvX8bo0aPZxySmp6ez6RKJBC+//DJcXFzQu3dvpKSk6JSfl5eH YcOGwcvLCwEBARg3bhwyMjI4tb179+44deoUW0+1Wg1A+9i+mTNnGmxfcXExQkNDMX78eJw+fZrd 7t7+AQCpVNpk+/RpjfIN9X9Lxw8hhOhDgSQhD4AjR47gl19+QU5ODoRCId5//302bfny5Th58iQu XbqE1NRU2NjYYOHChZzL/uSTT3Dz5k14eXnhwIEDyMzMxNGjR3W2KSwsxPjx4/H8888jIyMDW7du ZdOOHj2KzMxMZGZmwsnJqUH5XOo3bdo0LFiwAKmpqXBxccGqVat00oRCIbKzs7Fnzx7k5eXp5F2x YgW8vb2RmZmJmzdvYsyYMZzvb9ujRw/2XmdDhw7F7NmzAWhnZ7t3726wfc7OzkhOTsb69evRt29f drv/9t+yZcuabJ8+rVG+of5v6fghhBB9KJAk5AHw/vvvw83NDaamppg0aRIOHDjApq1btw4rV66E lZUVeDweFi5ciD179rTq/vPy8rBw4UKMGjUKlpaWcHd355yXS/3i4uIQFhYGBwcHjB49Gjdv3gQA lJeXY/fu3fjyyy9hZmYGJycnREdH6+QVi8U4efIkTp48CZVKhZiYmEYD2saEhYXh6tWrUKvVUCgU OHv2LADthTX1gWRr+Oijjxpt3/0o31D/34/xQwh5fNE5koQ8YLp06QKJRAJAe+6cVCrF5MmTdbax t7dv1X1aWVlhwIABRufjWj+hUMj+7uLiAoVCAQDsLKCdnV2T+1i4cCHs7e3ZGbnhw4dj5cqVnILd sLAwbN++HVevXkVAQABOnToFiUSCGzduICQkxJim6tVU+9q6fEP9f7/GDyHk8UWBJCEPmPT0dPj4 +AAAHBwcYGVlhfj4eHh4eLRzzRpqaf2cnZ0hkUggl8ubvAiIz+dj1qxZmDVrFiQSCWbPno0ZM2Zg 7969Bsvv1q0bbt68ibNnz+LJJ5+EQqHArl274OLiYtRFRyKRCGVlZZy3N1ZzyzfU/8a8P5WVlTA3 N4epqanR9SCEPL5oaZuQB8Dvv/8OuVwOqVSK5cuXszNIPB4PM2bMwMyZM1FZWQlAe4HGlStX2rO6 rJbWTywWIzQ0FLGxsWAYBmlpadixY4fONosWLWIvgLGzs0NQUBAYhuFUvrm5Odzd3fHHH38gIiIC ffv2xY4dO4xe1g4ODsa1a9eQnZ0NACgpKTEqf1uVb6j/ub4/NTU18PLyatasNCHk8UaBJCEPAG9v b/Tq1QtBQUGIjIzEvHnz2LS4uDhEREQgMjISwcHBiImJQX5+fjvWVldL67dz506cPHkSYrEYc+fO xcSJE3XSIyIiMG/ePAQGBsLf3x+JiYlG3YYoLCwM58+fR1BQEPr27YuEhASjA0lvb2+sXLkSUVFR CAoKwoQJE6BSqYwqo63KN9T/XN4fU1NTeHp6ws/Pr9XaRAh5PPCkUqnef+25Xh1JCCGEEEIeD/V3 xKAZSUIIIYQQ0iwUSBJCCCGEkGahQJIQQgghhDQLBZKEEEIIIaRZKJAkhBBCCCHNQoEkIYQAqFNq cPtGFerqNO1dlWZ52OtvyKPevvZG/UuaiwJJQsh9k5IkxR8786DRcLuh+P304+ZsrI29jd+35bZ3 VZrlYa+/IW3VPlmtGls33EFJkfGPtaypVmHW+MtY8V5Kq9apPTzq44e0HXpEIiEPgKP7i7Dv1wK8 HxcIN3fuj+57UMrnIj9Xhm/WZiA4tAN4PF6rlcswwJF9RbhwqgwV5XXw8bfEuCkesLU3RXZmLT5a fLPRfF/9GKbzt6ePBW5claKTt0Wr1e1efx0sxu/btV/S78cGwoPDfhgGuHBaghOHi1GQJ4eVtQCR UQ4Y9qIb/tuFbV3/puRmy/DbD7nIzqyBvYMphr3ohrDIpp+d3lxt1T6NhkFWei3WrbqNRauDYSZ6 POdX9PXvg/D5QR5cFEgS8q+K8joIhTxYWjV+WLQ0XZ/SIoV2SamNJuraunwufvo2B5aWfLw606tB ENQSv/6Qg8QTZXhpohiu7ub48+c8bN2QhbmL/GBppQ286slq1Uj6uwK+AVYNyhn4jDMGPuPcehW7 R3GhAnt+yYdIZAK5nPvSYZ1Sg8N7C2FqaoInBzji6uUKHNhVABs7Ifo+5aizbVvWvylKhQZff5wG pUKDfoOckHq9ClvWZcKqgwD+wa37MIu2ap+llQBT3/LGqg9u4sCuArwwzt3oMlpzPLcXff3L5fOD YR6NfiDGo0CSkH/t+jEXnj6WGDSs8Q/TlqY35u+z5fhxUxaUSm1wEfu+donM1l6IuHVdAQByuRr7 fi3AlfPlUKkYBHfrgFETxWzAWlKkwG/bcpFxqxomfB48vS0w6FkXBHSxbpXyD+wqwP7fC/C/L0OQ cKgYlxLLITQ1weKPgyEQcPvmyM2WIT21GqNf7QRTM+4zPvUziiHdbfDGu51RVVmHBTOvQuxpjg9W BqG0SIFTx0oxbooHevfXBozDXnTDlytvQyHXwMHJFBOne7Ll7dySDXMLPibN9GJfe/OVK9Co735D PvO8K4a/1BEAcPJICX7+PgfPj3VH9HMuAIA/duTh6P4ivLXYH35BVvjm8wwk/V2hU28rawE++r9Q ANov2G0bs2DdQYAuT9jg1FHd52jr619TMxPMW+wPS2sBeDzAw9sCP/zfHZSVKDnVv6ZahfnTk9E9 whYaDXArpQpuYnNMnO4JZ1czAEBRvhw/fZeDzLQa1CnvBrkTp3tCqdDobT+PB1SW12HQMGe8MM4d slo13n8jGYf3FrGBpL7y7w3ym6KvfYb6TyDggWGAcyfLcPxQMUqKFLB3NEW/QU4YMMSJLaOj2Bw9 Iu1w5ngpho/uyHlc1zM1NcGuH3Px99ly8AU8THjdEwFdtO2/cqEcp/8qRV6WDGoN0KVbB4x5tRPM LfgA9B+/XBTly7F9Uzbyc2ToGmaD0iIFqqtUWPZZF4PHj6H+5fL5AQA5d2rxzecZsLIWYM5CP7Zt 5PHweM7hE3KPG8lSyGrVqK1Wo7ZGhYryOqSnVrdauj6uYhGih7vAwckUABAV7YRnR7ph0DAXdpsf NmTh+KFieHhbIDTcFn+fLceOzdn3pN/BtSuVeHKAI/oMcERpiZI936s1yq+39as7SIgvgaOzGdzE IqO+bK//UwkA6Bpm02j6nbQaVEu1z5aWy9QozJNzKvdWShVMhTz07GMPACgrUaIgV5u3qrJOZ9uc O7U4c7wUTw11hr2jKfv6sBdc8exIN4Q2UreefewhNDXBpcRy9rWrlythYyeEb6B2VrNHbzs8O9IN Q19wZZdFI/ras9sfP1SMjFvVeHlyJ/D1fOI21b9WHQTIy5Hh6P4iHNhVADsHU0RG3S1fX/3rXblQ gdoaFRydzZBxqxo/bLjDpn331R2k3axGzOiO7HL7syPd4ONnZbD99e3Nz5GjukqF2zerYWLC03n/ 9JXPBZf26eu/o/uLsP2bLEgr6tAj0g4WFnyUlTQ8H7JrDxvIatXIvM3t2L1XdmYtrl6pRAdbISSl Svx2z3mG505KUFKoQGgPW1hZ83HxjAR7f737rHN9x68hGjWD//ssHRm3qiH2NIekVInMtBqj6q6v f7l8fgDAPxcrIClVIjuzFrdvGN9/5OFGM5LksSaXq7H7pzzk58jBMwHSUqsR/2chevS2Q+cAqxan GyL2MIfYwxy3UqpRVqJE1GAnuInvnoMkKVMi6e8K2NoL0W+wE3g8ICu9BsmXK6FWM+DzeZDLtLMF VVIVukfY4pnnXdlZv9Yov15JsQLLPuuiE4RxJSlVwoTPg519w7z/92k6rl6uBF/AQ6++9qitVSM7 vRbL13YxWG5JsRIOzmYQCHj486c8HNlXBDNR47Mhxw+VgMfjod8g3SXhoS+4AQDOJpQh+XKlTpq5 BR9hvWxx/pQExQUKgAcUFcgx8Blndhmvx7/nAx7aXQiFXAMvX0s8P1a7PFq/pN2rnwO6PGGD60lS PW1pun+vnC/Hod2FALQzrg5OZpzqX8/R2QxvLfaHRsPgnSlJyEyrQU21CubmfORm1cLdwxwDhzpD aGqC7MxsdPKygLObdh/62i/2tEDXMBtcvVyJ92ckw9ZeCJHIBAq5GoA20DFUviFc2tdU/zEMEP9n Ifh8Ht5bEcgGREwjS7SOztr6lJUo4RfEqWosW3shFq0KBgC8PeUfFObL2aXeMZM7oUMHIQRCHnKz ZFi18AZuXqti8+o7fg3JTK9BcYECvoFWmLfEHwq5Bm9P+ceouuvrX0OfH/XCetnhn4sVsLISwD+Y 2z8I5NFBgSR5rIlEfHywMgjxewqx5+d8qMFg7iI/dlmupektVVasnZmokNThq4/TdNIUcg0sLPkY N9UDP2y8g/OnynD+VBlE5nyMebWTzqxYS8qv99Qzzs0KIgFtQMHjNTyHqqxEidwsGeb/LxAFuTIk xJeAYRi8OtsLJiaGZzzrlBpYdxCgqECOw3uL8NIrndDJyxyfrbjVYP//XCyHm1gEaxuhUXV/coAj zp+S4MrFcpiaar/gw3vrXkxy+0Y19v9eAAtLPl6b7c0G4GePl6JOqWHfm3ofLb7JLo3X09e/z43q iP7RTjh1rBQHdhWgvEyJCa97NrptY/j/zs6ZmPDg5GqGvGwZaqrVsLQSwNlNhMI8Oa5dqcQ/FyvA 44Fd9jbUfh4PmP52Z2TcqoZcroFvgBU+fOsaG5SZ8HkGy6/X0nPsGuu/amkdZLVq2NoJ2SCyvt7/ ZfJv7KZpxt1vzER8CITaQi2tBJBW1oFhGPB4PFRVqvDbD7lIvSZlz4+tlNw9NaElx6+kVFuOm9i8 yXbdD+4e5lj8UTCdI/mYokCSPPZUKgbnT0rQq58DCvJkOHO8VCcQbGk6FyJz7bdYabFC5z9+J1ft 747OZvhwTbDODGE9V3cRlq7pgrxsGZIvV2L/b/n4+btsnS+ilpR/t4zmn/dk52AKtYpBlVQF6w53 P3YcnEzxvy9CwONprxr97zlz9cuT0n+XqaWVKp10B0dT3EqpYoNOVZ0G509JGuw/N0sGhVwDsafx V/z6BlrB2c0M1/+RwsKSDwcnU3j5WrLp1VIVvvsqExoNg4nTvXQCluBuHWBxz8VXyZcqkHm7Bv2f doKjs27Q01T/pqdWo3OAFTrYChHR1x4HdhXgjpHLl/UXSdTVabSzwyY8Nujq+5Qjdv+Uhy1fZsLC io/RkzrBpePdMWKo/XKZGj7+VuDxgGtXKlFdpdK5attQ+UDrnGPXWP9ZdRDC1MwEFeV1yM+RoWMn bcClVGgazPrVB2V2Dsb9o6GPXKbG2thbsLUTYuZ8X3TsZI4FbyTrXLPC5fhtSod//ymqX6pXq3Wn Wg0dP1w19flRj33/Oggwd6Ffiz4ryMOHAkny2MvLlsHeyRTjpnqgukqFzWszIKtVs19mLU3nwtvP ElcvV+K3bbm4faMKCrkGY6d4wNZOiO4RtrhyoQKf/+8WAkOsUVyggI+/JQYMcUZtjRr/ey8FLh1F 8A+2+ndWhweb/ywhN7f81hIQYo39vxcgJUmKXv10vyD1zWLYO5pCIOAhJ7MW61bfRl62TGd7Bxcz lBQpYGMrRM8+9jj0ZyEioxyw8quuOgFrUYH2nD0bu+YFCX0GOOLPn/MhEPJ0+oVhgO+/voPK8jo4 OpshP0eG/BwZAGBIjCv8g611/qmokCiRebsGkVEOsHMwPLt7J60Gn//vFjp5WUDsZYFbKdolUWP/ USkulGPzFxmorFBBVqtGRF97nXMIO4rNETXYESZ8Hswt+A0C/qbar1Yz+PrjNKjVDDp2Mselc9oL XZ4efvccOi7l159jJylV4vaNaoT20H8+JFc8HjBwiDPi9xTiq4/SEBJmg8J/z6F9a4m/zlhKSZZC aGrC+dxNLqqkKigVGijkGlxPkmLvrwVQqRh2hpjr8dsUb19LWNsIkJIkxfqP0lBTpRsoGjp+uGrq 86Peve/frZTWe//Iw4EutiGPPU8fC8x+3xcCAQ+2dkK8uzxAJwhsaToXA4c4o3d/B8jlapw7KUFh nhxKhXYZbOJ0Lwwa5ozK8jocO1CMkmIFLK21X8KmpiYYNtINapUGfx0sxonDJQju1gGvv+XTKuW3 Fh8/K7iJRTi8t1DnClFDROZ8vDBODAtLASQlSsSMcWdnlQAgqKs1RCI+zhwvxaszvbBmUzeMmiiG ja1QZ2m8fkbG0krP+9LYiXP/6tXPHjyediarxz2zbdXSOty4qj3vsbRYgb2/5rM/jJ7yuPLwtsCz ozpCo2Hw9xkJ1CoGg4Y548XxYqPKcXA2Q3WVGvk5MoRF2uGlVzqxad3CbZFzpxY/bs7Gto1Z+Obz DCyZe429aAlouv08AN162qKujsHl8+UQe1rgnaX+OkEyl/LDetnB1V0E3wCrVj/H7rlRbnhhrDtM RSa4cEoCmUyNnv+Z7ZOUKXH+lAThve1a9T6STi5mGPaiG+rqNLh4WgIfP0sEdr37TwDX47cppmYm eP2tznD3MMedtBp4+FjoBIqGjh+u9H1+AED3XnZwcRPBx89S53QN8njgSaVSvZ921tatey8wQsjj Ke1mNdbG3kJUtBNGT+pkOANHZ46X4ufvcjB8dEcEBFujMF8OOwdTo7/Q9v6aj0O7CzFqghgDh+rO xirkGiyZew0dbAVY/FFwq9W9rdXf/sfNXYTFHzesd1mJEivevY6xUzwQGeUAtZrBru25SDhcgldn erFXwze3/VzLb091dRp8uTINhflyfPhJsM5M6cNGqdBg3mv/wMnFDMs+M3yxGiEtkZycDICWtgkh 94lvoBXGTfVESlLDK8Jbos9AR5iZ8dnb4zi5mLFXohpSU63Cd1/dgbOLGS7+e4sbv//cvy9+TyGS LlagplqFURONmwl8UDT1RMryMiVUKgaXz5XDxlaI6moVriVJYW7Bh9+/y+ctaT+X8ttbbbUaJjxg 5nudH+ogkpD2QkcNIeS+eXKAA54cYPgm1MYKf9IO4U8a/1i+4gIF5DI1zp0qg629KV4c5w6xx92l P6VCg32/FsDKWoARoztyugDiYdI5wApDRrji/OkybFiTDitrAbx8LTH0BVfY2glb3H5D5T8IbOyE mPehf3tXg5CHFi1tE0IIIYQQo9QvbdPFNoQQQgghpFkokCSEEEIIIc1CgSQhj4g6pQa3b1Shrq4Z j+YgpI3R+CTk0UQX2xDyiPhxczYunpGg3yBHvPyah+EM5IGTkiRFakoVYsZ05PSIyPZ28YwE3399 h/27/9NN39rpQR+fGbdq8Pv2XOTnymDvaIpnYlwfiNsTEfKgo0CSkHYmq1Xjl605SEmWwszMBL36 OWDYi25GP4HC08cCN65K0cm74WMAj+4vwr5fC/B+XCDc3Bs+4qwlVi28gdwsmc5rHj4WeP9/gaiq rMOCmVfZ180t+PDqbIkXxrnD/Z6ro1OvV+HArgLkZctg52CKJwc4YMAQZ0598Nu2XBw/VKzz2tMj XLQ8zt0AABP/SURBVBEzpqNR7fjrYDF+354LAHg/NhAejfRjY/JzZEi+VImzCaUoK1HiwzXBcHEz vo/zc2X4Zm0GgkM7gPdvw+vvC/hfHcXmWPRR0H3pX33cOpnjmeddUZgvxz8XKvRuq298tlRLx3dd nQbfrE1HtVSFHr3twAMPHWzv31XliSfKcOJwCUqKFBB7mOO5l9zgF2SNogI5VrybAlMzE6z6uitE Ij4+mHkVdXUarNnUDQW5csS+n4LAEGu8+YEfAGDRm1chq1Xjsy1PcNq3vuOXEC4okCSknW1am4HU 61Xo5GWBmmoVDuwqgEbDYPhLxgVCA59xxsBnGn+sYWmRQrukqOceDdrHsxm1Sx1hvezY5xff+7xp ALDuIEBklAPyc2W4/o8UBZ/IEPtlV/B42serbf4iA3w+D75BVpCUKHHqWCkioxw4PSFIIVc32L+H t3FP7yguVGDPL/kQiUwglxu39Jp4ogyJJ8qgULRsyfanb3NgacnHqzO92PfBxISnvZG3isHFsxKI RCZ4IsIOtva6QU5b9q8+Yg9ziD3MceVChcFAUt/4bCku41ufogIFqipV8PG3wuRZ3q1bOQPi9xRi z8/5MLfgw8ffElnptbiUWA6/oLt3TFEqNLicWI4nBzq2WT30Hb+E6EOBJCHtKDujFqnXq+AmFmH+ igDUVKuweM41JBwqxjMxrijIk+OjxTcR0t0Gb7zbmZ2BEnua44OVQQCAN1+5ovPYwWeed2WD0L/P luPHTVlQKrVBTuz7KQAAW3sh4tZ1ZfPk3KnFN59nwMpagDkL/ZoVYIycKG7y3oA2dkI8P9YdABD3 /g3k58ogKVXCzkGI37blgmGAmfN9EdDFGhoNg5pq7s8qrw/8Jk73ZL8IjcEwwLaNWbDuIECXJ2xw 6miJUflHThBj5AQx1sbexu0bVUbvHwBys2VIT63G6Fc76bRBIORh4nRPyGrVuHhWAmsbISZO92yQ vy37l2GAcyfLcPxQMUqKFLB3NEW/QU4YMMSJU3594xMA5HI19v1agCvny6FSMQju1gGjJophaSVg n8wTFe0EgYCHS4nlEAh5GD/NEwFdrDmPb30Wz7mGynLtIzQzblVj1vjLOvmrpCrs+jEX1//Rrhj0 7GuPYS+4QSDURvsHdhVg/+8F+N+XIUg4VIxLidrnjS/+OJh9nnlTqqtUOLS7EAIBD/NXBMLZzQxV UhUsLXXfG6sOApxJKGvTQLKx4/ePHXk4dawEA552xtkTpXhxnBhH9xdBo2bwzjLto2CvXCjH6b9K kZclg1oDdOnWAWNe7cSOL0Pjp6RIgd+25SLjVjVM+Dx4eltg0LMuCOhCtx58WFAgSUg7ys3WLil1 6WYDEz4P1jZCePhYIuNWNUpLlJzKGPaCKxgGyMmsRfLlSp00V7EI0cNdcO5kGcpKlIiKdoJ1BwFE 5rpfVP9crICkVAlJqRK3b1QjtIeN0W3586c8mP0bBD01zAXOrmY66QwD3EmrQUmxAmYiE9jaC1FW okR5mRKdvCzYLw4TE55RTxhRyLQzksvfvQ6FXIOQ7jY6X2SGHD9UjIxb1Zj5XmekJEk577c1Xf9H +751DTO+3+u1Vf8e3V+E3TvzYN1BgB6RdijKl6OsRME5v77xCQA/bMhC0t8VCA2zgZWNEOdOlEGp 0GDaPc+bPnmkBM5uZuhgK0TOnVr8ti0Xi1YHcR7f+kRFO6G4QI7EE2VwcxchLNKOzc8wwMbP0pF5 uwahYTaQSlWI/7MQCpkaL/3nXNCtX91BZloNvH0tYWHFNxhEAkDunVooFRqE9rCBs5v2eGnsvQkO 7YALpyXIz5VBIOChro5z8zhr6vhVyDW4cqEc8loNtn2TBWdXMxTmyZGeWo2Q7jY4d1KCkkIFQnvY 4vbNKlw8I4GFJZ89V9bQ+Plhwx1k3K7B4GddwOfz8M/fFSgpUlAg+RChQJKQdlRZof1GsLS6+8Vn 9e/vleV1sLA0/IVY/zjAswllDb6o65ceb6VUa79oBzvBTdzwHLKwXnb452IFrKwE8A827hnV9S6c lrC/9+htrxNI5mbJMHvCZQDa5fMRozuCz+ehrFj7hWLv2PyltLBIO1h1EMLb1wLnTklw8Yx2CZjL BR31S9q9+jmgyxM2uN5OgaSkVAkTPg929s3rh7bqX4YB4v8sBJ/Pw3srAtklT8aIJWR941NSpkTS 3xWwtRei32An8HhAVnoNki9rH6NZz9ZeiEWrtM/4fnvKPyjMl/9/e/ceHXV553H8PbfMTGZyGUMg lyGECFFA6nJRghcUtyDLCihewcvW9bbrnu6BLe7WSrXelmLtaqXW2na3Fbf1tLq2R7ZqrS7LUlDE qkQIIQkSICQk5DoZMpOZycz+McmECCYzk8QE/LzOyUlOMs+TZ375/TLf+T7f5/cQicR/fvdn4ZJx 7K/w8u6WJnLybSxe3ru95qEDHRyoPM74wlTu+cbZBDrDrLlrF1vfaeSam919gsVjDZ1859+mJXSs mxqjbxZdWdE2j9xXRn2tH4DHf9ibUbWnmpg4ycH2zU3Y7CZ83W+ehlJ/1+91t7rZ9HIdjjQTcy7J 4oXnqqmv80fftN0+nvR0C2aLgZqDPtZ9ay/lu6OZ+XjOH78vmk1u94SYcWEmi67OSWpmQUaOAkmR EdQzheXz9dbX9XztcJoSesEejPwCO2vXTx1UjeTjP5z+uVPbaelmZs09i//9QwPZOVYWLMkBILM7 cGppii/7eiol87IomRfddrF4WhqPrCmjYq/3pMedqgZ0++ZGgoEwO7Y2sWNrU+z769eWs2ptMZOn OPttP1TCXREMhuT7H67j6/UE8XV0kemy9KmbG6rj0BPotjYHefaJqj4/6zyhVtVqM8Wmkh1OM562 IJFIJLYoabg01kfH554QrblNsRoZM85Kfa2f1qYAY8b1BltXLBqbcMCe0b2gp90TAmDOpWexc1sz dTX+Po/zekJcdHkWr/2mlnG5Nlq6Yz5jd7wVPqE8NxImqRX//V2/ZosRgxHMZuNJf/v2thCvbKxh 325PrMykrTnQPe6Bz5+Vdxaw8fnq2DVos5u48Wvjz7jtSM9kCvtFRlDPytpP90UDn2AwzOHqDiwW I9k51ljGw9MW7P4cSur32OzRS72x4dRTkoerO3hw1W7Wf7sc/zBkOzJcFq6/zc2556XRUNfJrg+i CzOyc6w4nGYOHYjWigKEwxFqa3z9ddfHvj3tsYDb2/2C/NlMbuz5rS3H19H7/Kaen86ym/JjHxMn O4DobWzGjE0ZsP1QcWWl0BWKxAKKRA3X8XWmW0ixGmltCVJ7uLdN4DMLi3oySO0Jnp/ZOdHs4Zix Vp7ZOINnfzkz9hFPNr7HQOd3srK6z4Ej3SUowUCYxvpOTCYDmVl9g8ZEptN7uAtTMZoMlH3cRmtL kCuX5jBx8skzAqFQhJlzXXR2hqk70htk9rxRqK3xEYlAe1uQttZg0pntRPl9XTz9WAV1NT7u/edJ PPnT8zGbDbE1T/GcPzn5Nh56chrfWjeFq67Po9Pfxa9/fugLGb8MDWUkRUZQUbGTPLedqn1e/vMn B2lpCuD3dTH3sixsNhNnjUnBbDZw+EAHG75byZFDvqSyQRMnO/jkwzZeebGGyr3tdPrDrLijd+r3 xBrJirLkaiR/+6saUqzRF9MUi+GkGjKI3panfHf0VjTnz87EZDKw/OZ8Xnz+ID96ooriaWmxcdz/ +JRY3djnqT3sY8O6SvIL7OQX2GNT0xdc1Deb8Xk1oMVT0yie2luL1doc4EDlcUrmZcWmG/trD/C7 l44QifQGMX/cVI/DaY7eC9IU3x/rnPPS+P1/1VG2y8OcS3vHHgpG+PULhwkFe6f/fvmzQ2S6LPz1 tbkn9TPUx9dggPlXjuUPrx3l2fVVnDczg6Pd2bJV3y6OnYvuAjsmk4HSP7ey8cfVZGRaWHZT/oDP O9NlYcaFmXz0fitPPVoRC4SLih1cfmX8K7wHOr+TNaHIwcRJDg5UHeenP/gUT2uIrq4Ily3MjqsG ciCZLgtX/NVY3v7vetbdv5cJZ6eyf9/xUz7WZjMxq8TFu1uaYvW/VpuRc6enUf5JO4/9Sxn+7jc5 X5k9PNfvZ7V7QgQ6w3T6w+zZ5WHTy3WEQhFM3cdmoPPH19HFo/eVMS7PRvFUZ3fW30DGFxQIy9BQ RlJkBBkMcNfqIvLG23l3SxPlu9s5b0YG193mBqJZjmtWukl1mGk+FmDZjfnkjU/s1jYQ/Wc+97Is /P4u3vu/Zo4e8ffJCsyY42Jcro2iyY4+07mJ+GB7C9s3N7J9cyM7Tqi3OtE509IoKErlyCEfH++M Zs1K5mVx9+oi8gvs7N/nxWgwsPT6vAGDHIBct51rb3FjNhv5eGcrNpuJa1bmM29B3xXFM+e4yMm3 MekcZ1I1oP21f+eNBt7+fX1s+vjdLU3Rla0J3A2oaLKTXLeNtzYd7bPCORyOsH1zY6x+ze/rYvvm xs+91c5QH1+Aq67L5ZoV+aTYjLy/tRmfr4sLPjPtmOGysOKOApzpZj75sI1D1R1xl2Xcek8hf7l4 LG0tQd55vYFjDZ040hLLcQx0fifLYIB7/qmICy46i4oyL82NnSxcmsPyle5B993j6pvyue4WN+kZ FqrKveTk2fibvy885TTzxadYtX3bPYWcPzsTT2uQcBgu/Wo2i5blJDyOeK7fz8oeZ2Xx8lyCwTA7 /9RM0WQH507vu0imv/MnJcXI4mtz6QqF+Z83Gtjy1jGmnp/O3ScstJLRz+DxePq93NPStHJKZLhF IvDkQ/uo3n+ca1bkc/EVYzCZDCo6/xKpKvfy9GMVzFvw+bvDiIiMFqWlpYAykiKjgsEAK+4sINVh 4rcvHWHNXbvYuT2+rICcGSad62TlnRPwtAb7rFgWERnNlJEUGUW87SH+/F4LHd4Q02dl4i5IfBpb RERkuPVkJLXYRmQUcaaZuWxBfDuGiIiIjDRNbYuIiIhIUhRIioiIiEhSFEiKiIiISFIUSIrIsPJ1 dPHCc9Ucqx/aXUdERGTkabGNyAiKROD9PzWz5a0G6o74caaZKZmXxeLlubFdQwKdYV7eeJjSD9uw Wo1cPH8MC5fmxL3DzWDbv/JiDZvfbOjzvYVLc1h2Y15c/YfDEQ7u72DDukoe+O5UrDa9fxUROVPo P7rICAoGwry16SiRCFx0+RgMBnj91Tq2bW6MPeal/zjEu1ua+IvZmeS67bz2m1q2vn0s7t8x2Pad /ui2azPnuCiZl0XJvCwKJvbelmig/h1OM3eumkhLU5DXX62L+/eKiMjop4ykyAhKsRpZvbYYR5oZ gwEKJqay8cfVNB2Lbrd33Bti57ZmZsxxseKOAiIReGj1brb88dhJ2wCeymDbA/j90a3mbr1nwkk7 7cTbf57bzqwSF9s2N7Lkhrwh2adYRERGngJJkRHmTDdTc8hH+Scetr7diCsrhZJ50b1oGxsCRCLg LrDz/YcrGF9oJ3+8nT27PEQiDDg9Pdj2AJ2+aEby4TV76PSHOW9GBjd+bTz2VFNC/U+flcHO7c0c qPQyeYo2OhARORMokBQZBT7a0cKbvzsKwOLluWRlWwEIBaPZQKPJQDAQJhiMYDQbCIcjhMMRTKb+ I8HBtgeYWeLCmW5h4qRU3tvazM5tzdhsRm7624KE+h8zNvqcmo4FmDwlwQMkIiKjkgJJkVHgquvy uGxBNlvfaeT1V+toaQpwy90TyHBZAOjwhvjm4+cC8NSjFTjTzScFgafKMA62PRCriwQonpbGI2vK qNjrTbh/Y/eseDgc92EREZFRTottREbY/n1eDAZIz7Rw4SXRKe3qquMAuLJScDjN7NvTDkCnP8zB TztwT0jt08fh6g4eXLWb9WvL8XV0xb4/2PYA+/a0E4lEv/Z6QgCkOkwJ9Q/Q3BjobmNJ8AiJiMho pYykyAiqrjrOU49WML4wFXdhKhVl0YCseGq0htBkMnDxFWN467Wj/OJH1bQ0BQgGwictlPl4ZyvN 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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 07 Feb 2023 15:24:02 +0000 Resent-Message-ID: <handler.60936.B60936.167578341529278 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.167578341529278 (code B ref 60936); Tue, 07 Feb 2023 15:24:02 +0000 Received: (at 60936) by debbugs.gnu.org; 7 Feb 2023 15:23:35 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Sun, 19 Feb 2023 15:07:03 +0000 Resent-Message-ID: <handler.60936.B60936.16768191647556 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16768191647556 (code B ref 60936); Sun, 19 Feb 2023 15:07:03 +0000 Received: (at 60936) by debbugs.gnu.org; 19 Feb 2023 15:06:04 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 20 Feb 2023 15:32:01 +0000 Resent-Message-ID: <handler.60936.B60936.16769070861940 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16769070861940 (code B ref 60936); Mon, 20 Feb 2023 15:32:01 +0000 Received: (at 60936) by debbugs.gnu.org; 20 Feb 2023 15:31:26 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Thu, 09 Mar 2023 14:43:02 +0000 Resent-Message-ID: <handler.60936.B60936.167837297413464 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.167837297413464 (code B ref 60936); Thu, 09 Mar 2023 14:43:02 +0000 Received: (at 60936) by debbugs.gnu.org; 9 Mar 2023 14:42:54 +0000 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> 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-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 --=-=-=--
Received: (at control) by debbugs.gnu.org; 8 Apr 2023 23:10:59 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Sat Apr 08 19:10:59 2023 Received: from localhost ([127.0.0.1]:59841 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1plHhy-0005DK-SG for submit <at> debbugs.gnu.org; Sat, 08 Apr 2023 19:10:59 -0400 Received: from mail-108-mta124.mxroute.com ([136.175.108.124]:43857) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1plHhx-0005D6-4E for control <at> debbugs.gnu.org; Sat, 08 Apr 2023 19:10:57 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta124.mxroute.com (ZoneMTA) with ESMTPSA id 1876322fd17000edb4.001 for <control <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Sat, 08 Apr 2023 23:10:50 +0000 X-Zone-Loop: 1b1d124ae0f85b7e918bde762c5bb61ca63a902661e4 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=hqjJpmYmesA1fNJAvtSuqfdydhtQQHqqfU2/J9f9mrQ=; b=crjCf0KQSQaWeVMQ/vxyebOrz/ XEYU0ZF4cnYZcAVQp/goGbQTX/TQIBnfnMVA5hhI/gIXRiOJbXXmJHJLnYmVK9g/B1V1YTYxDIUeq OWFZYyRNsL5kqx8mRNQGSofG2D2kisbQ8LD6U7ZiOg8ykCp3FXGKbZEZzQvFjQXm5YnFN13om3onw jgAcS7sLeXru+VIhBzypyV9XPlJm4lpARynE1Q8i/8Nyn57EOHw4/A8FmnVaJGtIsLsq7oSImx+AM 1aPVSxHgn9aSLeJwOBMGpX2WiJPorn3Q0YpLtgXSOHxbX0KTTNmzDbfGCUdebVZ8fTmTkE+yHeD8S uqOJEBGQ==; From: "J.P." <jp@HIDDEN> To: control <at> debbugs.gnu.org Subject: control message for bug #60936 Date: Sat, 08 Apr 2023 16:10:47 -0700 Message-ID: <87zg7i3r7s.fsf@HIDDEN> MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: control 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 (-) close 60936 30.1 quit
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 10 Apr 2023 20:50:02 +0000 Resent-Message-ID: <handler.60936.B60936.168115978518990 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.168115978518990 (code B ref 60936); Mon, 10 Apr 2023 20:50:02 +0000 Received: (at 60936) by debbugs.gnu.org; 10 Apr 2023 20:49:45 +0000 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> 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-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.
Received: (at fakecontrol) by fakecontrolmessage; To: internal_control <at> debbugs.gnu.org From: Debbugs Internal Request <help-debbugs@HIDDEN> Subject: Internal Control Message-Id: bug archived. Date: Tue, 09 May 2023 11:24:05 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator
Received: (at control) by debbugs.gnu.org; 9 May 2023 19:30:54 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue May 09 15:30:54 2023 Received: from localhost ([127.0.0.1]:44543 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1pwT2z-0002cN-UE for submit <at> debbugs.gnu.org; Tue, 09 May 2023 15:30:54 -0400 Received: from mail-108-mta167.mxroute.com ([136.175.108.167]:43369) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1pwT2w-0002c8-Cg for control <at> debbugs.gnu.org; Tue, 09 May 2023 15:30:53 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta167.mxroute.com (ZoneMTA) with ESMTPSA id 18801fe92d8000becb.001 for <control <at> debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Tue, 09 May 2023 19:30:40 +0000 X-Zone-Loop: 6a557e8aa65a4543986c0f89da7b87431173d3deda62 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=+9WXKYcyEWUyED97D+/LA/huZLVfUwmQg9I2F4g9VuI=; b=EVoMwaKBd7XyT+c3FmtEOlNVla KoZpYr4QBb1xU3ZRJpb+YIq7LUz4/v5lBOnKZiCGwNfGDR6ayM5xNUW0WN9lLKV5TAmwGXk8HMzZ6 XUH6pBiS0BPdbklXklRFdZiBvg+kLT/ZBMvIioUNkxepg6R8fxtwcjlibaRjYuPvMWmkaAQclQssl HnxPxvvEHM1/fEsv7oXOl63dWaGnio2gMb/3D9B/3/yOyyC6Rs2mDHMLoHptqVIU+/46DkFEMBWFp YGSYtPVEsZSnPtRNCzwYQjYtUG+PyR33VN8w6hLNWuCTUVCFts4BD/1cGZOYctSSSY/+VHeYvcCxB CTTFuPPA==; From: "J.P." <jp@HIDDEN> To: control <at> debbugs.gnu.org Subject: control message for bug #60936 Date: Tue, 09 May 2023 12:30:33 -0700 Message-ID: <87r0rps3om.fsf@HIDDEN> MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: control 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 (-) unarchive 60936 quit
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 09 May 2023 20:47:02 +0000 Resent-Message-ID: <handler.60936.B60936.168366520427909 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.168366520427909 (code B ref 60936); Tue, 09 May 2023 20:47:02 +0000 Received: (at 60936) by debbugs.gnu.org; 9 May 2023 20:46:44 +0000 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> 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-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
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 22 May 2023 04:22:02 +0000 Resent-Message-ID: <handler.60936.B60936.16847292746158 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16847292746158 (code B ref 60936); Mon, 22 May 2023 04:22:02 +0000 Received: (at 60936) by debbugs.gnu.org; 22 May 2023 04:21:14 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 30 May 2023 14:16:02 +0000 Resent-Message-ID: <handler.60936.B60936.168545611032637 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.168545611032637 (code B ref 60936); Tue, 30 May 2023 14:16:02 +0000 Received: (at 60936) by debbugs.gnu.org; 30 May 2023 14:15:10 +0000 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> 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-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.
Received: (at fakecontrol) by fakecontrolmessage; To: internal_control <at> debbugs.gnu.org From: Debbugs Internal Request <help-debbugs@HIDDEN> Subject: Internal Control Message-Id: bug archived. Date: Wed, 28 Jun 2023 11:24:05 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator
Received: (at control) by debbugs.gnu.org; 28 Jun 2023 20:56:17 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jun 28 16:56:17 2023 Received: from localhost ([127.0.0.1]:51776 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1qEcD3-0007qP-6a for submit <at> debbugs.gnu.org; Wed, 28 Jun 2023 16:56:17 -0400 Received: from mail-108-mta171.mxroute.com ([136.175.108.171]:46509) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1qEcCx-0007q7-Js for control <at> debbugs.gnu.org; Wed, 28 Jun 2023 16:56:15 -0400 Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta171.mxroute.com (ZoneMTA) with ESMTPSA id 18903cacb2e000ca8f.001 for <control <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Wed, 28 Jun 2023 20:56:09 +0000 X-Zone-Loop: 75228f8399371113d4e7eb06d628814509c6d481669b 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=+9WXKYcyEWUyED97D+/LA/huZLVfUwmQg9I2F4g9VuI=; b=fwxBrXgn4OFIFwwyrgVNtdUbIt I6DdmW3KWop219o+8hxuKVS3SCNHCa7l5EMrLJjCuKF/b0yG84nQCfAk2y7rC4WmTjpYbfV61lIEE +hgUljQ2VvS5GryXON74umgULC1XuhfxfQhv4QE3uhMBJDJeEI2yRLO1SpsaBzaBvF/5PivG4Y1xl g1sSPoGGeSjTbblIXalOU86qhr6EbdMvSYGc1ApHuSjfNLfAGMGm3h/4CWTnGSFAy3cB/knPHanRg LNflvej/lOtSOEBat0WeEbkVQNB0W9XsmrtaO7hg03Sgy7hgK0K0HRXGzBDusxTt+1PccLUNvZIBU tqvKuMOA==; From: "J.P." <jp@HIDDEN> To: control <at> debbugs.gnu.org Subject: control message for bug #60936 Date: Wed, 28 Jun 2023 13:56:05 -0700 Message-ID: <87h6qrxq56.fsf@HIDDEN> MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: control 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 (-) unarchive 60936 quit
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 28 Jun 2023 21:03:01 +0000 Resent-Message-ID: <handler.60936.B60936.16879861368159 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16879861368159 (code B ref 60936); Wed, 28 Jun 2023 21:03:01 +0000 Received: (at 60936) by debbugs.gnu.org; 28 Jun 2023 21:02:16 +0000 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> 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-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
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 03 Jul 2023 13:15:01 +0000 Resent-Message-ID: <handler.60936.B60936.16883900893275 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16883900893275 (code B ref 60936); Mon, 03 Jul 2023 13:15:01 +0000 Received: (at 60936) by debbugs.gnu.org; 3 Jul 2023 13:14:49 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 18 Jul 2023 13:35:02 +0000 Resent-Message-ID: <handler.60936.B60936.168968724416984 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.168968724416984 (code B ref 60936); Tue, 18 Jul 2023 13:35:02 +0000 Received: (at 60936) by debbugs.gnu.org; 18 Jul 2023 13:34:04 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 18 Jul 2023 13:56:01 +0000 Resent-Message-ID: <handler.60936.B60936.168968854820346 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.168968854820346 (code B ref 60936); Tue, 18 Jul 2023 13:56:01 +0000 Received: (at 60936) by debbugs.gnu.org; 18 Jul 2023 13:55:48 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 19 Jul 2023 13:17:01 +0000 Resent-Message-ID: <handler.60936.B60936.168977256631727 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.168977256631727 (code B ref 60936); Wed, 19 Jul 2023 13:17:01 +0000 Received: (at 60936) by debbugs.gnu.org; 19 Jul 2023 13:16:06 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Thu, 20 Jul 2023 13:29:02 +0000 Resent-Message-ID: <handler.60936.B60936.16898597386687 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16898597386687 (code B ref 60936); Thu, 20 Jul 2023 13:29:02 +0000 Received: (at 60936) by debbugs.gnu.org; 20 Jul 2023 13:28:58 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Sun, 23 Jul 2023 14:01:02 +0000 Resent-Message-ID: <handler.60936.B60936.169012081817395 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169012081817395 (code B ref 60936); Sun, 23 Jul 2023 14:01:02 +0000 Received: (at 60936) by debbugs.gnu.org; 23 Jul 2023 14:00:18 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Sat, 29 Jul 2023 00:00:02 +0000 Resent-Message-ID: <handler.60936.B60936.169058877311843 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169058877311843 (code B ref 60936); Sat, 29 Jul 2023 00:00:02 +0000 Received: (at 60936) by debbugs.gnu.org; 28 Jul 2023 23:59:33 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 09 Aug 2023 14:55:01 +0000 Resent-Message-ID: <handler.60936.B60936.16915928458634 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16915928458634 (code B ref 60936); Wed, 09 Aug 2023 14:55:01 +0000 Received: (at 60936) by debbugs.gnu.org; 9 Aug 2023 14:54:05 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: Michael Albinus <michael.albinus@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 09 Aug 2023 16:52:02 +0000 Resent-Message-ID: <handler.60936.B60936.169159988021202 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "J.P." <jp@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169159988021202 (code B ref 60936); Wed, 09 Aug 2023 16:52:02 +0000 Received: (at 60936) by debbugs.gnu.org; 9 Aug 2023 16:51:20 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 15 Aug 2023 14:02:02 +0000 Resent-Message-ID: <handler.60936.B60936.169210811826364 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Michael Albinus <michael.albinus@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169210811826364 (code B ref 60936); Tue, 15 Aug 2023 14:02:02 +0000 Received: (at 60936) by debbugs.gnu.org; 15 Aug 2023 14:01:58 +0000 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> 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-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
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: Michael Albinus <michael.albinus@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 15 Aug 2023 16:13:01 +0000 Resent-Message-ID: <handler.60936.B60936.16921159517344 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "J.P." <jp@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16921159517344 (code B ref 60936); Tue, 15 Aug 2023 16:13:01 +0000 Received: (at 60936) by debbugs.gnu.org; 15 Aug 2023 16:12:31 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: Michael Albinus <michael.albinus@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 15 Aug 2023 16:39:02 +0000 Resent-Message-ID: <handler.60936.B60936.16921174859699 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "J.P." <jp@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16921174859699 (code B ref 60936); Tue, 15 Aug 2023 16:39:02 +0000 Received: (at 60936) by debbugs.gnu.org; 15 Aug 2023 16:38:05 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 16 Aug 2023 14:29:02 +0000 Resent-Message-ID: <handler.60936.B60936.169219611916587 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Michael Albinus <michael.albinus@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169219611916587 (code B ref 60936); Wed, 16 Aug 2023 14:29:02 +0000 Received: (at 60936) by debbugs.gnu.org; 16 Aug 2023 14:28:39 +0000 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> 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-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/
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: Michael Albinus <michael.albinus@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 16 Aug 2023 17:40:02 +0000 Resent-Message-ID: <handler.60936.B60936.16922075481366 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "J.P." <jp@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16922075481366 (code B ref 60936); Wed, 16 Aug 2023 17:40:02 +0000 Received: (at 60936) by debbugs.gnu.org; 16 Aug 2023 17:39:08 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Thu, 31 Aug 2023 13:33:01 +0000 Resent-Message-ID: <handler.60936.B60936.169348872722851 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169348872722851 (code B ref 60936); Thu, 31 Aug 2023 13:33:01 +0000 Received: (at 60936) by debbugs.gnu.org; 31 Aug 2023 13:32:07 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 13 Sep 2023 14:07:02 +0000 Resent-Message-ID: <handler.60936.B60936.16946140063308 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16946140063308 (code B ref 60936); Wed, 13 Sep 2023 14:07:02 +0000 Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 14:06:46 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: Stefan Kangas <stefankangas@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 13 Sep 2023 15:57:02 +0000 Resent-Message-ID: <handler.60936.B60936.169462058825252 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "J.P." <jp@HIDDEN>, 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169462058825252 (code B ref 60936); Wed, 13 Sep 2023 15:57:02 +0000 Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 15:56:28 +0000 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> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Score: 0.0 (/) 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
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 13 Sep 2023 23:12:01 +0000 Resent-Message-ID: <handler.60936.B60936.169464669832554 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Stefan Kangas <stefankangas@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169464669832554 (code B ref 60936); Wed, 13 Sep 2023 23:12:01 +0000 Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 23:11:38 +0000 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> 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-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).
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: Stefan Kangas <stefankangas@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 13 Sep 2023 23:41:02 +0000 Resent-Message-ID: <handler.60936.B60936.16946484152700 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "J.P." <jp@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16946484152700 (code B ref 60936); Wed, 13 Sep 2023 23:41:02 +0000 Received: (at 60936) by debbugs.gnu.org; 13 Sep 2023 23:40:15 +0000 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> Content-Type: text/plain; charset="UTF-8" X-Spam-Score: 0.0 (/) 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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Fri, 22 Sep 2023 14:12:01 +0000 Resent-Message-ID: <handler.60936.B60936.16953918928398 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16953918928398 (code B ref 60936); Fri, 22 Sep 2023 14:12:01 +0000 Received: (at 60936) by debbugs.gnu.org; 22 Sep 2023 14:11:32 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 27 Sep 2023 14:01:02 +0000 Resent-Message-ID: <handler.60936.B60936.169582321922105 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169582321922105 (code B ref 60936); Wed, 27 Sep 2023 14:01:02 +0000 Received: (at 60936) by debbugs.gnu.org; 27 Sep 2023 14:00:19 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Fri, 06 Oct 2023 15:18:02 +0000 Resent-Message-ID: <handler.60936.B60936.169660547518033 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169660547518033 (code B ref 60936); Fri, 06 Oct 2023 15:18:02 +0000 Received: (at 60936) by debbugs.gnu.org; 6 Oct 2023 15:17:55 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Sat, 14 Oct 2023 00:25:02 +0000 Resent-Message-ID: <handler.60936.B60936.169724308927344 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169724308927344 (code B ref 60936); Sat, 14 Oct 2023 00:25:02 +0000 Received: (at 60936) by debbugs.gnu.org; 14 Oct 2023 00:24:49 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Sat, 14 Oct 2023 17:05:01 +0000 Resent-Message-ID: <handler.60936.B60936.16973030979764 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16973030979764 (code B ref 60936); Sat, 14 Oct 2023 17:05:01 +0000 Received: (at 60936) by debbugs.gnu.org; 14 Oct 2023 17:04:57 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 16 Oct 2023 14:09:02 +0000 Resent-Message-ID: <handler.60936.B60936.169746530511908 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169746530511908 (code B ref 60936); Mon, 16 Oct 2023 14:09:02 +0000 Received: (at 60936) by debbugs.gnu.org; 16 Oct 2023 14:08:25 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 17 Oct 2023 13:49:02 +0000 Resent-Message-ID: <handler.60936.B60936.16975505373641 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.16975505373641 (code B ref 60936); Tue, 17 Oct 2023 13:49:02 +0000 Received: (at 60936) by debbugs.gnu.org; 17 Oct 2023 13:48:57 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Thu, 19 Oct 2023 14:04:02 +0000 Resent-Message-ID: <handler.60936.B60936.169772422522420 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169772422522420 (code B ref 60936); Thu, 19 Oct 2023 14:04:02 +0000 Received: (at 60936) by debbugs.gnu.org; 19 Oct 2023 14:03:45 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 24 Oct 2023 02:21:01 +0000 Resent-Message-ID: <handler.60936.B60936.169811403328247 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169811403328247 (code B ref 60936); Tue, 24 Oct 2023 02:21:01 +0000 Received: (at 60936) by debbugs.gnu.org; 24 Oct 2023 02:20:33 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 24 Oct 2023 14:30:03 +0000 Resent-Message-ID: <handler.60936.B60936.169815780029655 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169815780029655 (code B ref 60936); Tue, 24 Oct 2023 14:30:03 +0000 Received: (at 60936) by debbugs.gnu.org; 24 Oct 2023 14:30:00 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: Corwin Brust <corwin@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Tue, 24 Oct 2023 17:12:01 +0000 Resent-Message-ID: <handler.60936.B60936.169816747325418 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "J.P." <jp@HIDDEN> Cc: 60936 <at> debbugs.gnu.org, emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169816747325418 (code B ref 60936); Tue, 24 Oct 2023 17:12:01 +0000 Received: (at 60936) by debbugs.gnu.org; 24 Oct 2023 17:11:13 +0000 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> Content-Type: multipart/alternative; boundary="000000000000a9b58c0608796a4a" X-Spam-Score: 0.5 (/) 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--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 25 Oct 2023 02:19:02 +0000 Resent-Message-ID: <handler.60936.B60936.169820031028421 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169820031028421 (code B ref 60936); Wed, 25 Oct 2023 02:19:02 +0000 Received: (at 60936) by debbugs.gnu.org; 25 Oct 2023 02:18:30 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 30 Oct 2023 13:50:01 +0000 Resent-Message-ID: <handler.60936.B60936.169867375719176 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169867375719176 (code B ref 60936); Mon, 30 Oct 2023 13:50:01 +0000 Received: (at 60936) by debbugs.gnu.org; 30 Oct 2023 13:49:17 +0000 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> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 01 Nov 2023 00:30:01 +0000 Resent-Message-ID: <handler.60936.B60936.169879858016007 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169879858016007 (code B ref 60936); Wed, 01 Nov 2023 00:30:01 +0000 Received: (at 60936) by debbugs.gnu.org; 1 Nov 2023 00:29:40 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 06 Nov 2023 02:32:01 +0000 Resent-Message-ID: <handler.60936.B60936.169923788324161 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169923788324161 (code B ref 60936); Mon, 06 Nov 2023 02:32:01 +0000 Received: (at 60936) by debbugs.gnu.org; 6 Nov 2023 02:31:23 +0000 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> 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-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.)
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Mon, 13 Nov 2023 21:04:01 +0000 Resent-Message-ID: <handler.60936.B60936.169990938112820 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.169990938112820 (code B ref 60936); Mon, 13 Nov 2023 21:04:01 +0000 Received: (at 60936) by debbugs.gnu.org; 13 Nov 2023 21:03:01 +0000 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> 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-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 --=-=-=--
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Thu, 07 Dec 2023 07:15:02 +0000 Resent-Message-ID: <handler.60936.B60936.170193329623935 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 60936 <at> debbugs.gnu.org Cc: emacs-erc@HIDDEN Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.170193329623935 (code B ref 60936); Thu, 07 Dec 2023 07:15:02 +0000 Received: (at 60936) by debbugs.gnu.org; 7 Dec 2023 07:14:56 +0000 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> 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-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 --=-=-=--
Received: (at fakecontrol) by fakecontrolmessage; To: internal_control <at> debbugs.gnu.org From: Debbugs Internal Request <help-debbugs@HIDDEN> Subject: Internal Control Message-Id: bug archived. Date: Thu, 04 Jan 2024 12:24:07 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator
Received: (at control) by debbugs.gnu.org; 15 Feb 2024 11:58:31 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 15 06:58:30 2024 Received: from localhost ([127.0.0.1]:54283 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1raaNq-0006Wi-JB for submit <at> debbugs.gnu.org; Thu, 15 Feb 2024 06:58:30 -0500 Received: from mail-40137.protonmail.ch ([185.70.40.137]:62415) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <tzakmagiel@HIDDEN>) id 1raaNm-0006WA-Vk for control <at> debbugs.gnu.org; Thu, 15 Feb 2024 06:58:29 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1707998281; x=1708257481; bh=f3S0P9MW+/Ch2kCaQNXyHd9QIqY5uhRj1M0Thwozm64=; h=Date:To:From:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=EU/VOq6YyJ0dWwapQg0h6jebwsE4+/3zVN25sUmnkaQ7iuIyHJ6Wgs7RvldiE9CUx hTox6LVEJl0CQiIHUh5F/+e9X/eVeQvxUnCpLdDoX1sze/l8qXCeDp4H56afgbwLHr kczdSFEZfRhpsNNXS6R7j4ULOws5JyToJ4dab3i5ZizOvEahgIsDGXswlC18cvLIpo V1sPJPipHAPbe/SHO4cXr0TJcBtPZrmewNzmvEzoV/H9tFlMQhibsiKfByK45Z3oPz fZDNzDh9u/Y/u7xgPUTo2PpYc1Y0KYDlM3XTxNCrKJoc5h2ZJ5DRjC7qMIX+iT3XsP Ee0U7szVB+Wrg== Date: Thu, 15 Feb 2024 11:57:49 +0000 To: "control <at> debbugs.gnu.org" <control <at> debbugs.gnu.org> From: tzakmagiel <tzakmagiel@HIDDEN> Subject: unarchive 60936 Message-ID: <YXvJodxhQ2DXLol69aPYrY0KVIzBY_Gk5n2lu9PX6s0c9v012Ub-fxMGZCU1wLk9_ZPEGWAd6hBF_j5J-BS4SOEf50OldpWMEiE9N4eqolk=@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: control 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 (--) unarchive 60936
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode References: <87tu0nao77.fsf@HIDDEN> In-Reply-To: <87tu0nao77.fsf@HIDDEN> Resent-From: tzakmagiel <tzakmagiel@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Thu, 15 Feb 2024 12:02:01 +0000 Resent-Message-ID: <handler.60936.B60936.17079985073553 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: "60936 <at> debbugs.gnu.org" <60936 <at> debbugs.gnu.org> Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.17079985073553 (code B ref 60936); Thu, 15 Feb 2024 12:02:01 +0000 Received: (at 60936) by debbugs.gnu.org; 15 Feb 2024 12:01:47 +0000 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 From: tzakmagiel <tzakmagiel@HIDDEN> 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-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.
X-Loop: help-debbugs@HIDDEN Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Resent-From: "J.P." <jp@HIDDEN> Original-Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org> Resent-CC: bug-gnu-emacs@HIDDEN Resent-Date: Wed, 21 Feb 2024 01:13:01 +0000 Resent-Message-ID: <handler.60936.B60936.170847797311233 <at> debbugs.gnu.org> Resent-Sender: help-debbugs@HIDDEN X-GNU-PR-Message: followup 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: tzakmagiel <tzakmagiel@HIDDEN> Cc: 60936 <at> debbugs.gnu.org Received: via spool by 60936-submit <at> debbugs.gnu.org id=B60936.170847797311233 (code B ref 60936); Wed, 21 Feb 2024 01:13:01 +0000 Received: (at 60936) by debbugs.gnu.org; 21 Feb 2024 01:12:53 +0000 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> 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-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.
Received: (at fakecontrol) by fakecontrolmessage; To: internal_control <at> debbugs.gnu.org From: Debbugs Internal Request <help-debbugs@HIDDEN> Subject: Internal Control Message-Id: bug archived. Date: Wed, 20 Mar 2024 11:24:08 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator
Received: (at control) by debbugs.gnu.org; 9 Apr 2024 10:31:19 +0000 From debbugs-submit-bounces <at> debbugs.gnu.org Tue Apr 09 06:31:19 2024 Received: from localhost ([127.0.0.1]:48416 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>) id 1ru8l4-0002dP-PU for submit <at> debbugs.gnu.org; Tue, 09 Apr 2024 06:31:19 -0400 Received: from mail-108-mta110.mxroute.com ([136.175.108.110]:39807) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from <jp@HIDDEN>) id 1ru8kz-0002cP-1H for control <at> debbugs.gnu.org; Tue, 09 Apr 2024 06:31:16 -0400 Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta110.mxroute.com (ZoneMTA) with ESMTPSA id 18ec26949100003bea.001 for <control <at> debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Tue, 09 Apr 2024 10:31:03 +0000 X-Zone-Loop: 048e755cda7b0d15c117c49659c24715bf0f9547f43a 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=+9WXKYcyEWUyED97D+/LA/huZLVfUwmQg9I2F4g9VuI=; b=f8dMsoeGeiKTk8sJXedPoNom0q zv+AFPaT2nK0FiTnLoWKFlz3xL8TYqJoqZWaYWOa+rImpX+iE3Oz5zYSFl7oZDxAFulwFg0/BiQhc AvrhBK9XdBXi8nH1fVIY7cCn+mIWG4b3o4rabXjsWuPDVNiAPy/XGcDWStYVtf3EJJThWK6H7N9ti ZYEgif5Orl8iAFivP5A79CJ//uej4HiXAt2fLLOy1MQju1YCBADnou2jUMUZ8WTzjOaM8DAYqjGhQ onHhlq6K31tUuS/tb/IwS9OjYoZfdfyozsDqJC5vITTJOaBJxwDofTx9bKPJiuwzfIy/YkOB8bkfd KpZgfjyA==; From: "J.P." <jp@HIDDEN> To: control <at> debbugs.gnu.org Subject: control message for bug #60936 Date: Tue, 09 Apr 2024 03:31:01 -0700 Message-ID: <87le5mddzu.fsf@HIDDEN> MIME-Version: 1.0 Content-Type: text/plain X-Authenticated-Id: masked@HIDDEN X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: control 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 (-) unarchive 60936 quit
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997 nCipher Corporation Ltd,
1994-97 Ian Jackson.