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#60954: 30.0.50; ERC >5.5: Stop requiring erc-goodies in erc.el Date: Tue, 14 Mar 2023 06:32:15 -0700 Message-ID: <87pm9bihls.fsf@neverwas.me> References: <87pmb9wyz6.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="30855"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-erc@gnu.org To: 60954@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue Mar 14 14:56:26 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 1pc58b-0007kS-J5 for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 14 Mar 2023 14:56:25 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pc51U-0000zq-6h; Tue, 14 Mar 2023 09:49:04 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pc51S-0000zb-OU for bug-gnu-emacs@gnu.org; Tue, 14 Mar 2023 09:49:02 -0400 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 1pc51S-0002Vj-Eu for bug-gnu-emacs@gnu.org; Tue, 14 Mar 2023 09:49:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pc51S-0004eR-4u for bug-gnu-emacs@gnu.org; Tue, 14 Mar 2023 09:49:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: "J.P." Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 14 Mar 2023 13:49:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 60954 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 60954-submit@debbugs.gnu.org id=B60954.167880168517590 (code B ref 60954); Tue, 14 Mar 2023 13:49:02 +0000 Original-Received: (at 60954) by debbugs.gnu.org; 14 Mar 2023 13:48:05 +0000 Original-Received: from localhost ([127.0.0.1]:36676 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pc50S-0004Z2-EV for submit@debbugs.gnu.org; Tue, 14 Mar 2023 09:48:04 -0400 Original-Received: from [66.45.233.19] (port=44411 helo=relay2-c.mailbaby.net) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pc4rM-0004LC-4b for 60954@debbugs.gnu.org; Tue, 14 Mar 2023 09:47:59 -0400 Original-Received: from zmta1 ([45.76.239.126] 45.76.239.126.vultrusercontent.com) (Authenticated sender: mb25440) by relay2-c.mailbaby.net (InterServerMTA) with ESMTPSA id 186e05748c60009da9.001 for <60954@debbugs.gnu.org> (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256); Tue, 14 Mar 2023 13:37:42 +0000 X-Zone-Loop: c5ed4aad66338d48bc8c9549202ad0735b7d317005b2 ARC-Authentication-Results: i=1; rspamd2.mailbaby.net; auth=pass smtp.auth=mb25440 smtp.mailfrom=jp@neverwas.me ARC-Seal: i=1; s=detka; d=mailbaby.net; t=1678801062; a=rsa-sha256; cv=none; b=IbrGerCf9a94jtidx2xSyDqdBng5OIlsqlDLqpgs2SSo2i+ABziUuHFK189ULrBGqC9LSs LpMjfJeWCpxgTPAFfyliJje5WJfRT33TAxLnwjLyIjhfbEXevEG9Z7Zu33Z/hw0EdfM6TF M7kW70Khd4ucHGepNSNTNwRTQttxNqwvzshNt6irXSX7tyab8uTsgat+9PEVibd3QPVRgq urC/8UPCblfm6AlCclFJj9RQZazbRR/3RUYfCp1OeymIWpZg92uM9KqVTdV4XU3exIRair yS47EFIZkG12QLFaShhtt76LwAX2ECFwbABHsOd0e+gKjAyxy9pKUtZzhcB8SQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbaby.net; s=detka; t=1678801062; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references:dkim-signature; bh=nc6Brc+tLE2RnD6DTksJxmFY22rjvdN6h/kyN8MZ4Rw=; b=pjYVuSJxpK36fVxHUSBLjuEEtflDdYF6JVIWkgFYJwnt5VHPSMw4S5kaQwcAZJgwMV5Hwi +iok7Fy47IIHMGVi+vA2MGG7HkmE2OL1pWSt5jbNmLZPY+etkY/GG8x+f8RV5W9gf65Ky+ 68JlQkrOXNnMnrF8EbWu4Sm1P+0BDBS8skEiiFxyQamR4I7Q9kjvsOrLFqkaaQtygTjSfO aFtsketnb3CNbEBOBRO0eMUvoPnL88OG9HHw5nbtw2BPYrVMBb700UI8q34B+le3oTQgIh f1oN9z0BMEEfcWKyDN1hRGtT+EyiXtBQjorPWfmlilfXKu3geQfFUofyMWUEZA== Original-Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by zmta1 (ZoneMTA) with ESMTPSA id 186e0526dfb000edb4.001 for <60954@debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Tue, 14 Mar 2023 13:32:23 +0000 X-Zone-Loop: 9298ebf14c582a56b514685ca9453693b9c04b3c3d64 X-Originating-IP: [45.76.239.126] 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=nc6Brc+tLE2RnD6DTksJxmFY22rjvdN6h/kyN8MZ4Rw=; b=F0IG8DzHQMAZE5+7+qYHuN9Fna Ni+cXHWDF7/6Lhux5JmFXarBJm5cVM0tArRvqvep+5E/HuE5109t1BPPpUHwe95WLGo5jaLKHwmx9 vwBsmABCYVyzRzHyeQo50/FHRZrPIGbbT9owtbkxCdS4aP1YXQ63U+T3KrxzflRggZzm6YDk5KfEe 9cCQqZ46st5IVu+QBRkvDXblo2kb5+ZFK6OqRw/vl2K6mW4Xn0ovBOv/zPsTgZkAdG8H1vog5DW5I IT1R+DfG9uK0AcUVtFCiL8cYTSNRxJCADOdbdoj2pS13oFqnww0/Kg9Pjh7O07bAepofWgKKGsDUB uhWpAENg==; In-Reply-To: <87pmb9wyz6.fsf@neverwas.me> (J. P.'s message of "Thu, 19 Jan 2023 21:34:37 -0800") X-Authenticated-Id: masked@neverwas.me X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:257933 gmane.emacs.erc.general:2107 Archived-At: --=-=-= Content-Type: text/plain v7. Prevent erroneous Custom "edit" state when initializing `erc-modules' on account of `standard-value' ordering mismatch. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v6-v7.diff >From 636bec56194f964907c5cf5d37f2cb18e338e64e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Tue, 14 Mar 2023 06:14:10 -0700 Subject: [PATCH 0/7] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (7): [5.6] Honor arbitrary CHANTYPES in ERC [5.6] Copy over upstream Compat macros to erc-compat [5.6] Leverage loaddefs for migrating ERC modules [5.6] Don't require erc-goodies in erc.el [5.6] Modify erc-mode-map in module definitions [5.6] Add missing colors to erc-irccontrols-mode [5.6] Convert ERC's Imenu integration into proper module lisp/erc/erc-backend.el | 2 +- lisp/erc/erc-button.el | 6 +- lisp/erc/erc-common.el | 39 +---- lisp/erc/erc-compat.el | 52 +++++- lisp/erc/erc-goodies.el | 117 ++++++++----- lisp/erc/erc-ibuffer.el | 1 + lisp/erc/erc-imenu.el | 23 ++- lisp/erc/erc-log.el | 8 +- lisp/erc/erc-match.el | 8 +- lisp/erc/erc-page.el | 4 + lisp/erc/erc-pcomplete.el | 2 + lisp/erc/erc-services.el | 1 + lisp/erc/erc-sound.el | 1 + lisp/erc/erc-speedbar.el | 1 + lisp/erc/erc-stamp.el | 4 + lisp/erc/erc.el | 108 ++++++++---- test/lisp/erc/erc-goodies-tests.el | 253 +++++++++++++++++++++++++++++ test/lisp/erc/erc-tests.el | 187 +++++++++++++++++++-- 18 files changed, 675 insertions(+), 142 deletions(-) create mode 100644 test/lisp/erc/erc-goodies-tests.el Interdiff: diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 1315bce2e54..e122f32d96a 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1850,7 +1850,9 @@ erc-modules (when-let* (((eq (car entry) 'const)) (s (cadddr entry))) ; (const :tag "..." ,s) (put s 'erc--module s))) - (custom-initialize-default symbol exp)) + (custom-initialize-reset symbol exp) + (put symbol 'standard-value + (list (custom-quote (default-toplevel-value symbol))))) :set (lambda (sym val) ;; disable modules which have just been removed (when (and (boundp 'erc-modules) erc-modules val) @@ -1873,6 +1875,7 @@ erc-modules (if (get v 'erc--module) (push v built-in) (push v third-party))) + ;; Calling `set-default-toplevel-value' complicates testing (set sym (append (sort built-in #'string-lessp) (nreverse third-party)))) ;; this test is for the case where erc hasn't been loaded yet -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Honor-arbitrary-CHANTYPES-in-ERC.patch >From 4b86ffb90b2cb12f96588aa3a6a0a59b3c425ab1 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Sat, 18 Feb 2023 19:32:36 -0800 Subject: [PATCH 1/7] [5.6] Honor arbitrary CHANTYPES in ERC * lisp/erc/erc.el (erc-channel-p): Favor "CHANTYPES" ISUPPORT item before falling back to well known prefixes. * test/lisp/erc/erc-tests.el (erc-channel-p): Add test. --- lisp/erc/erc.el | 12 ++++++++---- test/lisp/erc/erc-tests.el | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 69bdb5d71b1..dd3697ac50b 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1530,10 +1530,14 @@ erc-reuse-frames (defun erc-channel-p (channel) "Return non-nil if CHANNEL seems to be an IRC channel name." (cond ((stringp channel) - (memq (aref channel 0) '(?# ?& ?+ ?!))) - ((and (bufferp channel) (buffer-live-p channel)) - (with-current-buffer channel - (erc-channel-p (erc-default-target)))) + (memq (aref channel 0) + (if-let ((types (erc--get-isupport-entry 'CHANTYPES 'single))) + (append types nil) + '(?# ?& ?+ ?!)))) + ((and-let* (((bufferp channel)) + ((buffer-live-p channel)) + (target (buffer-local-value 'erc--target channel))) + (erc-channel-p (erc--target-string target)))) (t nil))) ;; For the sake of compatibility, a historical quirk concerning this diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index d6c63934163..bbf3269161d 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -447,6 +447,27 @@ erc-downcase (should (equal (erc-downcase "Tilde~") "tilde~" )) (should (equal (erc-downcase "\\O/") "|o/" ))))) +(ert-deftest erc-channel-p () + (let ((erc--isupport-params (make-hash-table)) + erc-server-parameters) + + (should (erc-channel-p "#chan")) + (should (erc-channel-p "##chan")) + (should (erc-channel-p "&chan")) + (should (erc-channel-p "+chan")) + (should (erc-channel-p "!chan")) + (should-not (erc-channel-p "@chan")) + + (push '("CHANTYPES" . "#&@+!") erc-server-parameters) + + (should (erc-channel-p "!chan")) + (should (erc-channel-p "#chan")) + + (with-current-buffer (get-buffer-create "#chan") + (setq erc--target (erc--target-from-string "#chan"))) + (should (erc-channel-p (get-buffer "#chan")))) + (kill-buffer "#chan")) + (ert-deftest erc--valid-local-channel-p () (ert-info ("Local channels not supported") (let ((erc--isupport-params (make-hash-table))) -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Copy-over-upstream-Compat-macros-to-erc-compat.patch >From 927962b4199cff9d2f3a9852021dadd563eb5a91 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 19 Jan 2023 20:52:47 -0800 Subject: [PATCH 2/7] [5.6] Copy over upstream Compat macros to erc-compat * lisp/erc/erc-backend: (erc--get-isupport-entry): Replace call to `erc-compat--with-memoization' with the built-in `with-memoization'. * lisp/erc/erc-compat.el: (erc-compat-function, erc-compat-call): Add new macros from Compat 29.1.2.0. (erc-compat--with-memoization): Remove because it's now provided by Compat. (Bug#60954.) --- lisp/erc/erc-backend.el | 2 +- lisp/erc/erc-compat.el | 52 ++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 567443f5329..8c90e8eebb9 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1876,7 +1876,7 @@ erc--get-isupport-entry primitive value." (if-let* ((table (or erc--isupport-params (erc-with-server-buffer erc--isupport-params))) - (value (erc-compat--with-memoization (gethash key table) + (value (with-memoization (gethash key table) (when-let ((v (assoc (symbol-name key) erc-server-parameters))) (if (cdr v) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 5601ede27a5..605ee701850 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -34,6 +34,49 @@ (require 'compat nil 'noerror) (eval-when-compile (require 'cl-lib) (require 'url-parse)) +;; Except for the "erc-" namespacing, these two definitions should be +;; continuously updated to match the latest upstream ones verbatim. +;; Although they're pretty simple, it's likely not worth checking for +;; and possibly deferring to the non-prefixed versions. +;; +;; BEGIN Compat macros + +;;;; Macros for extended compatibility function calls + +(defmacro erc-compat-function (fun) + "Return compatibility function symbol for FUN. + +If the Emacs version provides a sufficiently recent version of +FUN, the symbol FUN is returned itself. Otherwise the macro +returns the symbol of a compatibility function which supports the +behavior and calling convention of the current stable Emacs +version. For example Compat 29.1 will provide compatibility +functions which implement the behavior and calling convention of +Emacs 29.1. + +See also `compat-call' to directly call compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `#',(if (fboundp compat) compat fun))) + +(defmacro erc-compat-call (fun &rest args) + "Call compatibility function or macro FUN with ARGS. + +A good example function is `plist-get' which was extended with an +additional predicate argument in Emacs 29.1. The compatibility +function, which supports this additional argument, can be +obtained via (compat-function plist-get) and called +via (compat-call plist-get plist prop predicate). It is not +possible to directly call (plist-get plist prop predicate) on +Emacs older than 29.1, since the original `plist-get' function +does not yet support the predicate argument. Note that the +Compat library never overrides existing functions. + +See also `compat-function' to lookup compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `(,(if (fboundp compat) compat fun) ,@args))) + +;; END Compat macros + ;;;###autoload(autoload 'erc-define-minor-mode "erc-compat") (define-obsolete-function-alias 'erc-define-minor-mode #'define-minor-mode "28.1") @@ -368,15 +411,6 @@ erc-compat--29-sasl-scram--client-final-message ;;;; Misc 29.1 -(defmacro erc-compat--with-memoization (table &rest forms) - (declare (indent defun)) - (cond - ((fboundp 'with-memoization) - `(with-memoization ,table ,@forms)) ; 29.1 - ((fboundp 'cl--generic-with-memoization) - `(cl--generic-with-memoization ,table ,@forms)) - (t `(progn ,@forms)))) - (defvar url-irc-function) (defun erc-compat--29-browse-url-irc (string &rest _) -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Leverage-loaddefs-for-migrating-ERC-modules.patch >From 27194567216a079b2150b601d0aadbb9913466d4 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Sat, 4 Feb 2023 06:24:59 -0800 Subject: [PATCH 3/7] [5.6] Leverage loaddefs for migrating ERC modules * lisp/erc/erc-common.el (erc--features-to-modules, erc--modules-to-features, erc--module-name-migrations): Remove unused internal functions. (erc--normalize-module-symbol): Make aware of new symbol-prop-based migration scheme. * lisp/erc/erc-page.el: Add autoload cookie for module migration. * lisp/erc/erc-services.el: Add autoload cookie for module migration. * lisp/erc/erc-sound.el: Add autoload cookie for module migration. * lisp/erc/erc-stamp.el: Add autoload cookie for module migration. * lisp/erc/erc.el (erc-modules): Remove non-existent module `hecomplete' from lineup. Swap a couple more to maintain sorted order. Change `:initialize' function to tag all symbols for built-in modules with an `erc--module' property. Likewise, in the `:set' function, ensure third-party modules appear after the sorted and normalized built-ins, but in user-defined order. Do this to prevent all modules, built-ins included, from ending up as populated form fields for the "other" checkbox in the Customize interface. (erc--find-mode): Add helper function for `erc--update-modules'. (erc--update-modules): Always resolve module names and only conditionally attempt to require corresponding features. * test/lisp/erc/erc-tests.el (erc-tests--module): Add manifest for asserting built-in modules and features. This is easier to verify visually than looking at the custom-type set for `erc-modules'. (erc-modules--internal-property): Add test. (erc--normalize-module-symbol): Make more comprehensive. (erc--find-mode): New test. (Bug#60954.) --- lisp/erc/erc-common.el | 39 ++---------- lisp/erc/erc-page.el | 1 + lisp/erc/erc-pcomplete.el | 2 + lisp/erc/erc-services.el | 1 + lisp/erc/erc-sound.el | 1 + lisp/erc/erc-stamp.el | 4 ++ lisp/erc/erc.el | 59 +++++++++++++----- test/lisp/erc/erc-tests.el | 122 ++++++++++++++++++++++++++++++++----- 8 files changed, 164 insertions(+), 65 deletions(-) diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 0279b0a0bc4..f01db9d8bbc 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -85,40 +85,13 @@ erc--target (contents "" :type string) (tags '() :type list)) -;; TODO move goodies modules here after 29 is released. -(defconst erc--features-to-modules - '((erc-pcomplete completion pcomplete) - (erc-capab capab-identify) - (erc-join autojoin) - (erc-page page ctcp-page) - (erc-sound sound ctcp-sound) - (erc-stamp stamp timestamp) - (erc-services services nickserv)) - "Migration alist mapping a library feature to module names. -Keys need not be unique: a library may define more than one -module. Sometimes a module's downcased alias will be its -canonical name.") - -(defconst erc--modules-to-features - (let (pairs) - (pcase-dolist (`(,feature . ,names) erc--features-to-modules) - (dolist (name names) - (push (cons name feature) pairs))) - (nreverse pairs)) - "Migration alist mapping a module's name to its home library feature.") - -(defconst erc--module-name-migrations - (let (pairs) - (pcase-dolist (`(,_ ,canonical . ,rest) erc--features-to-modules) - (dolist (obsolete rest) - (push (cons obsolete canonical) pairs))) - pairs) - "Association list of obsolete module names to canonical names.") - +;; After deprecating 28, we can use prefixed "erc-autoload" cookies. (defun erc--normalize-module-symbol (symbol) - "Return preferred SYMBOL for `erc-modules'." - (setq symbol (intern (downcase (symbol-name symbol)))) - (or (cdr (assq symbol erc--module-name-migrations)) symbol)) + "Return preferred SYMBOL for `erc--modules'." + (while-let ((canonical (get symbol 'erc--module)) + ((not (eq canonical symbol)))) + (setq symbol canonical)) + symbol) (defun erc--assemble-toggle (localp name ablsym mode val body) (let ((arg (make-symbol "arg"))) diff --git a/lisp/erc/erc-page.el b/lisp/erc/erc-page.el index 308b3784ca5..6cba59c6946 100644 --- a/lisp/erc/erc-page.el +++ b/lisp/erc/erc-page.el @@ -34,6 +34,7 @@ erc-page "React to CTCP PAGE messages." :group 'erc) +;;;###autoload(put 'ctcp-page 'erc--module 'page) ;;;###autoload(autoload 'erc-page-mode "erc-page") (define-erc-module page ctcp-page "Process CTCP PAGE requests from IRC." diff --git a/lisp/erc/erc-pcomplete.el b/lisp/erc/erc-pcomplete.el index 0bce856018c..7eb7431fb91 100644 --- a/lisp/erc/erc-pcomplete.el +++ b/lisp/erc/erc-pcomplete.el @@ -56,6 +56,8 @@ erc-pcomplete-order-nickname-completions "If t, order nickname completions with the most recent speakers first." :type 'boolean) +;;;###autoload(put 'Completion 'erc--module 'completion) +;;;###autoload(put 'pcomplete 'erc--module 'completion) ;;;###autoload(autoload 'erc-completion-mode "erc-pcomplete" nil t) (define-erc-module pcomplete Completion "In ERC Completion mode, the TAB key does completion whenever possible." diff --git a/lisp/erc/erc-services.el b/lisp/erc/erc-services.el index 2e6959cc3f0..5408ba405db 100644 --- a/lisp/erc/erc-services.el +++ b/lisp/erc/erc-services.el @@ -102,6 +102,7 @@ erc-nickserv-identify-mode (when (featurep 'erc-services) (erc-nickserv-identify-mode val)))) +;;;###autoload(put 'nickserv 'erc--module 'services) ;;;###autoload(autoload 'erc-services-mode "erc-services" nil t) (define-erc-module services nickserv "This mode automates communication with services." diff --git a/lisp/erc/erc-sound.el b/lisp/erc/erc-sound.el index 0abdbfd959c..9da9202f0cf 100644 --- a/lisp/erc/erc-sound.el +++ b/lisp/erc/erc-sound.el @@ -47,6 +47,7 @@ (require 'erc) +;;;###autoload(put 'ctcp-sound 'erc--module 'sound) ;;;###autoload(autoload 'erc-sound-mode "erc-sound") (define-erc-module sound ctcp-sound "In ERC sound mode, the client will respond to CTCP SOUND requests diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 0aa1590f801..d1a1507f700 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -147,6 +147,10 @@ erc-timestamp-face "ERC timestamp face." :group 'erc-faces) +;; New libraries should only autoload the minor mode for a module's +;; preferred name (rather than its alias). + +;;;###autoload(put 'timestamp 'erc--module 'stamp) ;;;###autoload(autoload 'erc-timestamp-mode "erc-stamp" nil t) (define-erc-module stamp timestamp "This mode timestamps messages in the channel buffers." diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index dd3697ac50b..a729ba14f6e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1830,12 +1830,22 @@ erc-modules :get (lambda (sym) ;; replace outdated names with their newer equivalents (erc-migrate-modules (symbol-value sym))) - :initialize #'custom-initialize-default + ;; Expect every built-in module to have the symbol property + ;; `erc--module' set to its canonical symbol (often itself). + :initialize (lambda (symbol exp) + ;; Use `cdddr' because (set :greedy t . ,entries) + (dolist (entry (cdddr (get 'erc-modules 'custom-type))) + (when-let* (((eq (car entry) 'const)) + (s (cadddr entry))) ; (const :tag "..." ,s) + (put s 'erc--module s))) + (custom-initialize-reset symbol exp) + (put symbol 'standard-value + (list (custom-quote (default-toplevel-value symbol))))) :set (lambda (sym val) ;; disable modules which have just been removed (when (and (boundp 'erc-modules) erc-modules val) (dolist (module erc-modules) - (unless (member module val) + (unless (memq module val) (let ((f (intern-soft (format "erc-%s-mode" module)))) (when (and (fboundp f) (boundp f)) (when (symbol-value f) @@ -1847,7 +1857,15 @@ erc-modules (when (symbol-value f) (funcall f 0)) (kill-local-variable f))))))))) - (set sym val) + (let (built-in third-party) + (dolist (v val) + (setq v (erc--normalize-module-symbol v)) + (if (get v 'erc--module) + (push v built-in) + (push v third-party))) + ;; Calling `set-default-toplevel-value' complicates testing + (set sym (append (sort built-in #'string-lessp) + (nreverse third-party)))) ;; this test is for the case where erc hasn't been loaded yet (when (fboundp 'erc-update-modules) (erc-update-modules))) @@ -1861,7 +1879,6 @@ erc-modules capab-identify) (const :tag "completion: Complete nicknames and commands (programmable)" completion) - (const :tag "hecomplete: Complete nicknames and commands (obsolete, use \"completion\")" hecomplete) (const :tag "dcc: Provide Direct Client-to-Client support" dcc) (const :tag "fill: Wrap long lines" fill) (const :tag "identd: Launch an identd server on port 8113" identd) @@ -1878,11 +1895,11 @@ erc-modules (const :tag "networks: Provide data about IRC networks" networks) (const :tag "noncommands: Don't display non-IRC commands after evaluation" noncommands) + (const :tag "notifications: Desktop alerts on PRIVMSG or mentions" + notifications) (const :tag "notify: Notify when the online status of certain users changes" notify) - (const :tag "notifications: Send notifications on PRIVMSG or nickname mentions" - notifications) (const :tag "page: Process CTCP PAGE requests from IRC" page) (const :tag "readonly: Make displayed lines read-only" readonly) (const :tag "replace: Replace text in messages" replace) @@ -1895,8 +1912,8 @@ erc-modules (const :tag "smiley: Convert smileys to pretty icons" smiley) (const :tag "sound: Play sounds when you receive CTCP SOUND requests" sound) - (const :tag "stamp: Add timestamps to messages" stamp) (const :tag "spelling: Check spelling" spelling) + (const :tag "stamp: Add timestamps to messages" stamp) (const :tag "track: Track channel activity in the mode-line" track) (const :tag "truncate: Truncate buffers to a certain size" truncate) (const :tag "unmorse: Translate morse code in messages" unmorse) @@ -1910,18 +1927,28 @@ erc-update-modules (erc--update-modules) nil) +(defun erc--find-mode (sym) + (setq sym (erc--normalize-module-symbol sym)) + (if-let* ((mode (intern-soft (concat "erc-" (symbol-name sym) "-mode"))) + ((or (boundp mode) + (and (fboundp mode) + (autoload-do-load (symbol-function mode) mode))))) + mode + (and (require (or (get sym 'erc--feature) + (intern (concat "erc-" (symbol-name sym)))) + nil 'noerror) + (setq mode (intern-soft (concat "erc-" (symbol-name sym) "-mode"))) + (fboundp mode) + mode))) + (defun erc--update-modules () (let (local-modes) (dolist (module erc-modules local-modes) - (require (or (alist-get module erc--modules-to-features) - (intern (concat "erc-" (symbol-name module)))) - nil 'noerror) ; some modules don't have a corresponding feature - (let ((mode (intern-soft (concat "erc-" (symbol-name module) "-mode")))) - (unless (and mode (fboundp mode)) - (error "`%s' is not a known ERC module" module)) - (if (custom-variable-p mode) - (funcall mode 1) - (push mode local-modes)))))) + (if-let ((mode (erc--find-mode module))) + (if (custom-variable-p mode) + (funcall mode 1) + (push mode local-modes)) + (error "`%s' is not a known ERC module" module))))) (defun erc-setup-buffer (buffer) "Consults `erc-join-buffer' to find out how to display `BUFFER'." diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index bbf3269161d..6ab6d9ee40f 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1224,6 +1224,77 @@ erc-handle-irc-url (kill-buffer "baznet") (kill-buffer "#chan"))) +(defconst erc-tests--modules + '( autoaway autojoin button capab-identify completion dcc fill identd + irccontrols keep-place list log match menu move-to-prompt netsplit + networks noncommands notifications notify page readonly + replace ring sasl scrolltobottom services smiley sound + spelling stamp track truncate unmorse xdcc)) + +;; Ensure the `:initialize' function for `erc-modules' successfully +;; tags all built-in modules with the internal property `erc--module'. + +(ert-deftest erc-modules--internal-property () + (let (ours) + (mapatoms (lambda (s) + (when-let ((v (get s 'erc--module)) + ((eq v s))) + (push s ours)))) + (should (equal (sort ours #'string-lessp) erc-tests--modules)))) + +(ert-deftest erc--normalize-module-symbol () + (dolist (mod erc-tests--modules) + (should (eq (erc--normalize-module-symbol mod) mod))) + (should (eq (erc--normalize-module-symbol 'pcomplete) 'completion)) + (should (eq (erc--normalize-module-symbol 'Completion) 'completion)) + (should (eq (erc--normalize-module-symbol 'ctcp-page) 'page)) + (should (eq (erc--normalize-module-symbol 'ctcp-sound) 'sound)) + (should (eq (erc--normalize-module-symbol 'timestamp) 'stamp)) + (should (eq (erc--normalize-module-symbol 'nickserv) 'services))) + +;; Worrying about which library a module comes from is mostly not +;; worth the hassle so long as ERC can find its minor mode. However, +;; bugs involving multiple modules living in the same library may slip +;; by because a module's loading problems may remain hidden on account +;; of its place in the default ordering. + +(ert-deftest erc--find-mode () + (let* ((package (if-let* ((found (getenv "ERC_PACKAGE_NAME")) + ((string-prefix-p "erc-" found))) + (intern found) + 'erc)) + (prog + `(,@(and (featurep 'compat) + `((progn + (require 'package) + (let ((package-load-list '((compat t) (,package t)))) + (package-initialize))))) + (require 'erc) + (let ((mods (mapcar #'cadddr + (cdddr (get 'erc-modules 'custom-type)))) + moded) + (setq mods + (sort mods (lambda (a b) (if (zerop (random 2)) a b)))) + (dolist (mod mods) + (unless (keywordp mod) + (push (if-let ((mode (erc--find-mode mod))) + mod + (list :missing mod)) + moded))) + (message "%S" + (sort moded + (lambda (a b) + (string< (symbol-name a) (symbol-name b)))))))) + (proc (start-process "erc--module-mode-autoloads" + (current-buffer) + (concat invocation-directory invocation-name) + "-batch" "-Q" + "-eval" (format "%S" (cons 'progn prog))))) + (set-process-query-on-exit-flag proc t) + (while (accept-process-output proc 10)) + (goto-char (point-min)) + (should (equal (read (current-buffer)) erc-tests--modules)))) + (ert-deftest erc-migrate-modules () (should (equal (erc-migrate-modules '(autojoin timestamp button)) '(autojoin stamp button))) @@ -1234,17 +1305,28 @@ erc--update-modules (let (calls erc-modules erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + ;; This `lbaz' module is unknown, so ERC looks for it via the + ;; symbol proerty `erc--feature' and, failing that, by + ;; `require'ing its "erc-" prefixed symbol. + (should-not (intern-soft "erc-lbaz-mode")) + (cl-letf (((symbol-function 'require) - (lambda (s &rest _) (push s calls))) + (lambda (s &rest _) + (when (eq s 'erc--lbaz-feature) + (fset (intern "erc-lbaz-mode") ; local module + (lambda (n) (push (cons 'lbaz n) calls)))) + (push s calls))) ;; Local modules - ((symbol-function 'erc-fake-bar-mode) - (lambda (n) (push (cons 'fake-bar n) calls))) + ((symbol-function 'erc-lbar-mode) + (lambda (n) (push (cons 'lbar n) calls))) + ((get 'lbaz 'erc--feature) 'erc--lbaz-feature) ;; Global modules - ((symbol-function 'erc-fake-foo-mode) - (lambda (n) (push (cons 'fake-foo n) calls))) - ((get 'erc-fake-foo-mode 'standard-value) 'ignore) + ((symbol-function 'erc-gfoo-mode) + (lambda (n) (push (cons 'gfoo n) calls))) + ((get 'erc-gfoo-mode 'standard-value) 'ignore) ((symbol-function 'erc-autojoin-mode) (lambda (n) (push (cons 'autojoin n) calls))) ((get 'erc-autojoin-mode 'standard-value) 'ignore) @@ -1255,20 +1337,28 @@ erc--update-modules (lambda (n) (push (cons 'completion n) calls))) ((get 'erc-completion-mode 'standard-value) 'ignore)) + (ert-info ("Unknown module") + (setq erc-modules '(lfoo)) + (should-error (erc--update-modules)) + (should (equal (pop calls) 'erc-lfoo)) + (should-not calls)) + (ert-info ("Local modules") - (setq erc-modules '(fake-foo fake-bar)) - (should (equal (erc--update-modules) '(erc-fake-bar-mode))) - ;; Bar the feature is still required but the mode is not activated - (should (equal (nreverse calls) - '(erc-fake-foo (fake-foo . 1) erc-fake-bar))) + (setq erc-modules '(gfoo lbar lbaz)) + ;; Don't expose the mode here + (should (equal (mapcar #'symbol-name (erc--update-modules)) + '("erc-lbaz-mode" "erc-lbar-mode"))) + ;; Lbaz required because unknown. + (should (equal (nreverse calls) '((gfoo . 1) erc--lbaz-feature))) + (fmakunbound (intern "erc-lbaz-mode")) + (unintern (intern "erc-lbaz-mode") obarray) (setq calls nil)) - (ert-info ("Module name overrides") - (setq erc-modules '(completion autojoin networks)) + (ert-info ("Global modules") ; `pcomplete' resolved to `completion' + (setq erc-modules '(pcomplete autojoin networks)) (should-not (erc--update-modules)) ; no locals - (should (equal (nreverse calls) '( erc-pcomplete (completion . 1) - erc-join (autojoin . 1) - erc-networks (networks . 1)))) + (should (equal (nreverse calls) + '((completion . 1) (autojoin . 1) (networks . 1)))) (setq calls nil))))) (ert-deftest erc--merge-local-modes () -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Don-t-require-erc-goodies-in-erc.el.patch >From 6560102c934cb72270c1133aaae8be759c0dbf4e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 19 Jan 2023 21:07:27 -0800 Subject: [PATCH 4/7] [5.6] Don't require erc-goodies in erc.el * lisp/erc/erc-common.el: (erc--features-to-modules): Add mappings from erc-goodies. * lisp/erc/erc-goodies.el: Remove forward declarations. Add minor-mode autoloads for `scrolltobottom', `readonly', `move-to-prompt', `keep-place', `noncommands', `irccontrols', `smiley', and `unmorse'. Add Local variables footer with `generated-autoload-file'. (erc-controls-strip): Autoload this function. (erc-irccontrols-mode, erc-irccontrols-enable, erc-irccontrols-disable): Add and remove key for `erc-toggle-interpret-controls' to `erc-mode-map'. (erc--irccontrols-on-major-mode): New helper to add or remove toggle command from local map. * lisp/erc/erc-ibuffer.el: Require `erc-goodies' for `erc-control-interpret'. The justification for the blanket `require' is this module isn't a member of `erc-modules' by default. * lisp/erc/erc-page.el: (erc-ctcp-query-PAGE): Require `erc-goodies' and put forward declaration for `erc-control-interpret' atop file. * lisp/erc/erc-speedbar.el: Require `erc-goodies' for the same reason in erc-ibuffer.el. * lisp/erc/erc.el: Remove `require' for `erc-goodies' at end of file and `pp' at top of file because `pp-to-string' is autoloaded on Emacs 27. Also remove `require's for `thingatpt', `time-date', and `iso8601'. They're all used sparingly and the latter two have only been around for one major release, so their removal likely won't cause much churn. And `thingatpt' already has a call-site `require', so the top-level one was redundant. Also wrap local loaddefs `require' call in `eval-and-compile'. (erc-update-mode-line-buffer): Only strip control chars when `erc-irccontrols-mode' is active. This is arguably a minor breaking change perhaps deserving of a NEWS entry. (Bug#60954.) --- lisp/erc/erc-goodies.el | 28 ++++++++++++++-------------- lisp/erc/erc-ibuffer.el | 1 + lisp/erc/erc-page.el | 3 +++ lisp/erc/erc-speedbar.el | 1 + lisp/erc/erc.el | 19 +++++++++---------- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index 05a21019042..7ca155ef9d0 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -29,23 +29,10 @@ ;;; Code: -;;; Imenu support - (eval-when-compile (require 'cl-lib)) -(require 'erc-common) - (defvar erc-controls-highlight-regexp) (defvar erc-controls-remove-regexp) -(defvar erc-input-marker) -(defvar erc-insert-marker) -(defvar erc-server-process) -(defvar erc-modules) -(defvar erc-log-p) - -(declare-function erc-buffer-list "erc" (&optional predicate proc)) -(declare-function erc-error "erc" (&rest args)) -(declare-function erc-extract-command-from-line "erc" (line)) -(declare-function erc-beg-of-input-line "erc" nil) +(require 'erc) (defun erc-imenu-setup () "Setup Imenu support in an ERC buffer." @@ -65,6 +52,7 @@ erc-input-line-position :group 'erc-display :type '(choice integer (const nil))) +;;;###autoload(autoload 'erc-scrolltobottom-mode "erc-goodies" nil t) (define-erc-module scrolltobottom nil "This mode causes the prompt to stay at the end of the window." ((add-hook 'erc-mode-hook #'erc-add-scroll-to-bottom) @@ -116,6 +104,7 @@ erc-scroll-to-bottom (recenter (or erc-input-line-position -1))))))) ;;; Make read only +;;;###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) @@ -131,6 +120,7 @@ erc-make-read-only (put-text-property (point-min) (point-max) 'rear-nonsticky t)) ;;; Move to prompt when typing text +;;;###autoload(autoload 'erc-move-to-prompt-mode "erc-goodies" nil t) (define-erc-module move-to-prompt nil "This mode causes the point to be moved to the prompt when typing text." ((add-hook 'erc-mode-hook #'erc-move-to-prompt-setup) @@ -155,6 +145,7 @@ erc-move-to-prompt-setup (add-hook 'pre-command-hook #'erc-move-to-prompt nil t)) ;;; Keep place in unvisited channels +;;;###autoload(autoload 'erc-keep-place-mode "erc-goodies" nil t) (define-erc-module keep-place nil "Leave point above un-viewed text in other channels." ((add-hook 'erc-insert-pre-hook #'erc-keep-place)) @@ -193,6 +184,7 @@ erc-noncommands-list If a command's function symbol is in this list, the typed command does not appear in the ERC buffer after the user presses ENTER.") +;;;###autoload(autoload 'erc-noncommands-mode "erc-goodies" nil t) (define-erc-module noncommands nil "This mode distinguishes non-commands. Commands listed in `erc-insert-this' know how to display @@ -381,6 +373,7 @@ erc-get-fg-color-face (intern (concat "fg:erc-color-face" (number-to-string n)))) (t (erc-log (format " Wrong color: %s" n)) 'default)))) +;;;###autoload(autoload 'erc-irccontrols-mode "erc-goodies" nil t) (define-erc-module irccontrols nil "This mode enables the interpretation of IRC control chars." ((add-hook 'erc-insert-modify-hook #'erc-controls-highlight) @@ -440,6 +433,7 @@ erc-controls-interpret s)) (t s))))) +;;;###autoload (defun erc-controls-strip (str) "Return a copy of STR with all IRC control characters removed." (when str @@ -553,6 +547,7 @@ erc-toggle-interpret-controls (if erc-interpret-controls-p "ON" "OFF"))) ;; Smiley +;;;###autoload(autoload 'erc-smiley-mode "erc-goodies" nil t) (define-erc-module smiley nil "This mode translates text-smileys such as :-) into pictures. This requires the function `smiley-region', which is defined in @@ -569,6 +564,7 @@ erc-smiley (smiley-region (point-min) (point-max)))) ;; Unmorse +;;;###autoload(autoload 'erc-unmorse-mode "erc-goodies" nil t) (define-erc-module unmorse nil "This mode causes morse code in the current channel to be unmorsed." ((add-hook 'erc-insert-modify-hook #'erc-unmorse)) @@ -611,3 +607,7 @@ erc-occur (provide 'erc-goodies) ;;; erc-goodies.el ends here + +;; Local Variables: +;; generated-autoload-file: "erc-loaddefs.el" +;; End: diff --git a/lisp/erc/erc-ibuffer.el b/lisp/erc/erc-ibuffer.el index 6699afe36a0..612814ac6da 100644 --- a/lisp/erc/erc-ibuffer.el +++ b/lisp/erc/erc-ibuffer.el @@ -32,6 +32,7 @@ (require 'ibuffer) (require 'ibuf-ext) (require 'erc) +(require 'erc-goodies) ; `erc-controls-interpret' (defgroup erc-ibuffer nil "The Ibuffer group for ERC." diff --git a/lisp/erc/erc-page.el b/lisp/erc/erc-page.el index 6cba59c6946..a94678e5132 100644 --- a/lisp/erc/erc-page.el +++ b/lisp/erc/erc-page.el @@ -30,6 +30,8 @@ (require 'erc) +(declare-function erc-controls-interpret "erc-goodies" (str)) + (defgroup erc-page nil "React to CTCP PAGE messages." :group 'erc) @@ -70,6 +72,7 @@ erc-ctcp-query-PAGE This will call `erc-page-function', if defined, or it will just print a message and `beep'. In addition to that, the page message is also inserted into the server buffer." + (require 'erc-goodies) ; for `erc-controls-interpret' (when (and erc-page-mode (string-match "PAGE\\(\\s-+.*\\)?$" msg)) (let* ((m (match-string 1 msg)) diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el index 5fca14e2365..a9443e0ea17 100644 --- a/lisp/erc/erc-speedbar.el +++ b/lisp/erc/erc-speedbar.el @@ -36,6 +36,7 @@ ;;; Code: (require 'erc) +(require 'erc-goodies) (require 'speedbar) (condition-case nil (require 'dframe) (error nil)) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index a729ba14f6e..38865b46a47 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -58,17 +58,13 @@ ;;; Code: -(load "erc-loaddefs" 'noerror 'nomessage) +(eval-and-compile (load "erc-loaddefs" 'noerror 'nomessage)) (require 'erc-networks) (require 'erc-backend) (require 'cl-lib) (require 'format-spec) -(require 'pp) -(require 'thingatpt) (require 'auth-source) -(require 'time-date) -(require 'iso8601) (eval-when-compile (require 'subr-x) (require 'url-parse)) (defconst erc-version "5.5" @@ -140,6 +136,10 @@ tabbar--local-hlf (defvar motif-version-string) (defvar gtk-version-string) +(declare-function decoded-time-period "time-date" (time)) +(declare-function iso8601-parse-duration "iso8601" (string)) +(declare-function word-at-point "thingatpt" (&optional no-properties)) + ;; tunable connection and authentication parameters (defcustom erc-server nil @@ -3085,6 +3085,8 @@ erc--read-time-period (string-to-number period)) ;; Parse as a time spec. (t + (require 'time-date) + (require 'iso8601) (let ((time (condition-case nil (iso8601-parse-duration (concat (cond @@ -6867,8 +6869,6 @@ erc-format-lag-time (cond (lag (format "lag:%.0f" lag)) (t "")))) -;; erc-goodies is required at end of this file. - ;; TODO when ERC drops Emacs 28, replace the expressions in the format ;; spec below with functions. (defun erc-update-mode-line-buffer (buffer) @@ -6879,7 +6879,8 @@ erc-update-mode-line-buffer (?m . ,(erc-format-channel-modes)) (?n . ,(or (erc-current-nick) "")) (?N . ,(erc-format-network)) - (?o . ,(or (erc-controls-strip erc-channel-topic) "")) + (?o . ,(or (erc-controls-strip erc-channel-topic) + "")) (?p . ,(erc-port-to-string erc-session-port)) (?s . ,(erc-format-target-and/or-server)) (?S . ,(erc-format-target-and/or-network)) @@ -7417,6 +7418,4 @@ erc-handle-irc-url (provide 'erc) -;; FIXME this is a temporary stopgap for Emacs 29. -(require 'erc-goodies) ;;; erc.el ends here -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Modify-erc-mode-map-in-module-definitions.patch >From d43379e7cdf59de22ee370f8a71cc5180840937a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 19 Jan 2023 21:07:27 -0800 Subject: [PATCH 5/7] [5.6] Modify erc-mode-map in module definitions * lisp/erc/erc-button.el (erc-button-mode, erc-button-enable, erc-button-disable): Replace call to `erc-button-setup' with one to `erc--modify-local-map'. This means `erc-button-setup' is now dead from a client perspective. * lisp/erc/erc-goodies.el (erc-irccontrols-enable, erc-irccontrols-disable, erc-irccontrols-mode): Bind `erc-toggle-interpret-controls' in module definition so it's only available when the module is active. * lisp/erc/erc-log.el (erc-log-mode, erc-log-enable, erc-log-disable): Move top-level `define-key' into module definition. * lisp/erc/erc-match.el (erc-match-mode, erc-match-enable, erc-match-disable): Move top-level `define-key' into module definition. * lisp/erc/erc.el (erc-mode-map): Remove C-c C-c binding for `erc-toggle-interpret-controls'. (erc--modify-local-map): Add helper for global modules to use when modifying `erc-mode-map'. * test/lisp/erc/erc-tests.el (erc--modify-local-map): Add test. Ensure modifications to `erc-mode-map' on loading `erc' and via `erc-mode-hook' still work. (Bug#60954.) --- lisp/erc/erc-button.el | 6 ++++-- lisp/erc/erc-goodies.el | 6 ++++-- lisp/erc/erc-log.el | 8 +++---- lisp/erc/erc-match.el | 8 +++---- lisp/erc/erc.el | 14 +++++++++++- test/lisp/erc/erc-tests.el | 44 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 13 deletions(-) diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index c28dddefa0e..1be56f5dc21 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -55,11 +55,11 @@ button ((add-hook 'erc-insert-modify-hook #'erc-button-add-buttons 'append) (add-hook 'erc-send-modify-hook #'erc-button-add-buttons 'append) (add-hook 'erc-complete-functions #'erc-button-next-function) - (add-hook 'erc-mode-hook #'erc-button-setup)) + (erc--modify-local-map t "" #'erc-button-previous)) ((remove-hook 'erc-insert-modify-hook #'erc-button-add-buttons) (remove-hook 'erc-send-modify-hook #'erc-button-add-buttons) (remove-hook 'erc-complete-functions #'erc-button-next-function) - (remove-hook 'erc-mode-hook #'erc-button-setup))) + (erc--modify-local-map nil "" #'erc-button-previous))) ;;; Variables @@ -233,6 +233,8 @@ erc-button-keys-added "Internal variable used to keep track of whether we've added the global-level ERC button keys yet.") +;; Maybe deprecate this function and `erc-button-keys-added' if they +;; continue to go unused for a another version (currently 5.6). (defun erc-button-setup () "Add ERC mode-level button movement keys. This is only done once." ;; Add keys. diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index 7ca155ef9d0..7ff5b1aecdf 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -377,9 +377,11 @@ erc-get-fg-color-face (define-erc-module irccontrols nil "This mode enables the interpretation of IRC control chars." ((add-hook 'erc-insert-modify-hook #'erc-controls-highlight) - (add-hook 'erc-send-modify-hook #'erc-controls-highlight)) + (add-hook 'erc-send-modify-hook #'erc-controls-highlight) + (erc--modify-local-map t "C-c C-c" #'erc-toggle-interpret-controls)) ((remove-hook 'erc-insert-modify-hook #'erc-controls-highlight) - (remove-hook 'erc-send-modify-hook #'erc-controls-highlight))) + (remove-hook 'erc-send-modify-hook #'erc-controls-highlight) + (erc--modify-local-map nil "C-c C-c" #'erc-toggle-interpret-controls))) (defun erc-controls-interpret (str) "Return a copy of STR after dealing with IRC control characters. diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index 2cb9031640d..a44437ddcf7 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el @@ -230,7 +230,8 @@ log ;; append, so that 'erc-initialize-log-marker runs first (add-hook 'erc-connect-pre-hook #'erc-log-setup-logging 'append) (dolist (buffer (erc-buffer-list)) - (erc-log-setup-logging buffer))) + (erc-log-setup-logging buffer)) + (erc--modify-local-map t "C-c C-l" #'erc-save-buffer-in-logs)) ;; disable ((remove-hook 'erc-insert-post-hook #'erc-save-buffer-in-logs) (remove-hook 'erc-send-post-hook #'erc-save-buffer-in-logs) @@ -241,9 +242,8 @@ log (remove-hook 'erc-part-hook #'erc-conditional-save-buffer) (remove-hook 'erc-connect-pre-hook #'erc-log-setup-logging) (dolist (buffer (erc-buffer-list)) - (erc-log-disable-logging buffer)))) - -(define-key erc-mode-map "\C-c\C-l" #'erc-save-buffer-in-logs) + (erc-log-disable-logging buffer)) + (erc--modify-local-map nil "C-c C-l" #'erc-save-buffer-in-logs))) ;;; functionality referenced from erc.el (defun erc-log-setup-logging (buffer) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 52ee5c855f3..7ec9078d493 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -52,8 +52,10 @@ 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) + (erc--modify-local-map t "C-c C-k" #'erc-go-to-log-matches-buffer)) + ((remove-hook 'erc-insert-modify-hook #'erc-match-message) + (erc--modify-local-map nil "C-c C-k" #'erc-go-to-log-matches-buffer))) ;; Remaining customizations @@ -647,8 +649,6 @@ 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) - (defun erc-hide-fools (match-type _nickuserhost _message) "Hide foolish comments. This function should be called from `erc-text-matched-hook'." diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 38865b46a47..4f985da9651 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1189,7 +1189,6 @@ erc-mode-map (define-key map [home] #'erc-bol) (define-key map "\C-c\C-a" #'erc-bol) (define-key map "\C-c\C-b" #'erc-switch-to-buffer) - (define-key map "\C-c\C-c" #'erc-toggle-interpret-controls) (define-key map "\C-c\C-d" #'erc-input-action) (define-key map "\C-c\C-e" #'erc-toggle-ctcp-autoresponse) (define-key map "\C-c\C-f" #'erc-toggle-flood-control) @@ -1213,6 +1212,19 @@ erc-mode-map map) "ERC keymap.") +(defun erc--modify-local-map (mode &rest bindings) + "Modify `erc-mode-map' on behalf of a global module. +Add or remove `key-valid-p' BINDINGS when toggling MODE." + (declare (indent 1)) + (while (pcase-let* ((`(,key ,def . ,rest) bindings) + (existing (keymap-lookup erc-mode-map key))) + (if mode + (when (or (not existing) (eq existing #'undefined)) + (keymap-set erc-mode-map key def)) + (when (eq existing def) + (keymap-unset erc-mode-map key t))) + (setq bindings rest)))) + ;; Faces ; Honestly, I have a horrible sense of color and the "defaults" below diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 6ab6d9ee40f..2c5c2541bca 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -492,6 +492,50 @@ erc--target-from-string (should (equal (erc--target-from-string "&Bitlbee") #s(erc--target-channel-local "&Bitlbee" &bitlbee))))) +(ert-deftest erc--modify-local-map () + (when (and (bound-and-true-p erc-irccontrols-mode) + (fboundp 'erc-irccontrols-mode)) + (erc-irccontrols-mode -1)) + (when (and (bound-and-true-p erc-match-mode) + (fboundp 'erc-match-mode)) + (erc-match-mode -1)) + (let* (calls + (inhibit-message noninteractive) + (cmd-foo (lambda () (interactive) (push 'foo calls))) + (cmd-bar (lambda () (interactive) (push 'bar calls)))) + + (ert-info ("Add non-existing") + (erc--modify-local-map t "C-c C-c" cmd-foo "C-c C-k" cmd-bar) + (with-temp-buffer + (set-window-buffer (selected-window) (current-buffer)) + (use-local-map erc-mode-map) + (execute-kbd-macro "\C-c\C-c") + (execute-kbd-macro "\C-c\C-k")) + (should (equal calls '(bar foo)))) + (setq calls nil) + + (ert-info ("Add existing") ; Attempt to swap definitions fails + (erc--modify-local-map t "C-c C-c" cmd-bar "C-c C-k" cmd-foo) + (with-temp-buffer + (set-window-buffer (selected-window) (current-buffer)) + (use-local-map erc-mode-map) + (execute-kbd-macro "\C-c\C-c") + (execute-kbd-macro "\C-c\C-k")) + (should (equal calls '(bar foo)))) + (setq calls nil) + + (ert-info ("Remove existing") + (ert-with-message-capture messages + (erc--modify-local-map nil "C-c C-c" cmd-foo "C-c C-k" cmd-bar) + (with-temp-buffer + (set-window-buffer (selected-window) (current-buffer)) + (use-local-map erc-mode-map) + (execute-kbd-macro "\C-c\C-c") + (execute-kbd-macro "\C-c\C-k")) + (should (string-search "C-c C-c is undefined" messages)) + (should (string-search "C-c C-k is undefined" messages)) + (should-not calls))))) + (ert-deftest erc-ring-previous-command-base-case () (ert-info ("Create ring when nonexistent and do nothing") (let (erc-input-ring -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-5.6-Add-missing-colors-to-erc-irccontrols-mode.patch >From fa2057c5ff35b42b59b83aa6a3df003ae87aac84 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Fri, 9 Jul 2021 20:03:51 -0700 Subject: [PATCH 6/7] [5.6] Add missing colors to erc-irccontrols-mode * lisp/erc/erc-goodies.el (erc-spoiler-face): Add new face. (erc--controls-additional-colors): Add remaining 16-99 colors. (erc-get-bg-color-face, erc-get-fg-color-face): Look up colors in table. (erc-controls-remove-regexp, erc-controls-highlight-regexp): Convert to `rx' forms and move above first use to eliminate intra-file forward declarations. (erc-controls-propertize): Support spoilers. * test/lisp/erc/erc-goodies-tests.el: New file. (Bug#60954.) --- lisp/erc/erc-goodies.el | 77 +++++++-- test/lisp/erc/erc-goodies-tests.el | 253 +++++++++++++++++++++++++++++ 2 files changed, 312 insertions(+), 18 deletions(-) create mode 100644 test/lisp/erc/erc-goodies-tests.el diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index 7ff5b1aecdf..5ddacb643fd 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -30,8 +30,6 @@ ;;; Code: (eval-when-compile (require 'cl-lib)) -(defvar erc-controls-highlight-regexp) -(defvar erc-controls-remove-regexp) (require 'erc) (defun erc-imenu-setup () @@ -243,6 +241,12 @@ erc-inverse-face "ERC inverse face." :group 'erc-faces) +(defface erc-spoiler-face + '((((background light)) :foreground "DimGray" :background "DimGray") + (((background dark)) :foreground "LightGray" :background "LightGray")) + "ERC spoiler face." + :group 'erc-faces) + (defface erc-underline-face '((t :underline t)) "ERC underline face." :group 'erc-faces) @@ -345,19 +349,38 @@ bg:erc-color-face15 "ERC face." :group 'erc-faces) +;; https://lists.gnu.org/archive/html/emacs-erc/2021-07/msg00005.html +(defvar erc--controls-additional-colors + ["#470000" "#472100" "#474700" "#324700" "#004700" "#00472c" + "#004747" "#002747" "#000047" "#2e0047" "#470047" "#47002a" + "#740000" "#743a00" "#747400" "#517400" "#007400" "#007449" + "#007474" "#004074" "#000074" "#4b0074" "#740074" "#740045" + "#b50000" "#b56300" "#b5b500" "#7db500" "#00b500" "#00b571" + "#00b5b5" "#0063b5" "#0000b5" "#7500b5" "#b500b5" "#b5006b" + "#ff0000" "#ff8c00" "#ffff00" "#b2ff00" "#00ff00" "#00ffa0" + "#00ffff" "#008cff" "#0000ff" "#a500ff" "#ff00ff" "#ff0098" + "#ff5959" "#ffb459" "#ffff71" "#cfff60" "#6fff6f" "#65ffc9" + "#6dffff" "#59b4ff" "#5959ff" "#c459ff" "#ff66ff" "#ff59bc" + "#ff9c9c" "#ffd39c" "#ffff9c" "#e2ff9c" "#9cff9c" "#9cffdb" + "#9cffff" "#9cd3ff" "#9c9cff" "#dc9cff" "#ff9cff" "#ff94d3" + "#000000" "#131313" "#282828" "#363636" "#4d4d4d" "#656565" + "#818181" "#9f9f9f" "#bcbcbc" "#e2e2e2" "#ffffff"]) + (defun erc-get-bg-color-face (n) "Fetches the right face for background color N (0-15)." (if (stringp n) (setq n (string-to-number n))) (if (not (numberp n)) (prog1 'default (erc-error "erc-get-bg-color-face: n is NaN: %S" n)) - (when (> n 16) + (when (> n 99) (erc-log (format " Wrong color: %s" n)) (setq n (mod n 16))) (cond ((and (>= n 0) (< n 16)) (intern (concat "bg:erc-color-face" (number-to-string n)))) - (t (erc-log (format " Wrong color: %s" n)) 'default)))) + ((< 15 n 99) + (list :background (aref erc--controls-additional-colors (- n 16)))) + (t (erc-log (format " Wrong color: %s" n)) '(default))))) (defun erc-get-fg-color-face (n) "Fetches the right face for foreground color N (0-15)." @@ -365,13 +388,15 @@ erc-get-fg-color-face (if (not (numberp n)) (prog1 'default (erc-error "erc-get-fg-color-face: n is NaN: %S" n)) - (when (> n 16) + (when (> n 99) (erc-log (format " Wrong color: %s" n)) (setq n (mod n 16))) (cond ((and (>= n 0) (< n 16)) (intern (concat "fg:erc-color-face" (number-to-string n)))) - (t (erc-log (format " Wrong color: %s" n)) 'default)))) + ((< 15 n 99) + (list :foreground (aref erc--controls-additional-colors (- n 16)))) + (t (erc-log (format " Wrong color: %s" n)) '(default))))) ;;;###autoload(autoload 'erc-irccontrols-mode "erc-goodies" nil t) (define-erc-module irccontrols nil @@ -383,6 +408,25 @@ irccontrols (remove-hook 'erc-send-modify-hook #'erc-controls-highlight) (erc--modify-local-map nil "C-c C-c" #'erc-toggle-interpret-controls))) +;; These patterns were moved here to circumvent compiler warnings but +;; otherwise translated verbatim from their original string-literal +;; definitions (minus a small bug fix to satisfy newly added tests). +(defvar erc-controls-remove-regexp + (rx (or ?\C-b ?\C-\] ?\C-_ ?\C-v ?\C-g ?\C-o + (: ?\C-c (? (any "0-9")) (? (any "0-9")) + (? (group ?, (any "0-9") (? (any "0-9"))))))) + "Regular expression matching control characters to remove.") + +;; Before the change to `rx', group 3 used to be a sibling of group 2. +;; This was assumed to be a bug. A few minor simplifications were +;; also performed. If incorrect, please admonish. +(defvar erc-controls-highlight-regexp + (rx (group (or ?\C-b ?\C-\] ?\C-v ?\C-_ ?\C-g ?\C-o + (: ?\C-c (? (group (** 1 2 (any "0-9"))) + (? (group ?, (group (** 1 2 (any "0-9"))))))))) + (group (* (not (any ?\C-b ?\C-c ?\C-g ?\n ?\C-o ?\C-v ?\C-\] ?\C-_))))) + "Regular expression matching control chars to highlight.") + (defun erc-controls-interpret (str) "Return a copy of STR after dealing with IRC control characters. See `erc-interpret-controls-p' and `erc-interpret-mirc-color' for options." @@ -444,16 +488,6 @@ erc-controls-strip (setq s (replace-match "" nil nil s))) s))) -(defvar erc-controls-remove-regexp - "\C-b\\|\C-]\\|\C-_\\|\C-v\\|\C-g\\|\C-o\\|\C-c[0-9]?[0-9]?\\(,[0-9][0-9]?\\)?" - "Regular expression which matches control characters to remove.") - -(defvar erc-controls-highlight-regexp - (concat "\\(\C-b\\|\C-]\\|\C-v\\|\C-_\\|\C-g\\|\C-o\\|" - "\C-c\\([0-9][0-9]?\\)?\\(,\\([0-9][0-9]?\\)\\)?\\)" - "\\([^\C-b\C-]\C-v\C-_\C-c\C-g\C-o\n]*\\)") - "Regular expression which matches control chars and the text to highlight.") - (defun erc-controls-highlight () "Highlight IRC control chars in the buffer. This is useful for `erc-insert-modify-hook' and `erc-send-modify-hook'. @@ -510,6 +544,13 @@ erc-controls-propertize "Prepend properties from IRC control characters between FROM and TO. If optional argument STR is provided, apply to STR, otherwise prepend properties to a region in the current buffer." + (if (and fg bg (equal fg bg)) + (progn + (setq fg 'erc-spoiler-face + bg nil) + (put-text-property from to 'mouse-face 'erc-inverse-face str)) + (when fg (setq fg (erc-get-fg-color-face fg))) + (when bg (setq bg (erc-get-bg-color-face bg)))) (font-lock-prepend-text-property from to @@ -527,10 +568,10 @@ erc-controls-propertize '(erc-underline-face) nil) (if fg - (list (erc-get-fg-color-face fg)) + (list fg) nil) (if bg - (list (erc-get-bg-color-face bg)) + (list bg) nil)) str) str) diff --git a/test/lisp/erc/erc-goodies-tests.el b/test/lisp/erc/erc-goodies-tests.el new file mode 100644 index 00000000000..46fcf82401b --- /dev/null +++ b/test/lisp/erc/erc-goodies-tests.el @@ -0,0 +1,253 @@ +;;; erc-goodies-tests.el --- Tests for erc-goodies -*- 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-x) +(require 'erc-goodies) +(declare-function erc--initialize-markers "erc" (old-point continued) t) + +(defun erc-goodies-tests--assert-face (beg end-str present &optional absent) + (setq beg (+ beg (point-min))) + (let ((end (+ beg (1- (length end-str))))) + (while (and beg (< beg end)) + (let* ((val (get-text-property beg 'font-lock-face)) + (ft (flatten-tree (ensure-list val)))) + (dolist (p (ensure-list present)) + (if (consp p) + (should (member p val)) + (should (memq p ft)))) + (dolist (a (ensure-list absent)) + (if (consp a) + (should-not (member a val)) + (should-not (memq a ft)))) + (setq beg (text-property-not-all beg (point-max) + 'font-lock-face val)))))) + +;; These are from the "Examples" section of +;; https://modern.ircdocs.horse/formatting.html + +(ert-deftest erc-controls-highlight--examples () + ;; FIXME remove after adding + (unless (fboundp 'erc--initialize-markers) + (ert-skip "Missing required function")) + (should (eq t erc-interpret-controls-p)) + (let ((erc-insert-modify-hook '(erc-controls-highlight)) + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (setq-local erc-interpret-mirc-color t) + (erc--initialize-markers (point) nil) + + (let* ((m "I love \C-c3IRC!\C-c It is the \C-c7best protocol ever!") + (msg (erc-format-privmessage "bob" m nil t))) + (erc-display-message nil nil (current-buffer) msg)) + (forward-line -1) + (should (search-forward " " nil t)) + (save-restriction + (narrow-to-region (point) (pos-eol)) + (erc-goodies-tests--assert-face + 0 "I love" 'erc-default-face 'fg:erc-color-face3) + (erc-goodies-tests--assert-face + 7 " IRC!" 'fg:erc-color-face3) + (erc-goodies-tests--assert-face + 11 " It is the " 'erc-default-face 'fg:erc-color-face7) + (erc-goodies-tests--assert-face + 22 "best protocol ever!" 'fg:erc-color-face7)) + + (let* ((m "This is a \C-]\C-c13,9cool \C-cmessage") + (msg (erc-format-privmessage "alice" m nil t))) + (erc-display-message nil nil (current-buffer) msg)) + (should (search-forward " " nil t)) + (save-restriction + (narrow-to-region (point) (pos-eol)) + (erc-goodies-tests--assert-face + 0 "this is a " 'erc-default-face 'erc-italic-face) + (erc-goodies-tests--assert-face + 10 "cool " '(erc-italic-face fg:erc-color-face13 bg:erc-color-face9)) + (erc-goodies-tests--assert-face + 15 "message" 'erc-italic-face + '(fg:erc-color-face13 bg:erc-color-face9))) + + (let* ((m "IRC \C-bis \C-c4,12so \C-cgreat\C-o!") + (msg (erc-format-privmessage "bob" m nil t))) + (erc-display-message nil nil (current-buffer) msg)) + (should (search-forward " " nil t)) + (save-restriction + (narrow-to-region (point) (pos-eol)) + (erc-goodies-tests--assert-face + 0 "IRC " 'erc-default-face 'erc-bold-face) + (erc-goodies-tests--assert-face + 4 "is " 'erc-bold-face '(fg:erc-color-face4 bg:erc-color-face12)) + (erc-goodies-tests--assert-face + 7 "so " '(erc-bold-face fg:erc-color-face4 bg:erc-color-face12)) + (erc-goodies-tests--assert-face + 10 "great" 'erc-bold-face '(fg:erc-color-face4 bg:erc-color-face12)) + (erc-goodies-tests--assert-face + 15 "!" 'erc-default-face 'erc-bold-face)) + + (let* ((m (concat "Rules: Don't spam 5\C-c13,8,6\C-c,7,8, " + "and especially not \C-b9\C-b\C-]!")) + (msg (erc-format-privmessage "alice" m nil t))) + (erc-display-message nil nil (current-buffer) msg)) + (should (search-forward " " nil t)) + (save-restriction + (narrow-to-region (point) (pos-eol)) + (erc-goodies-tests--assert-face + 0 "Rules: Don't spam 5" 'erc-default-face + '(fg:erc-color-face13 bg:erc-color-face8)) + (erc-goodies-tests--assert-face + 19 ",6" '(fg:erc-color-face13 bg:erc-color-face8)) + (erc-goodies-tests--assert-face + 21 ",7,8, and especially not " 'erc-default-face + '(fg:erc-color-face13 bg:erc-color-face8 erc-bold-face)) + (erc-goodies-tests--assert-face + 44 "9" 'erc-bold-face 'erc-italic-face) + (erc-goodies-tests--assert-face + 45 "!" 'erc-italic-face 'erc-bold-face)) + + (when noninteractive + (kill-buffer))))) + +;; Like the test above, this is most intuitive when run interactively. +;; Hovering over the redacted area should reveal its underlying text +;; in a high-contrast face. + +(ert-deftest erc-controls-highlight--inverse () + ;; FIXME remove after adding + (unless (fboundp 'erc--initialize-markers) + (ert-skip "Missing required function")) + (should (eq t erc-interpret-controls-p)) + (let ((erc-insert-modify-hook '(erc-controls-highlight)) + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (setq-local erc-interpret-mirc-color t) + (erc--initialize-markers (point) nil) + + (let* ((m "Spoiler: \C-c0,0Hello\C-c1,1World!") + (msg (erc-format-privmessage "bob" m nil t))) + (erc-display-message nil nil (current-buffer) msg)) + (forward-line -1) + (should (search-forward " " nil t)) + (save-restriction + (narrow-to-region (point) (pos-eol)) + (should (eq (get-text-property (+ 9 (point)) 'mouse-face) + 'erc-inverse-face)) + (should (eq (get-text-property (1- (pos-eol)) 'mouse-face) + 'erc-inverse-face)) + (erc-goodies-tests--assert-face + 0 "Spoiler: " 'erc-default-face + '(fg:erc-color-face0 bg:erc-color-face0)) + (erc-goodies-tests--assert-face + 9 "Hello" '(erc-spoiler-face) + '( fg:erc-color-face0 bg:erc-color-face0 + fg:erc-color-face1 bg:erc-color-face1)) + (erc-goodies-tests--assert-face + 18 " World" '(erc-spoiler-face) + '( fg:erc-color-face0 bg:erc-color-face0 + fg:erc-color-face1 bg:erc-color-face1 ))) + (when noninteractive + (kill-buffer))))) + +(defvar erc-goodies-tests--motd + ;; This is from ergo's MOTD + '((":- - this is \2bold text\17.") + (":- - this is \35italics text\17.") + (":- - this is \0034red\3 and \0032blue\3 text.") + (":- - this is \0034,12red text with a light blue background\3.") + (":- - this is a normal escaped dollarsign: $") + (":- ") + (":- " + "\0031,0 00 \0030,1 01 \0030,2 02 \0030,3 03 " + "\0031,4 04 \0030,5 05 \0030,6 06 \0031,7 07 ") + (":- " + "\0031,8 08 \0031,9 09 \0030,10 10 \0031,11 11 " + "\0030,12 12 \0031,13 13 \0031,14 14 \0031,15 15 ") + (":- ") + (":- " + "\0030,16 16 \0030,17 17 \0030,18 18 \0030,19 19 " + "\0030,20 20 \0030,21 21 \0030,22 22 \0030,23 23 " + "\0030,24 24 \0030,25 25 \0030,26 26 \0030,27 27 ") + (":- " + "\0030,28 28 \0030,29 29 \0030,30 30 \0030,31 31 " + "\0030,32 32 \0030,33 33 \0030,34 34 \0030,35 35 " + "\0030,36 36 \0030,37 37 \0030,38 38 \0030,39 39 ") + (":- " + "\0030,40 40 \0030,41 41 \0030,42 42 \0030,43 43 " + "\0030,44 44 \0030,45 45 \0030,46 46 \0030,47 47 " + "\0030,48 48 \0030,49 49 \0030,50 50 \0030,51 51 ") + (":- " + "\0030,52 52 \0030,53 53 \0031,54 54 \0031,55 55 " + "\0031,56 56 \0031,57 57 \0031,58 58 \0030,59 59 " + "\0030,60 60 \0030,61 61 \0030,62 62 \0030,63 63 ") + (":- " + "\0030,64 64 \0031,65 65 \0031,66 66 \0031,67 67 " + "\0031,68 68 \0031,69 69 \0031,70 70 \0031,71 71 " + "\0030,72 72 \0030,73 73 \0030,74 74 \0030,75 75 ") + (":- " + "\0031,76 76 \0031,77 77 \0031,78 78 \0031,79 79 " + "\0031,80 80 \0031,81 81 \0031,82 82 \0031,83 83 " + "\0031,84 84 \0031,85 85 \0031,86 86 \0031,87 87 ") + (":- " + "\0030,88 88 \0030,89 89 \0030,90 90 \0030,91 91 " + "\0030,92 92 \0030,93 93 \0030,94 94 \0030,95 95 " + "\0031,96 96 \0031,97 97 \0031,98 98 \399,99 99 ") + (":- "))) + +(ert-deftest erc-controls-highlight--motd () + ;; FIXME remove after adding + (unless (fboundp 'erc--initialize-markers) + (ert-skip "Missing required function")) + (should (eq t erc-interpret-controls-p)) + (let ((erc-insert-modify-hook '(erc-controls-highlight)) + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + (with-current-buffer (get-buffer-create "#chan") + (erc-mode) + (setq-local erc-interpret-mirc-color t) + (erc--initialize-markers (point) nil) + + (dolist (parts erc-goodies-tests--motd) + (erc-display-message nil 'notice (current-buffer) (string-join parts))) + + ;; Spot check + (goto-char (point-min)) + (should (search-forward " 16 " nil t)) + (save-restriction + (narrow-to-region (point) (pos-eol)) + (erc-goodies-tests--assert-face + 0 " 17 " '(fg:erc-color-face0 (:background "#472100"))) + (erc-goodies-tests--assert-face + 4 " 18 " '(fg:erc-color-face0 (:background "#474700")) + '((:background "#472100")))) + + (should (search-forward " 71 " nil t)) + (save-restriction + (narrow-to-region (point) (pos-eol)) + (erc-goodies-tests--assert-face + 0 " 72 " '(fg:erc-color-face0 (:background "#5959ff"))) + (erc-goodies-tests--assert-face + 4 " 73 " '(fg:erc-color-face0 (:background "#c459ff")) + '((:background "#5959ff")))) + + (goto-char (point-min)) + (when noninteractive + (kill-buffer))))) + +;;; erc-goodies-tests.el ends here -- 2.39.2 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-5.6-Convert-ERC-s-Imenu-integration-into-proper-modu.patch >From 636bec56194f964907c5cf5d37f2cb18e338e64e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 19 Jan 2023 21:07:27 -0800 Subject: [PATCH 7/7] [5.6] Convert ERC's Imenu integration into proper module TODO: add news item once a section for 5.6 has been added. * lisp/erc/erc-goodies.el: Don't add Imenu hooks to `erc-mode-hook' at top level. Remove autoload for `erc-create-imenu-index' because it already exists in the `erc-imenu' library. (erc-imenu-setup) Move to erc-imenu. * lisp/erc/erc-imenu.el (erc-unfill-notice): Allow modifications to read-only text. Thanks to Yusef Aslam for reporting this bug. (erc-imenu-setup): Move here from goodies. (erc-imenu-mode, erc-imenu-enable, erc-imenu-disable): Create new ERC module for Imenu. * lisp/erc/erc.el (erc-modules): Add `imenu' to default value and create menu item. Update package-version. * test/lisp/erc/erc-tests.el (erc-tests--modules): Add `imenu'. (Bug#60954.) --- lisp/erc/erc-goodies.el | 6 ------ lisp/erc/erc-imenu.el | 23 ++++++++++++++++++++++- lisp/erc/erc.el | 4 +++- test/lisp/erc/erc-tests.el | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index 5ddacb643fd..7ea6c42ec65 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -32,12 +32,6 @@ (eval-when-compile (require 'cl-lib)) (require 'erc) -(defun erc-imenu-setup () - "Setup Imenu support in an ERC buffer." - (setq-local imenu-create-index-function #'erc-create-imenu-index)) - -(add-hook 'erc-mode-hook #'erc-imenu-setup) -(autoload 'erc-create-imenu-index "erc-imenu" "Imenu index creation function") ;;; Automatically scroll to bottom (defcustom erc-input-line-position nil diff --git a/lisp/erc/erc-imenu.el b/lisp/erc/erc-imenu.el index 6223cd3d06f..526afd32249 100644 --- a/lisp/erc/erc-imenu.el +++ b/lisp/erc/erc-imenu.el @@ -52,7 +52,8 @@ erc-unfill-notice (forward-line 1) (looking-at " ")) (forward-line 1)) - (end-of-line) (point))))) + (end-of-line) (point)))) + (inhibit-read-only t)) (with-temp-buffer (insert str) (goto-char (point-min)) @@ -124,6 +125,26 @@ erc-create-imenu-index index-alist)) index-alist)) +(defvar-local erc-imenu--create-index-function nil + "Previous local value of `imenu-create-index-function', if any.") + +(defun erc-imenu-setup () + "Wire up support for Imenu in an ERC buffer." + (when (and (local-variable-p 'imenu-create-index-function) + imenu-create-index-function) + (setq erc-imenu--create-index-function imenu-create-index-function)) + (setq imenu-create-index-function #'erc-create-imenu-index)) + +;;;###autoload(autoload 'erc-imenu-mode "erc-imenu" nil t) +(define-erc-module imenu nil + "Simple Imenu integration for ERC." + ((add-hook 'erc-mode-hook #'erc-imenu-setup)) + ((remove-hook 'erc-mode-hook #'erc-imenu-setup) + (erc-with-all-buffers-of-server erc-server-process nil + (when erc-imenu--create-index-function + (setq imenu-create-index-function erc-imenu--create-index-function) + (kill-local-variable 'erc-imenu--create-index-function))))) + (provide 'erc-imenu) ;;; erc-imenu.el ends here diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 4f985da9651..e122f32d96a 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1834,7 +1834,7 @@ erc-migrate-modules (defcustom erc-modules '(netsplit fill button match track completion readonly networks ring autojoin noncommands irccontrols - move-to-prompt stamp menu list) + move-to-prompt stamp menu list imenu) "A list of modules which ERC should enable. If you set the value of this without using `customize' remember to call \(erc-update-modules) after you change it. When using `customize', modules @@ -1894,6 +1894,7 @@ erc-modules (const :tag "dcc: Provide Direct Client-to-Client support" dcc) (const :tag "fill: Wrap long lines" fill) (const :tag "identd: Launch an identd server on port 8113" identd) + (const :tag "imenu: A simple Imenu integration" imenu) (const :tag "irccontrols: Highlight or remove IRC control characters" irccontrols) (const :tag "keep-place: Leave point above un-viewed text" keep-place) @@ -1931,6 +1932,7 @@ erc-modules (const :tag "unmorse: Translate morse code in messages" unmorse) (const :tag "xdcc: Act as an XDCC file-server" xdcc) (repeat :tag "Others" :inline t symbol)) + :package-version '(ERC . "5.6") ; FIXME sync on release :group 'erc) (defun erc-update-modules () diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 2c5c2541bca..3e844f45f1a 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1270,7 +1270,7 @@ erc-handle-irc-url (defconst erc-tests--modules '( autoaway autojoin button capab-identify completion dcc fill identd - irccontrols keep-place list log match menu move-to-prompt netsplit + imenu irccontrols keep-place list log match menu move-to-prompt netsplit networks noncommands notifications notify page readonly replace ring sasl scrolltobottom services smiley sound spelling stamp track truncate unmorse xdcc)) -- 2.39.2 --=-=-=--