From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: "J.P." Newsgroups: gmane.emacs.bugs,gmane.emacs.erc.general Subject: bug#60936: 30.0.50; ERC >5.5: Add erc-fill style based on visual-line-mode Date: Wed, 18 Jan 2023 06:53:48 -0800 Message-ID: <87tu0nao77.fsf@neverwas.me> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="5137"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-erc@gnu.org To: 60936@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Jan 18 15:55:12 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pI9qK-0001Au-5X for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 18 Jan 2023 15:55:12 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pI9qD-00016Y-Ih; Wed, 18 Jan 2023 09:55:05 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pI9qB-00015h-Dd; Wed, 18 Jan 2023 09:55:03 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pI9qB-0005pR-34; Wed, 18 Jan 2023 09:55:03 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pI9qA-00051k-D1; Wed, 18 Jan 2023 09:55:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: "J.P." Original-Sender: "Debbugs-submit" Resent-CC: emacs-erc@gnu.org, bug-gnu-emacs@gnu.org Resent-Date: Wed, 18 Jan 2023 14:55:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 60936 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org X-Debbugs-Original-Xcc: emacs-erc@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.167405364619245 (code B ref -1); Wed, 18 Jan 2023 14:55:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 18 Jan 2023 14:54:06 +0000 Original-Received: from localhost ([127.0.0.1]:40005 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pI9pE-00050K-8Y for submit@debbugs.gnu.org; Wed, 18 Jan 2023 09:54:06 -0500 Original-Received: from lists.gnu.org ([209.51.188.17]:43346) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pI9pB-0004zt-9g for submit@debbugs.gnu.org; Wed, 18 Jan 2023 09:54:03 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pI9pA-0000rr-Tu for bug-gnu-emacs@gnu.org; Wed, 18 Jan 2023 09:54:00 -0500 Original-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 ) id 1pI9p6-0005hm-Vc for bug-gnu-emacs@gnu.org; Wed, 18 Jan 2023 09:54:00 -0500 Original-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 (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==; X-Authenticated-Id: masked@neverwas.me Received-SPF: pass client-ip=136.175.108.238; envelope-from=jp@neverwas.me; 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-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:253641 gmane.emacs.erc.general:2054 Archived-At: --=-=-= 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" 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" 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 . + +;;; 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" 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" 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 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 --=-=-=--