]> git.eshelyaron.com Git - emacs.git/commitdiff
More clearly define local module behavior in ERC
authorF. Jason Park <jp@neverwas.me>
Tue, 4 Feb 2025 14:11:50 +0000 (06:11 -0800)
committerEshel Yaron <me@eshelyaron.com>
Sun, 9 Feb 2025 08:44:50 +0000 (09:44 +0100)
* doc/misc/erc.texi (Modules): Label all local modules as being such.
Move `querypoll' to the auxiliary section.  Rework entire "Local
Modules" portion.
* lisp/erc/erc-goodies.el (erc-keep-place-indicator-mode)
(erc-command-indicator-mode): Mention what buffer types they operate in.
* lisp/erc/erc-nicks.el (erc-nicks-mode): Mention the mode is enabled in
all buffers.
* lisp/erc/erc-notify.el (erc-querypoll-mode): Mention which buffers it
operates in.
* lisp/erc/erc-sasl.el (erc-sasl-mode): Disable completely in target
buffers so its mode variable is nil.
* lisp/erc/erc-services.el (erc-services-regain-mode): Disable in target
buffers.
* lisp/erc/erc.el (erc-open): When activating local modules, skip those
that have just been enabled by a fellow module.  Do this even though
their setup code is meant to be idempotent.
* test/lisp/erc/erc-scenarios-base-local-modules.el
(erc-scenarios-base-local-modules--toggle-helpers): Revise to assert
current behavior.  (Bug#57955)

(cherry picked from commit e9408918f4e7fe00eb4e25e1e5428fb26c4ad847)

doc/misc/erc.texi
lisp/erc/erc-goodies.el
lisp/erc/erc-nicks.el
lisp/erc/erc-notify.el
lisp/erc/erc-sasl.el
lisp/erc/erc-services.el
lisp/erc/erc.el
test/lisp/erc/erc-scenarios-base-local-modules.el

index 1518196a3482fb1980ea95ca5b683cb50d9493c2..c1df5a62796a36d99a4e4fac6f5e654824d3a06f 100644 (file)
@@ -452,7 +452,7 @@ Buttonize URLs, nicknames, and other text
 Mark unidentified users on freenode and other servers supporting CAPAB.
 
 @cindex modules, command-indicator
-@item command-indicator
+@item command-indicator (local)
 Echo command lines for ``slash commands'', like @kbd{/JOIN #erc} and
 @kbd{/HELP join}
 
@@ -494,7 +494,7 @@ Display a menu in ERC buffers
 Detect netsplits
 
 @cindex modules, nicks
-@item nicks
+@item nicks (local)
 Automatically colorize nicks
 
 @cindex modules, nickbar
@@ -519,10 +519,6 @@ or your nickname is mentioned
 @item page
 Process CTCP PAGE requests from IRC
 
-@cindex modules, querypoll
-@item querypoll
-Update query participant data by continually polling the server
-
 @cindex modules, readonly
 @item readonly
 Make displayed lines read-only
@@ -536,7 +532,7 @@ Replace text in messages
 Enable an input history
 
 @cindex modules, sasl
-@item sasl
+@item sasl (local)
 Enable SASL authentication
 
 @cindex modules, scrolltobottom
@@ -583,22 +579,26 @@ Translate morse code in messages
 
 For various reasons, the following modules aren't currently listed in
 the Custom interface for @code{erc-modules}, but feel free to add them
-explicitly.  They may be managed by another module or considered more
-useful when toggled interactively or just deemed experimental.
+explicitly.  They may be managed by another module or just deemed too
+niche or experimental.
 
 @table @code
 
 @cindex modules, fill-wrap
-@item fill-wrap
+@item fill-wrap (local)
 Wrap long lines using @code{visual-line-mode}
 
 @cindex modules, keep-place-indicator
-@item keep-place-indicator
+@item keep-place-indicator (local)
 Remember your place in buffers with a visible reminder; activated
 interactively or via something like @code{erc-join-hook}
 
+@cindex modules, querypoll
+@item querypoll (local)
+Update query participant data by continually polling the server
+
 @cindex modules, services-regain
-@item services-regain
+@item services-regain (local)
 Automatically ask NickServ to reclaim your nick when reconnecting;
 experimental as of ERC 5.6
 
@@ -618,51 +618,84 @@ always loads anyway.
 @subheading Local Modules
 @cindex local modules
 
-All modules operate as minor modes under the hood, and some newer ones
-may be defined as buffer-local.  These so-called ``local modules'' are
-a work in progress and their behavior and interface are subject to
-change.  As of ERC 5.5, the only practical differences are as follows:
+@c Earlier language in code comments, commit messages, and tracker
+@c discussions used to describe a local module as being "active" in a
+@c buffer if it had a local binding but "disabled" if that binding's
+@c value was nil.  For better or worse, ERC has since abandoned that
+@c distinction and now considers "active" to be synonymous with
+@c "enabled".
+
+All modules operate as minor modes under the hood, and newer ones are
+mostly defined as buffer-local.  These so-called @dfn{local modules} are
+a work in progress, and their behavior and interface are subject to
+change.  As of ERC 5.6, the only practical differences are as follows:
 
 @enumerate
 @item
-``Control variables,'' like @code{erc-sasl-mode}, retain their values
-across IRC sessions and override @code{erc-module} membership when
-influencing module activation.
+@dfn{Mode variables}, a.k.a. @dfn{control variables}, like
+@code{erc-sasl-mode}, retain their values across IRC sessions.
 @item
 Removing a local module from @code{erc-modules} via Customize not only
-disables its mode but also kills its control variable in all ERC
-buffers.
+disables its mode but also kills its mode variable in all ERC buffers.
 @item
-``Mode toggles,'' like @code{erc-sasl-mode} and the complementary
-@code{erc-sasl-enable}/@code{erc-sasl-disable} pairing, behave
-differently than their global counterparts.
+@dfn{Mode commands}, like @code{erc-sasl-mode} and its one-way variants
+@code{erc-sasl-enable} and @code{erc-sasl-disable}, behave differently
+than their global counterparts.
 @end enumerate
 
-In target buffers, a local module's activation state survives
-``reassociation'' by default, but modules themselves always have the
-final say.  For example, a module may reset all instances of itself in
-its network context upon reconnecting.  Moreover, the value of a mode
-variable may be meaningless in buffers that its module has no interest
-in.  For example, the value of @code{erc-sasl-mode} doesn't matter in
-target buffers and may even remain non-@code{nil} after SASL has been
-disabled for the current connection (and vice versa).
-
-When it comes to server buffers, a module's activation state only
-persists for sessions revived via the automatic reconnection mechanism
-or a manual @samp{/reconnect} issued at the prompt.  In other words,
-this doesn't apply to sessions revived by an entry-point command, such
-as @code{erc-tls}, because such commands always ensure a clean slate
-by looking only to @code{erc-modules}.  Although a session revived in
-this manner may indeed harvest other information from a previous
-server buffer, it simply doesn't care which modules might have been
-active during that connection.
-
-Lastly, a local mode's toggle command, like @code{erc-sasl-mode}, only
-affects the current buffer, but its ``non-mode'' cousins, like
+To detect whether a module is local, examine its mode variable.  For
+example, if you run @kbd{C-h v erc-sasl-mode @key{RET}}, you'll notice
+it says ``Automatically becomes buffer-local when set''.  You can do the
+same in Lisp code with @code{(local-variable-if-set-p 'erc-sasl-mode)}.
+
+In an ERC buffer, a local module is either enabled or disabled if its
+mode variable has a local binding.  This @dfn{activation state} may
+contradict a module's presence in @code{erc-modules}, namely, in buffers
+where it isn't applicable or has otherwise been disabled.  In fact, a
+local module's membership in @code{erc-modules} does nothing more than
+guarantee
+
+@enumerate
+@item
+its setup code runs in @emph{new} buffers
+@item
+its mode variable has a local binding in all affected buffers
+@end enumerate
+
+In keeping with this, all built-in local modules disable themselves in
+nonapplicable buffers rather than remain no-ops.  Some also take strides
+to enable themselves elsewhere when needed or at least emit a helpful
+error.  For example, the @samp{nicks} module does both in server
+buffers, where it shares resources among the target buffers it primarily
+services.  ERC expects third-party local modules to mimic this pattern
+and to document what buffer types they operate in: server, query, or
+channel.  (In the case of @samp{nicks}, it would be all three: it's
+@dfn{session-local}.)
+
+In ERC, you can think of an IRC session as a group of buffers sharing
+the same connection to a server.  After a connection ends, this
+association endures so that ERC can revive the session when
+reconnecting.  As it does with connection parameters, ERC therefore
+persists a local module's activation state through reconnections,
+reenabling modules that were previously active while ensuring others are
+disabled.  A couple related things to note here are
+
+@enumerate
+@item
+each module must manage its own application data and restore or reset
+its environment accordingly
+@item
+session persistence is less predictable if a user changes the makeup of
+@code{erc-modules} between sessions
+@end enumerate
+
+When it comes to a local module's various activation commands, the
+primary mode command, like @code{erc-sasl-mode}, for example, only
+affects the current buffer, but its unidirectional cousins, like
 @code{erc-sasl-enable} and @code{erc-sasl-disable}, operate on all
-buffers belonging to their connection (when called interactively).
-And unlike global toggles, none of these ever mutates
-@code{erc-modules}.
+buffers belonging to their connection (when called interactively).  And
+unlike global toggles, none of these ever mutates @code{erc-modules}.
+
 
 @c FIXME add section to Advanced chapter for creating modules, and
 @c move this there.
index 1dd2f2d881f38fc39d8fdebd792f62ef9dbab4a5..1cf1d196786d2f7bef008f08d0058375e43ca48d 100644 (file)
@@ -370,7 +370,9 @@ than the indicator's position."
   "Buffer-local `keep-place' with fringe arrow and/or highlighted face.
 Play nice with global module `keep-place' but don't depend on it.
 Expect that users may want different combinations of `keep-place'
