Use correct buffer for local-module vars in erc-open

* lisp/erc/erc.el (erc--target-priors): New internal variable to do
for target buffers what `erc--server-reconnecting' does for server
buffers.
(erc-open): Source the state of a local module's mode variable from
its actual buffer rather than its server buffer.  Additionally, make
all local variables from a prior session available to
module-activation functions and `erc-mode' hooks, even when
`erc-reuse-buffers' is nil.  This bug arrived with the introduction of
"local-modules" (bug#57955).

* test/lisp/erc/erc-scenarios-base-local-modules.el
(erc-scenarios-base-local-modules--toggle-helpers): Remove useless
`with-current-buffer'.
(erc-scenarios-base-local-modules--local-var, erc--phony-sblm--enable,
erc--phony-sblm--disable, erc--phony-sblm--mode): Add fake local
module and data var for test scenario.
(erc-scenarios-base-local-modules--var-persistence) Add slightly hacky
test case with promise to improve later when splitting the file.
This commit is contained in:
F. Jason Park 2023-01-16 23:05:16 -08:00
parent 7b13422298
commit 7b8322f628
2 changed files with 106 additions and 9 deletions

View file

@ -1305,6 +1305,14 @@ See also `erc-show-my-nick'."
(defvar-local erc-dbuf nil)
;; See comments in `erc-scenarios-base-local-modules' explaining why
;; this is insufficient as a public interface.
(defvar erc--target-priors nil
"Analogous to `erc--server-reconnecting' but for target buffers.
Bound to local variables from an existing (logical) session's
buffer during local-module setup and `erc-mode-hook' activation.")
(defun erc--target-from-string (string)
"Construct an `erc--target' variant from STRING."
(funcall (if (erc-channel-p string)
@ -1985,7 +1993,9 @@ Returns the buffer for the given server or channel."
(let* ((target (and channel (erc--target-from-string channel)))
(buffer (erc-get-buffer-create server port nil target id))
(old-buffer (current-buffer))
(old-vars (and target (buffer-local-variables)))
(erc--target-priors (and target ; buf from prior session
(buffer-local-value 'erc--target buffer)
(buffer-local-variables buffer)))
(old-recon-count erc-server-reconnect-count)
(old-point nil)
(delayed-modules nil)
@ -1998,7 +2008,8 @@ Returns the buffer for the given server or channel."
(setq old-point (point))
(setq delayed-modules
(erc--merge-local-modes (erc--update-modules)
(or erc--server-reconnecting old-vars)))
(or erc--server-reconnecting
erc--target-priors)))
(delay-mode-hooks (erc-mode))

View file

@ -19,8 +19,17 @@
;;; Commentary:
;; These tests all use `sasl' because, as of ERC 5.5, it's the one
;; and only local module.
;; A local module doubles as a minor mode whose mode variable and
;; associated local data can withstand service disruptions.
;; Unfortunately, the current implementation is too unwieldy to be
;; made public because it doesn't perform any of the boiler plate
;; needed to save and restore buffer-local and "network-local" copies
;; of user options. Ultimately, a user-friendly framework must fill
;; this void if third-party local modules are ever to become
;; practical.
;;
;; The following tests all use `sasl' because, as of ERC 5.5, it's the
;; only local module.
;;; Code:
@ -206,7 +215,7 @@
(erc-cmd-QUIT "")
(funcall expect 10 "finished")))
(ert-info ("Disabling works from a target buffer.")
(ert-info ("Disabling works from a target buffer")
(with-current-buffer "#chan"
(should erc-sasl-mode)
(call-interactively #'erc-sasl-disable)
@ -214,10 +223,9 @@
(should (local-variable-p 'erc-sasl-mode))
(should-not (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
(erc-cmd-RECONNECT)
(with-current-buffer "#chan"
(funcall expect 10 "Some enigma, some riddle")
(should-not erc-sasl-mode) ; regression
(should (local-variable-p 'erc-sasl-mode))))
(funcall expect 10 "Some enigma, some riddle")
(should-not erc-sasl-mode) ; regression
(should (local-variable-p 'erc-sasl-mode)))
(with-current-buffer "foonet"
(should (local-variable-p 'erc-sasl-mode))
@ -239,4 +247,82 @@
(should erc-sasl-mode)
(funcall expect 10 "User modes for tester")))))
(defvar-local erc-scenarios-base-local-modules--local-var nil)
(define-erc-module -phony-sblm- nil
"Test module for `erc-scenarios-base-local-modules--var-persistence'."
((when-let ((vars (or erc--server-reconnecting erc--target-priors)))
(should (assq 'erc--phony-sblm--mode vars))
(setq erc-scenarios-base-local-modules--local-var
(alist-get 'erc-scenarios-base-local-modules--local-var vars)))
(setq erc-scenarios-base-local-modules--local-var
(or erc-scenarios-base-local-modules--local-var
(if erc--target 100 0))))
((kill-local-variable 'erc-scenarios-base-local-modules--local-var))
'local)
;; Note: this file has grown too expensive (time-wise) and must be
;; split up. When that happens, this test should be rewritten without
;; any time-saving hacks, namely, server-initiated JOINs and an
;; absence of QUITs. (That said, three connections in under 2 seconds
;; is pretty nice.)
(ert-deftest erc-scenarios-base-local-modules--var-persistence ()
:tags '(:expensive-test)
(erc-scenarios-common-with-cleanup
((erc-scenarios-common-dialog "base/reconnect")
(erc-server-flood-penalty 0.1)
(dumb-server (erc-d-run "localhost" t 'options 'options 'options))
(port (process-contact dumb-server :service))
(erc-modules (cons '-phony-sblm- (remq 'autojoin erc-modules)))
(expect (erc-d-t-make-expecter))
(server-buffer-name (format "127.0.0.1:%d" port)))
(ert-info ("Initial authentication succeeds as expected")
(with-current-buffer (erc :server "127.0.0.1"
:port port
:nick "tester"
:password "changeme"
:full-name "tester")
(should (string= (buffer-name) server-buffer-name)))
(with-current-buffer (erc-d-t-wait-for 10 (get-buffer "FooNet"))
(funcall expect 10 "This server is in debug mode")
(should erc--phony-sblm--mode)
(should (eql erc-scenarios-base-local-modules--local-var 0))
(setq erc-scenarios-base-local-modules--local-var 1)))
(ert-info ("Save module's local var in target buffer")
(with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
(should (eql erc-scenarios-base-local-modules--local-var 100))
(setq erc-scenarios-base-local-modules--local-var 101)
(funcall expect 20 "welcome")))
(with-current-buffer "FooNet" (funcall expect 20 "terminated"))
(ert-info ("Vars reused when mode was left enabled")
(with-current-buffer "#chan"
(erc-cmd-RECONNECT)
(funcall expect 20 "welcome")
(should (eql erc-scenarios-base-local-modules--local-var 101))
(erc--phony-sblm--mode -1))
(with-current-buffer "FooNet"
(funcall expect 10 "User modes for tester")
(should (eql erc-scenarios-base-local-modules--local-var 1))))
(with-current-buffer "FooNet" (funcall expect 20 "terminated"))
(ert-info ("Local binding gone when mode disabled in target")
(with-current-buffer "#chan"
(erc-cmd-RECONNECT)
(funcall expect 20 "welcome")
(should-not erc--phony-sblm--mode)
(should-not erc-scenarios-base-local-modules--local-var))
;; But value retained in server buffer, where mode is active.
(with-current-buffer "FooNet"
(funcall expect 10 "User modes for tester")
(should (eql erc-scenarios-base-local-modules--local-var 1))))))
;;; erc-scenarios-local-modules.el ends here