Restore erc-last-saved-position from previous session

* lisp/erc/erc-log.el (erc-log-setup-logging): Restore
`erc-last-saved-position' from previous session.  By default, a
non-/QUIT disconnect does not write out any remaining buffer text to
logs, instead leaving it until the buffer or Emacs is killed.  But if a
successful reconnect occurs beforehand, the uncommitted portion must be
seen to somehow.  Before this change, it would be lost because the
function `erc-initialize-log-marker' remakes the marker at the prompt
instead of recovering the previous value as now done here.  Moreover,
the traditional workaround of customizing `erc-log-write-after-insert'
and `erc-log-write-after-send' to t should not be required to prevent
gaps in any decent IRC client.
* test/lisp/erc/erc-scenarios-log.el (erc-scenarios-log--reconnect): New
function.
(erc-scenarios-log--reconnect/auto, erc-scenarios-log--reconnect/manual):
New tests.
;; * test/lisp/erc/resources/join/reconnect/foonet-again.eld: Add QUIT.
This commit is contained in:
F. Jason Park 2026-04-28 14:44:45 -07:00
parent c7bca9f340
commit ba2a150740
3 changed files with 122 additions and 0 deletions

View file

@ -256,6 +256,12 @@ This function is destined to be run from `erc-connect-pre-hook'.
The current buffer is given by BUFFER."
(when (erc-logging-enabled buffer)
(with-current-buffer buffer
(when-let* ((erc-last-saved-position)
(priors (or erc--server-reconnecting erc--target-priors))
(val (alist-get 'erc-last-saved-position priors))
(_ (eq buffer (marker-buffer val))))
;; Will have been initialized by `erc-initialize-log-marker'.
(move-marker erc-last-saved-position val))
(auto-save-mode -1)
(setq buffer-file-name nil)
(add-hook 'write-file-functions #'erc-save-buffer-in-logs nil t)

View file

@ -460,4 +460,116 @@
(erc-truncate-mode -1)
(when noninteractive (delete-directory tempdir :recursive))))
;; These tests check whether logs contain gaps when reconnecting.
(defun erc-scenarios-log--reconnect (autop)
(erc-scenarios-common-with-cleanup
((erc-scenarios-common-dialog "join/reconnect")
(dumb-server (erc-d-run "localhost" t 'foonet 'foonet-again))
(tempdir (make-temp-file "erc-tests-log." t nil nil))
(erc-log-channels-directory tempdir)
(erc-modules `(log ,@erc-modules))
(erc-timestamp-format-left "\n[@@DATE__STAMP@@]\n")
(port (process-contact dumb-server :service))
(erc-server-auto-reconnect autop)
(erc-server-flood-penalty 0.1)
(expect (erc-d-t-make-expecter))
;; Bind these so they'll be killed on teardown.
(server-log-buffer (get-buffer-create "*erc-log FooNet*"))
(chan-log-buffer (get-buffer-create "*erc-log #chan*"))
(spam-log-buffer (get-buffer-create "*erc-log #spam*")))
(ert-info ("Connect")
(with-current-buffer (erc :server "127.0.0.1"
:port port
:nick "tester"
:password "changeme"
:full-name "tester")
(funcall expect 10 "debug mode")))
(ert-info ("#chan populated")
(with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
(funcall expect 10 "@@DATE__STAMP@@")
(funcall expect 10 "<alice> tester, welcome")))
(ert-info ("#spam populated")
(with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
(funcall expect 10 "@@DATE__STAMP@@")
(funcall expect 10 "<alice> tester, welcome")))
(ert-info ("Reconnect")
(with-current-buffer "FooNet"
(funcall expect 10 "Connection failed!")
(if autop
(funcall expect 10 "Reconnecting")
(erc-scenarios-common-say "/reconnect"))
(funcall expect 10 "Welcome")
(funcall expect 10 "debug mode")))
(with-current-buffer "#chan"
(funcall expect -0.01 "@@DATE__STAMP@@")
(funcall expect 10 "<alice> bob: Well, this"))
(with-current-buffer "#spam"
(funcall expect -0.01 "@@DATE__STAMP@@")
(funcall expect 10 "<alice> bob: Our queen and all"))
(with-current-buffer "FooNet"
(erc-scenarios-common-say "/quit")
(funcall expect 10 "Quit"))
(with-current-buffer "FooNet"
(let ((file (erc-current-logfile (current-buffer))))
(with-current-buffer server-log-buffer
(insert-file-contents file)
(funcall expect 1 "@@DATE__STAMP@@")
(funcall expect 1 "*** Welcome to the foonet")
(funcall expect 1 "debug mode")
(funcall expect 1 "*** Connection failed!")
;; Full output again on reconnect.
(funcall expect -0.01 "@@DATE__STAMP@@") ; but no stamp
(funcall expect 1 "*** Welcome to the foonet")
(funcall expect 1 "debug mode"))))
(with-current-buffer "#chan"
(let ((file (erc-current-logfile (current-buffer))))
(with-current-buffer chan-log-buffer
(insert-file-contents file)
(funcall expect 1 "@@DATE__STAMP@@")
(funcall expect 1 "*** You have joined channel #chan")
(funcall expect 1 "<alice> tester, welcome!")
;; No stamp on reconnect.
(funcall expect -0.01 "@@DATE__STAMP@@")
(funcall expect 1 "*** You have joined channel #chan")
(funcall expect 1 "<alice> bob: Well, this is the forest"))))
(with-current-buffer "#spam"
(let ((file (erc-current-logfile (current-buffer))))
(with-current-buffer spam-log-buffer
(insert-file-contents file)
(funcall expect 1 "@@DATE__STAMP@@")
(funcall expect 1 "*** You have joined channel #spam")
(funcall expect 1 "<alice> tester, welcome!")
;; No stamp on reconnect.
(funcall expect -0.01 "@@DATE__STAMP@@")
(funcall expect 1 "*** You have joined channel #spam")
(funcall expect 1 "<alice> bob: Our queen and all her elves come"))))
(erc-log-mode -1)
(if noninteractive
(delete-directory tempdir :recursive)
(add-hook 'kill-emacs-hook
(lambda () (delete-directory tempdir :recursive))))))
(ert-deftest erc-scenarios-log--reconnect/auto ()
:tags '(:expensive-test)
(erc-scenarios-log--reconnect 'autop))
(ert-deftest erc-scenarios-log--reconnect/manual ()
:tags '(:expensive-test)
(erc-scenarios-log--reconnect nil))
;;; erc-scenarios-log.el ends here

View file

@ -43,3 +43,7 @@
(0 ":irc.foonet.org 329 tester #spam 1620104779")
(0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #spam :alice: Signior Iachimo will not from it. Pray, let us follow 'em.")
(0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #spam :bob: Our queen and all her elves come here anon."))
((quit 10 "QUIT :\2ERC\2")
(0.07 ":tester!~u@h3f95zveyc38a.irc QUIT :Quit: \2ERC\2 5.5 (IRC client for GNU Emacs 30.0.50)")
(0.01 "ERROR :Quit: \2ERC\2 5.5 (IRC client for GNU Emacs 30.0.50)"))