-and `keep-place-indicator' in different buffers."
+and `keep-place-indicator' in different buffers.
+
+This module is local to individual buffers."
   ((cond (erc-keep-place-mode)
          ((memq 'keep-place erc-modules)
           (erc-keep-place-mode +1))
@@ -587,7 +589,9 @@ message's speaker."
 Skip those appearing in `erc-noncommands-list'.
 
 Users can run \\[erc-command-indicator-toggle-hidden] to hide and
-reveal echoed command lines after they've been inserted."
+reveal echoed command lines after they've been inserted.
+
+This module is local to individual buffers."
   ((add-hook 'erc--input-review-functions
              #'erc--command-indicator-permit-insertion 80 t)
    (erc-command-indicator-toggle-hidden -1))
index 7dbf94a45be909802152b16439eba81f154789fd..a25d39610afcf9716b611d1f20fa515abd0b5ff2 100644 (file)
@@ -541,7 +541,9 @@ Abandon search after examining LIMIT faces."
   nick-object)
 
 (define-erc-module nicks nil
-  "Uniquely colorize nicknames in target buffers."
+  "Uniquely colorize nicknames in target buffers.
+
+This module is local per connection."
   ((if erc--target
        (progn
          (erc-with-server-buffer
index c74c5635a12327d66d31fee512302525e119b640..af3fc6f46f395182563e81aacfdfa664e1502a5f 100644 (file)
@@ -299,7 +299,8 @@ like `nickbar', to provide UI feedback when changes occur.
 Once ERC implements the `monitor' extension, this module will serve as
 an optional fallback for keeping query-participant rolls up to date on
 servers that lack support or are stingy with their allotments.  Until
-such time, this module should be considered experimental.
+such time, this module should be considered experimental and only really
+useful for bots and other non-interactive Lisp programs.
 
 This is a local ERC module, so selectively polling only a subset of
 query targets is possible but cumbersome.  To do so, ensure
@@ -307,7 +308,8 @@ query targets is possible but cumbersome.  To do so, ensure
 as appropriate in desired query buffers.  To stop polling for the
 current connection, toggle off the command \\[erc-querypoll-mode] from a
 server buffer, or run \\`M-x C-u erc-querypoll-disable RET' from a
-target buffer."
+target buffer.  Note that this module's minor mode must remain active in
+at least the server buffer."
   ((if erc--target
        (if (erc-query-buffer-p)
            (progn ; accommodate those who eschew `erc-modules'
index 87ee7bb138dcd0d8fa2fb2219fc8a4128940cad1..f311255dfbba062487268f2281d739898d133136 100644 (file)
 ;;
 ;; - Implement a proxy mechanism that chooses the strongest available
 ;;   mechanism for you.  Requires CAP 3.2 (see bug#49860).
-;;
-;; - Integrate with whatever solution ERC eventually settles on to
-;;   handle user options for different network contexts.  At the
-;;   moment, this does its own thing for stashing and restoring
-;;   session options, but ERC should make abstractions available for
-;;   all local modules to use, possibly based on connection-local
-;;   variables.
 
 ;;; Code:
 (require 'erc)
@@ -315,9 +308,10 @@ If necessary, pass PROMPT to `read-passwd'."
 
 (define-erc-module sasl nil
   "Non-IRCv3 SASL support for ERC.
-This doesn't solicit or validate a suite of supported mechanisms."
-  ;; See bug#49860 for a CAP 3.2-aware WIP implementation.
-  ((unless erc--target
+This local module only enables its minor mode in server buffers, and it
+doesn't currently solicit or validate supported mechanisms."
+  ((if erc--target
+       (erc-sasl-mode -1)
      (setq erc-sasl--state (make-erc-sasl--state))
      ;; If the previous attempt failed during registration, this may be
      ;; non-nil and contain erroneous values, but how can we detect that?
index 270ca74be85be3d60a22f57da89b834c3b70e805..b10504dd30680683b58a7fb2987b8197aa63d6e3 100644 (file)
@@ -613,8 +613,10 @@ In practical terms, this means that this module, which is still
 somewhat experimental, is likely only useful in conjunction with
 SASL authentication or CertFP rather than the traditional approach
 provided by the `services' module it shares a library with (see Info
-node `(erc) SASL' for more)."
-  nil nil localp)
+node `(erc) SASL' for more).
+
+This local module's minor mode is only active in server buffers."
+  ((when erc--target (erc-services-regain-mode -1))) nil localp)
 
 (cl-defmethod erc--nickname-in-use-make-request
   ((want string) temp &context (erc-server-connected null)
index 7fff9803164e95793f4bc37e7f0f55fdc58c69ae..fc2245e98311406f2918e72cd6c0038aaf2640c7 100644 (file)
@@ -2662,7 +2662,9 @@ side effect of setting the current buffer to the one it returns.  Use
     (erc--initialize-markers old-point continued-session)
     (erc-determine-parameters server port nick full-name user passwd)
     (save-excursion (run-mode-hooks)
-                    (dolist (mod (car delayed-modules)) (funcall mod +1))
+                    (dolist (mod (car delayed-modules))
+                      (unless (and (boundp mod) (symbol-value mod))
+                        (funcall mod +1)))
                     (dolist (var (cdr delayed-modules)) (set var nil)))
 
     ;; Saving log file on exit
index 63328f49d0dd71599208ab006fc06ea95ce00c31..df7a7e88839f656bbdb37531ed3032771e6aa85a 100644 (file)
         (erc-cmd-QUIT "")
         (funcall expect 10 "finished")))
 
-    (ert-info ("Disabling works from a target buffer")
+    (ert-info ("Explicit disabling affects entire session")
+      ;; Even though the mode variable is nil (but locally bound) in
+      ;; this target buffer, disabling interactively with
+      ;; `erc-sasl-disable', deactivates the module session-wide.
       (with-current-buffer "#chan"
-        (should erc-sasl-mode)
-        (call-interactively #'erc-sasl-disable)
         (should-not erc-sasl-mode)
         (should (local-variable-p 'erc-sasl-mode))
+        (should (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
+        (call-interactively #'erc-sasl-disable)
         (should-not (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
+        (should-not erc-sasl-mode)
         (erc-cmd-RECONNECT)
         (funcall expect 10 "Some enigma, some riddle")
-        (should-not erc-sasl-mode) ; regression
+        (should-not erc-sasl-mode)
         (should (local-variable-p 'erc-sasl-mode)))
 
       (with-current-buffer "foonet"
         (should (local-variable-p 'erc-sasl-mode))
+        (should-not erc-sasl-mode)
         (funcall expect 10 "User modes for tester`")
         (erc-cmd-QUIT "")
         (funcall expect 10 "finished")))
       (with-current-buffer "#chan"
         (call-interactively #'erc-sasl-enable)
         (should (local-variable-p 'erc-sasl-mode))
-        (should erc-sasl-mode)
+        (should-not erc-sasl-mode)
+        (should (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
         (erc-cmd-RECONNECT)
         (funcall expect 10 "Well met; good morrow, Titus and Hortensius.")
         (erc-cmd-QUIT ""))