unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: "J.P." <jp@neverwas.me>
To: 60935@debbugs.gnu.org
Cc: emacs-erc@gnu.org
Subject: bug#60935: 30.0.50; ERC >5.5: Improve ERC's treatment of customization groups
Date: Tue, 14 Mar 2023 06:43:15 -0700	[thread overview]
Message-ID: <87jzzjih3g.fsf@neverwas.me> (raw)
In-Reply-To: <87v8l3aod4.fsf@neverwas.me> (J. P.'s message of "Wed, 18 Jan 2023 06:50:15 -0800")

[-- Attachment #1: Type: text/plain, Size: 192 bytes --]

v4. Use `custom-set-variables' instead of `customize-set-variable'.
Munge `standard-value' of deprecated `erc-foo-mode' variables when
called by `erc-update-modules' (but not interactively).


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0000-v3-v4.diff --]
[-- Type: text/x-patch, Size: 4065 bytes --]

From a6662c04e156b1dd37661991a045acaf3c5cb9b4 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Tue, 14 Mar 2023 06:25:32 -0700
Subject: [PATCH 0/3] *** NOT A PATCH ***

*** BLURB HERE ***

F. Jason Park (3):
  [5.6] Don't associate ERC modules with undefined groups
  [5.6] Warn when setting minor-mode vars for ERC modules
  [5.6] Fill doc strings for ERC modules.

 lisp/erc/erc-capab.el      |   1 +
 lisp/erc/erc-common.el     | 146 +++++++++++++++++++++++++++++++++----
 lisp/erc/erc.el            |   3 +-
 test/lisp/erc/erc-tests.el |  88 +++++++++++++++++-----
 4 files changed, 207 insertions(+), 31 deletions(-)

Interdiff:
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 4332ed00cfb..522803b91e2 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -162,11 +162,14 @@ erc--assemble-toggle
                                        erc-modules)))
                          `(,(if val v `(not ,v)))))
                (let ((erc--inside-mode-toggle-p t))
-                 (customize-set-variable
-                  'erc-modules (,(if val 'cons 'delq)
-                                ',(erc--normalize-module-symbol name)
-                                erc-modules))))
+                 (custom-set-variables
+                  `(erc-modules ',(,(if val 'cons 'delq)
+                                   ',(erc--normalize-module-symbol name)
+                                   erc-modules)))))
              (setq ,mode ,val)
+             ;; Avoid "changed" state from `erc-update-modules'
+             (unless (called-interactively-p 'any)
+               (put ',mode 'standard-value (list ,val)))
              ,@body)))))
 
 ;; This is a migration helper that determines a module's `:group'
