From 9cd47017c705fe0efe8f42c143807a489ed69016 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Tue, 19 Dec 2023 22:33:48 -0800 Subject: [PATCH] Fix overlapping logs from erc-truncate-buffer-on-save * lisp/erc/erc-button.el (erc-button--display-error-notice-with-keys): Currently, internal "error notices" do not have timestamps. However, this causes alignment issues for non-`fill-wrap' users of left-sided stamps. The heuristic used by this change for detecting such stamps is weak and prone to false negatives. * lisp/erc/erc-log.el (erc-log-mode, erc-log-enable): Set explicit depth for `erc--pre-clear-functions' to 50. (erc-save-buffer-in-logs): Fix partial regression in which redundant text would appear in logs that have undergone truncation via an interactive call to this command when the deprecated option `erc-truncate-on-save' is non-nil. * lisp/erc/erc-stamp.el (erc-stamp-mode, erc-stamp-enable): Set depth for `erc--pre-clear-functions' to 40. (erc-stamp--reset-on-clear): Only add `erc-stamp--insert-date-hook' when `erc-stamp--date-mode' is active. * lisp/erc/erc.el (erc-cmd-CLEAR): Rework to honor but improve upon the old behavior when called from lisp. Do this by attempting to find the beginning of the current message and excluding it from the truncated portion of the buffer. A NEWS entry describing this behavior already exists for 5.6. * test/lisp/erc/erc-scenarios-log.el (erc-scenarios-log--save-buffer-in-logs/truncate-on-save): New test. These changes originate from bug#60936. --- lisp/erc/erc-button.el | 7 ++-- lisp/erc/erc-log.el | 5 +-- lisp/erc/erc-stamp.el | 7 ++-- lisp/erc/erc.el | 16 +++++---- test/lisp/erc/erc-scenarios-log.el | 55 ++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index a62dd520860..c290e76843c 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -829,6 +829,7 @@ argument when calling `erc-display-message'. Otherwise, add it to STRINGS. If STRINGS contains any trailing non-nil non-strings, concatenate leading string members before applying `format'. Otherwise, just concatenate everything." + (defvar erc-stamp--skip) (let* ((buffer (if (bufferp maybe-buffer) maybe-buffer (when (stringp maybe-buffer) @@ -844,8 +845,10 @@ non-strings, concatenate leading string members before applying (push head strings)) #'format)) (string (apply op strings)) - (erc-insert-modify-hook (remove 'erc-add-timestamp - erc-insert-modify-hook)) + ;; Avoid timestamps unless left-sided. + (erc-stamp--skip (or (bound-and-true-p erc-stamp--display-margin-mode) + (not (fboundp 'erc-timestamp-offset)) + (zerop (erc-timestamp-offset)))) (erc-insert-post-hook (cons (lambda () (setq string (buffer-substring (point-min) diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index 79fece5779e..5efde6cad11 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el @@ -231,7 +231,7 @@ also be a predicate function. To only log when you are not set away, use: (add-hook 'erc-part-hook #'erc-conditional-save-buffer) ;; append, so that 'erc-initialize-log-marker runs first (add-hook 'erc-connect-pre-hook #'erc-log-setup-logging 'append) - (add-hook 'erc--pre-clear-functions #'erc-save-buffer-in-logs) + (add-hook 'erc--pre-clear-functions #'erc-save-buffer-in-logs 50) (dolist (buffer (erc-buffer-list)) (erc-log-setup-logging buffer)) (erc--modify-local-map t "C-c C-l" #'erc-save-buffer-in-logs)) @@ -430,7 +430,8 @@ You can save every individual message by putting this function on (if (and erc-truncate-buffer-on-save (called-interactively-p 'interactive)) (let ((erc-log--save-in-progress-p t)) - (erc-cmd-CLEAR) + (save-excursion (goto-char erc-insert-marker) + (erc-cmd-CLEAR)) (erc-button--display-error-notice-with-keys (erc-server-buffer) "Option `%s' is deprecated." " Use /CLEAR instead." 'erc-truncate-buffer-on-save)) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 9ca3ea320a0..a65b564ba6c 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -182,7 +182,7 @@ from entering them and instead jump over them." (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 70) (add-hook 'erc-send-modify-hook #'erc-add-timestamp 70) (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) - (add-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear) + (add-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear 40) (unless erc--updating-modules-p (erc-buffer-do #'erc-stamp--setup))) ((remove-hook 'erc-mode-hook #'erc-munge-invisibility-spec) (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) @@ -973,8 +973,9 @@ with the option `erc-echo-timestamps', see the companion option (defun erc-stamp--reset-on-clear (pos) "Forget last-inserted stamps when POS is at insert marker." (when (= pos (1- erc-insert-marker)) - (add-hook 'erc-stamp--insert-date-hook - #'erc-stamp--update-saved-position 0 t) + (when erc-stamp--date-mode + (add-hook 'erc-stamp--insert-date-hook + #'erc-stamp--update-saved-position 0 t)) (setq erc-timestamp-last-inserted nil erc-timestamp-last-inserted-left nil erc-timestamp-last-inserted-right nil))) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 64629026704..6eee8bcae92 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -4160,12 +4160,16 @@ If no USER argument is specified, list the contents of `erc-ignore-list'." Called with position indicating boundary of interval to be excised.") (defun erc-cmd-CLEAR () - "Clear the window content." - (let ((inhibit-read-only t)) - (run-hook-with-args 'erc--pre-clear-functions (1- erc-insert-marker)) - ;; Ostensibly, `line-beginning-position' is for use in lisp code. - (delete-region (point-min) (min (line-beginning-position) - (1- erc-insert-marker)))) + "Clear messages in current buffer after informing active modules. +Expect modules to perform housekeeping tasks to withstand the +disruption. When called from lisp code, only clear messages up +to but not including the one occupying the current line." + (with-silent-modifications + (let ((max (if (>= (point) erc-insert-marker) + (1- erc-insert-marker) + (or (erc--get-inserted-msg-bounds 'beg) (pos-bol))))) + (run-hook-with-args 'erc--pre-clear-functions max) + (delete-region (point-min) max))) t) (put 'erc-cmd-CLEAR 'process-not-needed t) diff --git a/test/lisp/erc/erc-scenarios-log.el b/test/lisp/erc/erc-scenarios-log.el index cd28ea54b2e..cff88d59c85 100644 --- a/test/lisp/erc/erc-scenarios-log.el +++ b/test/lisp/erc/erc-scenarios-log.el @@ -206,4 +206,59 @@ (erc-truncate-mode -1) (when noninteractive (delete-directory tempdir :recursive)))) +(defvar erc-insert-timestamp-function) +(declare-function erc-insert-timestamp-left "erc-stamp" (string)) + +(ert-deftest erc-scenarios-log--save-buffer-in-logs/truncate-on-save () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/assoc/bouncer-history") + (dumb-server (erc-d-run "localhost" t 'foonet)) + (tempdir (make-temp-file "erc-tests-log." t nil nil)) + (erc-log-channels-directory tempdir) + (erc-modules (cons 'log erc-modules)) + (port (process-contact dumb-server :service)) + (erc-truncate-buffer-on-save t) + (logchan (expand-file-name (format "#chan!tester@127.0.0.1:%d.txt" port) + tempdir)) + (erc-server-flood-penalty 0.1) + (erc-insert-timestamp-function #'erc-insert-timestamp-left) + (expect (erc-d-t-make-expecter))) + + (unless noninteractive + (add-hook 'kill-emacs-hook + (lambda () (delete-directory tempdir :recursive)))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :password "foonet:changeme" + :full-name "tester") + (should (string= (buffer-name) (format "127.0.0.1:%d" port))))) + + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (funcall expect 10 " [07:04:10] hi everyone") + (should-not (file-exists-p logchan)) + ;; Simulate an M-x erc-save-buffer-in-logs RET + (cl-letf (((symbol-function 'called-interactively-p) #'always)) + (call-interactively #'erc-save-buffer-in-logs)) + (should (file-exists-p logchan)) + (funcall expect 10 " bob: As't please your lordship") + (erc-save-buffer-in-logs) + ;; Not truncated when called by lisp code. + (should (> (buffer-size) 400))) + + (ert-info ("No double entries") + (with-temp-buffer + (insert-file-contents logchan) + (funcall expect 0.1 "hi everyone") + (funcall expect -0.1 "hi everyone") + (funcall expect 0.1 "Playback Complete") + (funcall expect -0.1 "Playback Complete") + (funcall expect 10 " bob: As't"))) + + (erc-log-mode -1) + (when noninteractive (delete-directory tempdir :recursive)))) + ;;; erc-scenarios-log.el ends here -- 2.39.2