>From 4a7391f478c58f46e02fa2e38693e9c60a0c679b Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Sun, 7 May 2023 19:43:57 -0700 Subject: [PATCH 3/3] [5.6] Make some ERC module toggles more resilient * lisp/erc/erc-goodies.el (erc-scrolltobottom-mode, erc-scrolltobottom-enable, erc-move-to-prompt-mode, erc-move-to-prompt-enable): Guard setup procedure behind `erc--updating-modules-p'. * lisp/erc/erc-imenu.el (erc-imenu-mode, erc-imenu-enable, erc-imenu-disable): Don't run setup when `erc--updating-modules-p' is non-nil. Also don't restrict buffers to those of process on teardown. * lisp/erc/erc-match.el (erc-match-mode, erc-match-enable, erc-match-disable): Also major-mode hookee immediately. * lisp/erc/erc-spelling.el (erc-spelling-mode, erc-spelling-enable): Only conditionally run setup immediately. * lisp/erc/erc-stamp.el (erc-stamp-mode, erc-stamp-enable, erc-stamp-disable): Also run setup hook immediately. Don't forget to kill local vars in all ERC buffers during teardown. * lisp/erc/erc.el (erc--updating-modules-p): New variable that global modules use to provide their `erc-mode-hook'-deferred code on demand while guarding it from running during ERC buffer initialization. (erc-open): Make `erc--updating-modules-p' non-nil while activating global modules. --- lisp/erc/erc-goodies.el | 10 ++++------ lisp/erc/erc-imenu.el | 5 +++-- lisp/erc/erc-match.el | 4 +++- lisp/erc/erc-spelling.el | 5 +++-- lisp/erc/erc-stamp.el | 10 ++++++++-- lisp/erc/erc.el | 23 ++++++++++++++++++++++- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index 4558ff7c076..01eae4b63c5 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -53,9 +53,8 @@ scrolltobottom "This mode causes the prompt to stay at the end of the window." ((add-hook 'erc-mode-hook #'erc-add-scroll-to-bottom) (add-hook 'erc-insert-done-hook #'erc-possibly-scroll-to-bottom) - (dolist (buffer (erc-buffer-list)) - (with-current-buffer buffer - (erc-add-scroll-to-bottom)))) + (unless erc--updating-modules-p + (erc-buffer-filter #'erc-add-scroll-to-bottom))) ((remove-hook 'erc-mode-hook #'erc-add-scroll-to-bottom) (remove-hook 'erc-insert-done-hook #'erc-possibly-scroll-to-bottom) (dolist (buffer (erc-buffer-list)) @@ -120,9 +119,8 @@ erc-make-read-only (define-erc-module move-to-prompt nil "This mode causes the point to be moved to the prompt when typing text." ((add-hook 'erc-mode-hook #'erc-move-to-prompt-setup) - (dolist (buffer (erc-buffer-list)) - (with-current-buffer buffer - (erc-move-to-prompt-setup)))) + (unless erc--updating-modules-p + (erc-buffer-filter #'erc-move-to-prompt-setup))) ((remove-hook 'erc-mode-hook #'erc-move-to-prompt-setup) (dolist (buffer (erc-buffer-list)) (with-current-buffer buffer diff --git a/lisp/erc/erc-imenu.el b/lisp/erc/erc-imenu.el index 526afd32249..9864d7c4042 100644 --- a/lisp/erc/erc-imenu.el +++ b/lisp/erc/erc-imenu.el @@ -138,9 +138,10 @@ erc-imenu-setup ;;;###autoload(autoload 'erc-imenu-mode "erc-imenu" nil t) (define-erc-module imenu nil "Simple Imenu integration for ERC." - ((add-hook 'erc-mode-hook #'erc-imenu-setup)) + ((add-hook 'erc-mode-hook #'erc-imenu-setup) + (unless erc--updating-modules-p (erc-buffer-filter #'erc-imenu-setup))) ((remove-hook 'erc-mode-hook #'erc-imenu-setup) - (erc-with-all-buffers-of-server erc-server-process nil + (erc-with-all-buffers-of-server nil nil (when erc-imenu--create-index-function (setq imenu-create-index-function erc-imenu--create-index-function) (kill-local-variable 'erc-imenu--create-index-function))))) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index c08a640260c..967ba039102 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -54,10 +54,12 @@ match highlighted." ((add-hook 'erc-insert-modify-hook #'erc-match-message 'append) (add-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) + (unless erc--updating-modules-p + (erc-buffer-filter #'erc-match--modify-invisibility-spec)) (erc--modify-local-map t "C-c C-k" #'erc-go-to-log-matches-buffer)) ((remove-hook 'erc-insert-modify-hook #'erc-match-message) (remove-hook 'erc-mode-hook #'erc-match--modify-invisibility-spec) - (erc-match--modify-invisibility-spec) + (erc-buffer-filter #'erc-match--modify-invisibility-spec) (erc--modify-local-map nil "C-c C-k" #'erc-go-to-log-matches-buffer))) ;; Remaining customizations diff --git a/lisp/erc/erc-spelling.el b/lisp/erc/erc-spelling.el index 8fce2508ceb..8e5424f4162 100644 --- a/lisp/erc/erc-spelling.el +++ b/lisp/erc/erc-spelling.el @@ -39,8 +39,9 @@ spelling ;; Use erc-connect-pre-hook instead of erc-mode-hook as pre-hook is ;; called AFTER the server buffer is initialized. ((add-hook 'erc-connect-pre-hook #'erc-spelling-init) - (dolist (buffer (erc-buffer-list)) - (erc-spelling-init buffer))) + (unless erc--updating-modules-p + (erc-with-all-buffers-of-server nil nil + (erc-spelling-init (current-buffer))))) ((remove-hook 'erc-connect-pre-hook #'erc-spelling-init) (dolist (buffer (erc-buffer-list)) (with-current-buffer buffer (flyspell-mode 0))))) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index f90a8fc50b1..9191bbe5a2a 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -165,11 +165,17 @@ stamp ((add-hook 'erc-mode-hook #'erc-munge-invisibility-spec) (add-hook 'erc-insert-modify-hook #'erc-add-timestamp t) (add-hook 'erc-send-modify-hook #'erc-add-timestamp t) - (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect)) + (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) + (unless erc--updating-modules-p + (erc-buffer-filter #'erc-munge-invisibility-spec))) ((remove-hook 'erc-mode-hook #'erc-munge-invisibility-spec) (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp) - (remove-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect))) + (remove-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) + (erc-with-all-buffers-of-server nil nil + (kill-local-variable 'erc-timestamp-last-inserted) + (kill-local-variable 'erc-timestamp-last-inserted-left) + (kill-local-variable 'erc-timestamp-last-inserted-right)))) (defun erc-stamp--recover-on-reconnect () (when-let ((priors (or erc--server-reconnecting erc--target-priors))) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 249b9963cea..41d4f068ecd 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2084,6 +2084,26 @@ erc--update-modules (push mode local-modes)) (error "`%s' is not a known ERC module" module))))) +(defvar erc--updating-modules-p nil + "Non-nil when running `erc--update-modules' in `erc-open'. +This allows global modules with known or likely dependents (or +some other reason for activating after session initialization) to +conditionally run setup code traditionally reserved for +`erc-mode-hook' in the setup portion of their mode toggle. Note +that being \"global\", they'll likely want to do so in all ERC +buffers and ensure the code is idempotent. For example: + + (add-hook \\='erc-mode-hook #\\='erc-foo-setup-fn) + (unless erc--updating-modules-p + (erc-with-all-buffers-of-server nil + (lambda () some-condition-p) + (erc-foo-setup-fn))) + +This means that when a dependent module is initializing and +realizes it's missing some required module \"foo\", it can +confidently call (erc-foo-mode 1) without having to learn +anything about the dependency's implementation.") + (defun erc--setup-buffer-first-window (frame a b) (catch 'found (walk-window-tree @@ -2243,7 +2263,8 @@ erc-open (set-buffer buffer) (setq old-point (point)) (setq delayed-modules - (erc--merge-local-modes (erc--update-modules) + (erc--merge-local-modes (let ((erc--updating-modules-p t)) + (erc--update-modules)) (or erc--server-reconnecting erc--target-priors))) -- 2.40.0