@@ -203,9 +206,9 @@ erc--find-group
 (defun erc--custom-set-minor-mode (variable value)
   (let ((name (get variable 'erc-module))
         (erc--inside-mode-toggle-p t))
-    (customize-set-variable
-     'erc-modules
-     (if value (cl-pushnew name erc-modules) (delq name erc-modules)))
+    (custom-set-variables
+     `(erc-modules
+       ',(if value (cl-pushnew name erc-modules) (delq name erc-modules))))
     (custom-set-minor-mode variable value)))
 
 ;; This exists as a separate, top-level function to prevent the byte
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 62480c0604e..ef742c853d6 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1340,9 +1340,11 @@ define-erc-module--global
                         (unless (or erc--inside-mode-toggle-p
                                     (memq 'mname erc-modules))
                           (let ((erc--inside-mode-toggle-p t))
-                            (customize-set-variable
-                             'erc-modules (cons 'mname erc-modules))))
+                            (custom-set-variables
+                             `(erc-modules ',(cons 'mname erc-modules)))))
                         (setq erc-mname-mode t)
+                        (unless (called-interactively-p 'any)
+                          (put 'erc-mname-mode 'standard-value (list t)))
                         (ignore a) (ignore b))
 
                       (defun erc-mname-disable ()
@@ -1351,9 +1353,11 @@ define-erc-module--global
                         (unless (or erc--inside-mode-toggle-p
                                     (not (memq 'mname erc-modules)))
                           (let ((erc--inside-mode-toggle-p t))
-                            (customize-set-variable
-                             'erc-modules (delq 'mname erc-modules))))
+                            (custom-set-variables
+                             `(erc-modules ',(delq 'mname erc-modules)))))
                         (setq erc-mname-mode nil)
+                        (unless (called-interactively-p 'any)
+                          (put 'erc-mname-mode 'standard-value (list nil)))
                         (ignore c) (ignore d))
 
                       (defalias 'erc-malias-mode #'erc-mname-mode)
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-5.6-Don-t-associate-ERC-modules-with-undefined-group.patch --]
[-- Type: text/x-patch, Size: 7145 bytes --]

From 12dd0075b751a9dbdfae57a500425f177158bb73 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Sat, 14 Jan 2023 19:05:59 -0800
Subject: [PATCH 1/3] [5.6] Don't associate ERC modules with undefined groups

* lisp/erc/erc-capab.el Add property crutch to help ERC find module's
custom group.
* lisp/erc/erc-common.el (erc--find-group): Add new function, a helper
for finding an existing ERC custom group based on `define-erc-module'
params.  Prefer `group-documentation' as a sentinel over symbol
properties owned by Customize because they might not be present if the
group isn't yet associated with any custom variables.
(define-erc-module): Set `:group' keyword value more accurately,
falling back to `erc' group when no associated group has been defined.
* test/lisp/erc/erc-tests.el (erc--find-group, erc--find-group--real):
New tests.
(define-erc-module--global, define-erc-module--local): Expect the
:group keyword to be the unevaluated `erc--find-group'
form.  (Bug#60935.)
---
 lisp/erc/erc-capab.el      |  1 +
 lisp/erc/erc-common.el     | 38 +++++++++++++++++++++++++++++++++-----
 test/lisp/erc/erc-tests.el | 37 +++++++++++++++++++++++++++++++++++--
 3 files changed, 69 insertions(+), 7 deletions(-)

diff --git a/lisp/erc/erc-capab.el b/lisp/erc/erc-capab.el
index 650c5fa84ac..bb0921da7f0 100644
--- a/lisp/erc/erc-capab.el
+++ b/lisp/erc/erc-capab.el
@@ -89,6 +89,7 @@ erc-capab-identify-unidentified
 ;;; Define module:
 
 ;;;###autoload(autoload 'erc-capab-identify-mode "erc-capab" nil t)
+(put 'capab-identify 'erc-group 'erc-capab)
 (define-erc-module capab-identify nil
   "Handle dancer-ircd's CAPAB IDENTIFY-MSG and IDENTIFY-CTCP."
   ;; append so that `erc-server-parameters' is already set by `erc-server-005'
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 0279b0a0bc4..0eabd3a2fe9 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -145,6 +145,37 @@ erc--assemble-toggle
              (setq ,mode ,val)
              ,@body)))))
 
+;; This is a migration helper that determines a module's `:group'
+;; keyword argument from its name or alias.  A (global) module's minor
+;; mode variable appears under the group's Custom menu.  Like
+;; `erc--normalize-module-symbol', it must run when the module's
+;; definition (rather than that of `define-erc-module') is expanded.
+;; For corner cases in which this fails or the catch-all of `erc' is
+;; more inappropriate, (global) modules can declare a top-level
+;;
+;;   (put 'foo 'erc-group 'erc-bar)
+;;
+;; where `erc-bar' is the group and `foo' is the normalized module.
+;; Do this *before* the module's definition.  If `define-erc-module'
+;; ever accepts arbitrary keywords, passing an explicit `:group' will
+;; obviously be preferable.
+
+(defun erc--find-group (&rest symbols)
+  (catch 'found
+    (dolist (s symbols)
+      (let* ((downed (downcase (symbol-name s)))
+             (known (intern-soft (concat "erc-" downed))))
+        (when (and known
+                   (or (get known 'group-documentation)
+                       (rassq known custom-current-group-alist)))
+          (throw 'found known))
+        (when (setq known (intern-soft (concat "erc-" downed "-mode")))
+          (when-let ((found (custom-group-of-mode known)))
+            (throw 'found found))))
+      (when-let ((found (get (erc--normalize-module-symbol s) 'erc-group)))
+        (throw 'found found)))
+    'erc))
+
 (defmacro define-erc-module (name alias doc enable-body disable-body
                                   &optional local-p)
   "Define a new minor mode using ERC conventions.
@@ -179,7 +210,6 @@ define-erc-module
   (declare (doc-string 3) (indent defun))
   (let* ((sn (symbol-name name))
          (mode (intern (format "erc-%s-mode" (downcase sn))))
-         (group (intern (format "erc-%s" (downcase sn))))
          (enable (intern (format "erc-%s-enable" (downcase sn))))
          (disable (intern (format "erc-%s-disable" (downcase sn)))))
     `(progn
@@ -190,10 +220,8 @@ define-erc-module
 and disable it otherwise.  If called from Lisp, enable the mode
 if ARG is omitted or nil.
 %s" name name doc)
-         ;; FIXME: We don't know if this group exists, so this `:group' may
-         ;; actually just silence a valid warning about the fact that the var
-         ;; is not associated with any group.
-         :global ,(not local-p) :group (quote ,group)
+         :global ,(not local-p)
+         :group (erc--find-group ',name ,(and alias (list 'quote alias)))
          (if ,mode
              (,enable)
            (,disable)))
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index d6c63934163..13ef99be167 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1209,6 +1209,39 @@ erc-migrate-modules
   ;; Default unchanged
   (should (equal (erc-migrate-modules erc-modules) erc-modules)))
 
+(ert-deftest erc--find-group ()
+  ;; These two are loaded by default
+  (should (eq (erc--find-group 'keep-place nil) 'erc))
+  (should (eq (erc--find-group 'networks nil) 'erc-networks))
+  ;; These are fake
+  (cl-letf (((get 'erc-bar 'group-documentation) "")
+            ((get 'baz 'erc-group) 'erc-foo))
+    (should (eq (erc--find-group 'foo 'bar) 'erc-bar))
+    (should (eq (erc--find-group 'bar 'foo) 'erc-bar))
+    (should (eq (erc--find-group 'bar nil) 'erc-bar))
+    (should (eq (erc--find-group 'foo nil) 'erc))
+    (should (eq (erc--find-group 'fake 'baz) 'erc-foo))))
+
+(ert-deftest erc--find-group--real ()
+  :tags '(:unstable)
+  (require 'erc-services)
+  (require 'erc-stamp)
+  (require 'erc-sound)
+  (require 'erc-page)
+  (require 'erc-join)
+  (require 'erc-capab)
+  (require 'erc-pcomplete)
+  (should (eq (erc--find-group 'services 'nickserv) 'erc-services))
+  (should (eq (erc--find-group 'stamp 'timestamp) 'erc-stamp))
+  (should (eq (erc--find-group 'sound 'ctcp-sound) 'erc-sound))
+  (should (eq (erc--find-group 'page 'ctcp-page) 'erc-page))
+  (should (eq (erc--find-group 'autojoin) 'erc-autojoin))
+  (should (eq (erc--find-group 'pcomplete 'Completion) 'erc-pcomplete))
+  (should (eq (erc--find-group 'capab-identify) 'erc-capab))
+  ;; No group specified.
+  (should (eq (erc--find-group 'smiley nil) 'erc))
+  (should (eq (erc--find-group 'unmorse nil) 'erc)))
+
 (ert-deftest erc--update-modules ()
   (let (calls
         erc-modules
@@ -1290,7 +1323,7 @@ define-erc-module--global
 if ARG is omitted or nil.
 Some docstring"
                         :global t
-                        :group 'erc-mname
+                        :group (erc--find-group 'mname 'malias)
                         (if erc-mname-mode
                             (erc-mname-enable)
                           (erc-mname-disable)))
@@ -1336,7 +1369,7 @@ define-erc-module--local
 if ARG is omitted or nil.
 Some docstring"
                         :global nil
-                        :group 'erc-mname
+                        :group (erc--find-group 'mname nil)
                         (if erc-mname-mode
                             (erc-mname-enable)
                           (erc-mname-disable)))
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0002-5.6-Warn-when-setting-minor-mode-vars-for-ERC-module.patch --]
[-- Type: text/x-patch, Size: 11018 bytes --]

From 764dc63582a440495ab53a9986003d5d1a794bcf Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Sat, 14 Jan 2023 19:08:11 -0800
Subject: [PATCH 2/3] [5.6] Warn when setting minor-mode vars for ERC modules

(erc--inside-mode-toggle-p): Add global var to inhibit mode toggles
from being run by `erc-update-modules'.  It must be non-nil inside
custom-set functions for mode toggles created by `define-erc-module'.
(erc--assemble-toggle): Don't modify `erc-modules' when run from
custom-set function.
(erc--custom-set-minor-mode): Add new custom-set function for module
minor modes.  Update `erc-modules' before calling a minor-mode toggle
via `custom-set-minor-mode'.
(erc--tick-module-checkbox): Add helper to toggle the appropriate
checkbox in the `erc-modules' widget when a user interactively toggles
a minor-mode state variable.
(erc--prepare-custom-module-type): Create spec for minor-mode custom
`:type', deferring various aspects until module-definition time.
(define-erc-module): Add `:set' and `:type' keywords for global
modules.
* lisp/erc/erc.el (erc-modules): Inhibit `erc-update-modules' when run
from a minor-mode toggle's custom-set function.
* test/lisp/erc/erc-tests.el
(define-erc-module--global, define-erc-module--local): Update
`erc-modules' mutations with `erc--inside-mode-toggle-p' guard
conditions.  (Bug#60935.)
---
 lisp/erc/erc-common.el     | 88 +++++++++++++++++++++++++++++++++++---
 lisp/erc/erc.el            |  3 +-
 test/lisp/erc/erc-tests.el | 23 ++++++++--
 3 files changed, 105 insertions(+), 9 deletions(-)

diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 0eabd3a2fe9..cd0fc79e568 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -29,6 +29,7 @@
 (defvar erc--casemapping-rfc1459)
 (defvar erc--casemapping-rfc1459-strict)
 (defvar erc-channel-users)
+(defvar erc-modules)
 (defvar erc-dbuf)
 (defvar erc-log-p)
 (defvar erc-server-users)
@@ -37,6 +38,11 @@ erc-session-server
 (declare-function erc--get-isupport-entry "erc-backend" (key &optional single))
 (declare-function erc-get-buffer "erc" (target &optional proc))
 (declare-function erc-server-buffer "erc" nil)
+(declare-function widget-apply-action "wid-edit" (widget &optional event))
+(declare-function widget-at "wid-edit" (&optional pos))
+(declare-function widget-get-sibling "wid-edit" (widget))
+(declare-function widget-move "wid-edit" (arg &optional suppress-echo))
+(declare-function widget-type "wid-edit" (widget))
 
 (cl-defstruct erc-input
   string insertp sendp)
@@ -120,6 +126,16 @@ erc--normalize-module-symbol
   (setq symbol (intern (downcase (symbol-name symbol))))
   (or (cdr (assq symbol erc--module-name-migrations)) symbol))
 
+(defvar erc--inside-mode-toggle-p nil
+  "Non-nil when a module's mode toggle is updating module membership.
+This serves as a flag to inhibit the mutual recursion that would
+otherwise occur between an ERC-defined minor-mode function, such
+as `erc-services-mode', and the custom-set function for
+`erc-modules'.  For historical reasons, the latter calls
+`erc-update-modules', which, in turn, enables the minor-mode
+functions for all member modules.  Also non-nil when a mode's
+widget runs its set function.")
+
 (defun erc--assemble-toggle (localp name ablsym mode val body)
   (let ((arg (make-symbol "arg")))
     `(defun ,ablsym ,(if localp `(&optional ,arg) '())
@@ -137,12 +153,23 @@ erc--assemble-toggle
                        (,ablsym))
                    (setq ,mode ,val)
                    ,@body)))
-           `(,(if val
-                  `(cl-pushnew ',(erc--normalize-module-symbol name)
-                               erc-modules)
-                `(setq erc-modules (delq ',(erc--normalize-module-symbol name)
-                                         erc-modules)))
+           ;; No need for `default-value', etc. because a buffer-local
+           ;; `erc-modules' only influences the next session and
+           ;; doesn't survive the major-mode reset that soon follows.
+           `((unless
+                 (or erc--inside-mode-toggle-p
+                     ,@(let ((v `(memq ',(erc--normalize-module-symbol name)
+                                       erc-modules)))
+                         `(,(if val v `(not ,v)))))
+               (let ((erc--inside-mode-toggle-p t))
+                 (custom-set-variables
+                  `(erc-modules ',(,(if val 'cons 'delq)
+                                   ',(erc--normalize-module-symbol name)
+                                   erc-modules)))))
              (setq ,mode ,val)
+             ;; Avoid "changed" state from `erc-update-modules'
+             (unless (called-interactively-p 'any)
+               (put ',mode 'standard-value (list ,val)))
              ,@body)))))
 
 ;; This is a migration helper that determines a module's `:group'
@@ -176,6 +203,55 @@ erc--find-group
         (throw 'found found)))
     'erc))
 
+(defun erc--custom-set-minor-mode (variable value)
+  (let ((name (get variable 'erc-module))
+        (erc--inside-mode-toggle-p t))
+    (custom-set-variables
+     `(erc-modules
+       ',(if value (cl-pushnew name erc-modules) (delq name erc-modules))))
+    (custom-set-minor-mode variable value)))
+
+;; This exists as a separate, top-level function to prevent the byte
+;; compiler from warning about widget-related dependencies not being
+;; loaded at runtime.
+
+(defun erc--tick-module-checkbox (name &rest _) ; `name' must be normalized
+  (customize-variable-other-window 'erc-modules)
+  ;; Move to `erc-modules' section.
+  (while (not (eq (widget-type (widget-at)) 'checkbox))
+    (widget-move 1 t))
+  ;; This search for a checkbox can fail when `name' refers to a
+  ;; third-party module that modifies `erc-modules' (improperly) on
+  ;; load.
+  (let (w)
+    (while (and (eq (widget-type (widget-at)) 'checkbox)
+                (not (and (setq w (widget-get-sibling (widget-at)))
+                          (eq (widget-value w) name))))
+      (setq w nil)
+      (widget-move 1 t)) ; the `suppress-echo' arg exists in 27.2
+    (if w
+        (progn (widget-apply-action (widget-at))
+               (message "Hit %s to apply or %s to apply and save."
+                        (substitute-command-keys "\\[Custom-set]")
+                        (substitute-command-keys "\\[Custom-save]")))
+      (error "Failed to find %s in `erc-modules' checklist" name))))
+
+(defun erc--prepare-custom-module-type (name)
+  `(let* ((name (erc--normalize-module-symbol ',name))
+          (fmtd (format " `%s' " name)))
+     `(boolean
+       :button-face '(error custom-button)
+       :format "%{%t%}: %[Deprecated Toggle%] \n%d\n"
+       :doc ,(concat "Setting a module's minor-mode variable is "
+                     (propertize "ineffective" 'face 'error) ".\nPlease add"
+                     fmtd "directly to `erc-modules' instead.\nYou can do so"
+                     " now by clicking the scary button above.")
+       :help-echo ,(lambda (_)
+                     (let ((hasp (memq name erc-modules)))
+                       (concat (if hasp "Remove" "Add") fmtd
+                               (if hasp "from" "to") " `erc-modules'.")))
+       :action ,(apply-partially #'erc--tick-module-checkbox name))))
+
 (defmacro define-erc-module (name alias doc enable-body disable-body
                                   &optional local-p)
   "Define a new minor mode using ERC conventions.
@@ -222,6 +298,8 @@ define-erc-module
 %s" name name doc)
          :global ,(not local-p)
          :group (erc--find-group ',name ,(and alias (list 'quote alias)))
+         ,@(unless local-p '(:set #'erc--custom-set-minor-mode))
+         ,@(unless local-p `(:type ,(erc--prepare-custom-module-type name)))
          (if ,mode
              (,enable)
            (,disable)))
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 69bdb5d71b1..59ab1f1eab3 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1846,7 +1846,8 @@ erc-modules
          (set sym val)
          ;; this test is for the case where erc hasn't been loaded yet
          (when (fboundp 'erc-update-modules)
-           (erc-update-modules)))
+           (unless erc--inside-mode-toggle-p
+             (erc-update-modules))))
   :type
   '(set
     :greedy t
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 13ef99be167..a31c2c530a3 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1313,7 +1313,10 @@ define-erc-module--global
                           ((ignore a) (ignore b))
                           ((ignore c) (ignore d)))))
 
-    (should (equal (macroexpand global-module)
+    (should (equal (cl-letf (((symbol-function
+                               'erc--prepare-custom-module-type)
+                              #'symbol-name))
+                     (macroexpand global-module))
                    `(progn
 
                       (define-minor-mode erc-mname-mode
@@ -1324,6 +1327,8 @@ define-erc-module--global
 Some docstring"
                         :global t
                         :group (erc--find-group 'mname 'malias)
+                        :set #'erc--custom-set-minor-mode
+                        :type "mname"
                         (if erc-mname-mode
                             (erc-mname-enable)
                           (erc-mname-disable)))
@@ -1331,15 +1336,27 @@ define-erc-module--global
                       (defun erc-mname-enable ()
                         "Enable ERC mname mode."
                         (interactive)
-                        (cl-pushnew 'mname erc-modules)
+                        (unless (or erc--inside-mode-toggle-p
+                                    (memq 'mname erc-modules))
+                          (let ((erc--inside-mode-toggle-p t))
+                            (custom-set-variables
+                             `(erc-modules ',(cons 'mname erc-modules)))))
                         (setq erc-mname-mode t)
+                        (unless (called-interactively-p 'any)
+                          (put 'erc-mname-mode 'standard-value (list t)))
                         (ignore a) (ignore b))
 
                       (defun erc-mname-disable ()
                         "Disable ERC mname mode."
                         (interactive)
-                        (setq erc-modules (delq 'mname erc-modules))
+                        (unless (or erc--inside-mode-toggle-p
+                                    (not (memq 'mname erc-modules)))
+                          (let ((erc--inside-mode-toggle-p t))
+                            (custom-set-variables
+                             `(erc-modules ',(delq 'mname erc-modules)))))
                         (setq erc-mname-mode nil)
+                        (unless (called-interactively-p 'any)
+                          (put 'erc-mname-mode 'standard-value (list nil)))
                         (ignore c) (ignore d))
 
                       (defalias 'erc-malias-mode #'erc-mname-mode)
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0003-5.6-Fill-doc-strings-for-ERC-modules.patch --]
[-- Type: text/x-patch, Size: 5781 bytes --]

From a6662c04e156b1dd37661991a045acaf3c5cb9b4 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 16 Jan 2023 20:18:32 -0800
Subject: [PATCH 3/3] [5.6] Fill doc strings for ERC modules.

* lisp/erc/erc-common.el (erc--fill-module-docstring): Add helper to
fill doc strings.
(erc--assemble-toggle, define-erc-module): Use helper to fill doc
string.
* test/lisp/erc/erc-tests.el (define-minor-mode--global,
define-minor-mode--local): Adjust expected output for generated doc
strings.  (Bug#60935.)
---
 lisp/erc/erc-common.el     | 20 +++++++++++++++++---
 test/lisp/erc/erc-tests.el | 28 ++++++++++++++++------------
 2 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index cd0fc79e568..522803b91e2 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -139,7 +139,7 @@ erc--inside-mode-toggle-p
 (defun erc--assemble-toggle (localp name ablsym mode val body)
   (let ((arg (make-symbol "arg")))
     `(defun ,ablsym ,(if localp `(&optional ,arg) '())
-       ,(concat
+       ,(erc--fill-module-docstring
          (if val "Enable" "Disable")
          " ERC " (symbol-name name) " mode."
          (when localp
@@ -252,6 +252,20 @@ erc--prepare-custom-module-type
                                (if hasp "from" "to") " `erc-modules'.")))
        :action ,(apply-partially #'erc--tick-module-checkbox name))))
 
+(defun erc--fill-module-docstring (&rest strings)
+  (with-temp-buffer
+    (emacs-lisp-mode)
+    (insert "(defun foo ()\n"
+            (format "%S" (apply #'concat strings))
+            "\n(ignore))")
+    (goto-char (point-min))
+    (forward-line 2)
+    (let ((emacs-lisp-docstring-fill-column 65)
+          (sentence-end-double-space t))
+      (fill-paragraph))
+    (goto-char (point-min))
+    (nth 3 (read (current-buffer)))))
+
 (defmacro define-erc-module (name alias doc enable-body disable-body
                                   &optional local-p)
   "Define a new minor mode using ERC conventions.
@@ -291,11 +305,11 @@ define-erc-module
     `(progn
        (define-minor-mode
          ,mode
-         ,(format "Toggle ERC %S mode.
+         ,(erc--fill-module-docstring (format "Toggle ERC %s mode.
 With a prefix argument ARG, enable %s if ARG is positive,
 and disable it otherwise.  If called from Lisp, enable the mode
 if ARG is omitted or nil.
-%s" name name doc)
+\n%s" name name doc))
          :global ,(not local-p)
          :group (erc--find-group ',name ,(and alias (list 'quote alias)))
          ,@(unless local-p '(:set #'erc--custom-set-minor-mode))
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index a31c2c530a3..ef742c853d6 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1309,7 +1309,7 @@ erc--merge-local-modes
 
 (ert-deftest define-erc-module--global ()
   (let ((global-module '(define-erc-module mname malias
-                          "Some docstring"
+                          "Some docstring."
                           ((ignore a) (ignore b))
                           ((ignore c) (ignore d)))))
 
@@ -1321,10 +1321,11 @@ define-erc-module--global
 
                       (define-minor-mode erc-mname-mode
                         "Toggle ERC mname mode.
-With a prefix argument ARG, enable mname if ARG is positive,
-and disable it otherwise.  If called from Lisp, enable the mode
-if ARG is omitted or nil.
-Some docstring"
+With a prefix argument ARG, enable mname if ARG is positive, and
+disable it otherwise.  If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
+Some docstring."
                         :global t
                         :group (erc--find-group 'mname 'malias)
                         :set #'erc--custom-set-minor-mode
@@ -1369,7 +1370,7 @@ define-erc-module--global
 
 (ert-deftest define-erc-module--local ()
   (let* ((global-module '(define-erc-module mname nil ; no alias
-                           "Some docstring"
+                           "Some docstring."
                            ((ignore a) (ignore b))
                            ((ignore c) (ignore d))
                            'local))
@@ -1381,10 +1382,11 @@ define-erc-module--local
                    `(progn
                       (define-minor-mode erc-mname-mode
                         "Toggle ERC mname mode.
-With a prefix argument ARG, enable mname if ARG is positive,
-and disable it otherwise.  If called from Lisp, enable the mode
-if ARG is omitted or nil.
-Some docstring"
+With a prefix argument ARG, enable mname if ARG is positive, and
+disable it otherwise.  If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
+Some docstring."
                         :global nil
                         :group (erc--find-group 'mname nil)
                         (if erc-mname-mode
@@ -1393,7 +1395,8 @@ define-erc-module--local
 
                       (defun erc-mname-enable (&optional ,arg-en)
                         "Enable ERC mname mode.
-When called interactively, do so in all buffers for the current connection."
+When called interactively, do so in all buffers for the current
+connection."
                         (interactive "p")
                         (when (derived-mode-p 'erc-mode)
                           (if ,arg-en
@@ -1405,7 +1408,8 @@ define-erc-module--local
 
                       (defun erc-mname-disable (&optional ,arg-dis)
                         "Disable ERC mname mode.
-When called interactively, do so in all buffers for the current connection."
+When called interactively, do so in all buffers for the current
+connection."
                         (interactive "p")
                         (when (derived-mode-p 'erc-mode)
                           (if ,arg-dis
-- 
2.39.2


  parent reply	other threads:[~2023-03-14 13:43 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-18 14:50 bug#60935: 30.0.50; ERC >5.5: Improve ERC's treatment of customization groups J.P.
2023-02-07 15:23 ` J.P.
2023-02-19 15:03 ` J.P.
2023-03-14 13:43 ` J.P. [this message]
2023-03-15 14:05 ` J.P.
     [not found] ` <87edpqglf1.fsf@neverwas.me>
2023-04-14 14:03   ` J.P.
     [not found]   ` <87a5zay31h.fsf@neverwas.me>
2023-05-06  0:54     ` J.P.

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87jzzjih3g.fsf@neverwas.me \
    --to=jp@neverwas.me \
    --cc=60935@debbugs.gnu.org \
    --cc=emacs-erc@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).