From 49e66fee68a4ad69418dae329e24e5611ea8de6e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Wed, 26 Jul 2023 05:33:54 -0700 Subject: [PATCH 0/1] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (1): [5.6] Consider all windows in erc-scrolltobottom-mode lisp/erc/erc-goodies.el | 102 +++++++++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 11 deletions(-) Interdiff: diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index af44b98e0bf..e82dc73f82f 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -52,22 +52,26 @@ erc-input-line-position (define-erc-module scrolltobottom nil "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-pre-hook #'erc--on-pre-insert) + (add-hook 'erc-insert-pre-hook #'erc--scroll-to-bottom-on-pre-insert) + (add-hook 'erc-send-pre-functions #'erc--scroll-to-bottom-on-pre-insert) (add-hook 'erc-insert-done-hook #'erc--scroll-to-bottom-all) (add-hook 'erc-send-completed-hook #'erc--scroll-to-bottom-all) (unless erc--updating-modules-p (erc-buffer-do #'erc-add-scroll-to-bottom))) ((remove-hook 'erc-mode-hook #'erc-add-scroll-to-bottom) - (remove-hook 'erc-insert-pre-hook #'erc--on-pre-insert) + (remove-hook 'erc-insert-pre-hook #'erc--scroll-to-bottom-on-pre-insert) + (remove-hook 'erc-send-pre-functions #'erc--scroll-to-bottom-on-pre-insert) (remove-hook 'erc-insert-done-hook #'erc--scroll-to-bottom-all) (remove-hook 'erc-send-completed-hook #'erc--scroll-to-bottom-all) (erc-buffer-do #'erc-add-scroll-to-bottom))) (defvar-local erc--scroll-to-bottom-debounce-expire nil - "Time after which `scrolltobottom' is allowed to run. -Set to a fraction of a second in the future on every refresh.") + "A cons of some window and the expiration time in seconds. +The CAR is a window in whose buffer this variable is local. The +CDR is a half second after the last attempted refresh of such a +window.") (defvar-local erc--scroll-to-bottom-last-window-start nil - "A cons of a window and a starting position.") + "Alist whose members are a cons of a window and a starting position.") (defun erc-possibly-scroll-to-bottom () "Like `erc-add-scroll-to-bottom', but only if window is selected." @@ -76,18 +80,36 @@ erc-possibly-scroll-to-bottom (defun erc--possibly-scroll-to-bottom () "Call `erc-scroll-to-bottom' when buffer occupies selected window. -Skip when `erc--scroll-to-bottom-debounce-expire' has not yet -arrived." +Expect narrowing not to be in effect. Skip when +`erc--scroll-to-bottom-debounce-expire' has not yet transpired." (when (eq (selected-window) (get-buffer-window)) - (unless (eq this-command 'recenter-top-bottom) - (let (erc--scroll-to-bottom-last-window-start) - (erc--scroll-to-bottom))))) + (unless (or (eq this-command 'recenter-top-bottom) (input-pending-p)) + (let ((now (erc-current-time)) + (at-prompt-p (>= (point) erc-input-marker))) + (unless (and at-prompt-p + erc--scroll-to-bottom-debounce-expire + (eq (car erc--scroll-to-bottom-debounce-expire) + (selected-window)) + (< now (cdr erc--scroll-to-bottom-debounce-expire))) + (erc--scroll-to-bottom)) + (setq erc--scroll-to-bottom-debounce-expire + (and at-prompt-p (cons (selected-window) (+ now 0.5)))))))) (defun erc--scroll-to-bottom-all (&rest _) - "Run `erc-scroll-to-bottom' in all windows showing current buffer." + "Maybe put prompt on last line in all windows displaying current buffer. +Expect to run when narrowing is in effect, such as on insertion +or send-related hooks. When recentering has not been performed, +attempt to restore last `window-start', if known." (dolist (window (get-buffer-window-list nil nil 'visible)) (with-selected-window window - (erc--scroll-to-bottom)))) + (when-let + (((not (erc--scroll-to-bottom))) + (erc--scroll-to-bottom-last-window-start) + (found (assq window erc--scroll-to-bottom-last-window-start))) + (setf (window-start window) (cdr found))))) + ;; Necessary unless we're sure `erc--scroll-to-bottom-on-pre-insert' + ;; always runs between calls to this function. + (setq erc--scroll-to-bottom-last-window-start nil)) (defun erc-add-scroll-to-bottom () "Arrange for `scrolltobottom' to refresh on window configuration changes. @@ -110,31 +132,30 @@ erc-add-scroll-to-bottom (remove-hook 'post-command-hook #'erc--possibly-scroll-to-bottom t))) -(defun erc--on-pre-insert (&rest _) - (when (eq (selected-window) (get-buffer-window)) - (setq erc--scroll-to-bottom-last-window-start - (cons (selected-window) (window-start))))) +(cl-defmethod erc--scroll-to-bottom-on-pre-insert (_input-or-string) + "Remember the `window-start' before inserting a message." + (setq erc--scroll-to-bottom-last-window-start + (mapcar (lambda (w) (cons w (window-start w))) + (get-buffer-window-list nil nil 'visible)))) + +(cl-defmethod erc--scroll-to-bottom-on-pre-insert ((input erc-input)) + "Remember the `window-start' before inserting a message." + (when (erc-input-insertp input) + (cl-call-next-method))) (defun erc--scroll-to-bottom () "Like `erc-scroll-to-bottom', but use `window-point'. Expect to run in some window, not necessarily the user-selected -one." +one. Return non-nil when recentering has occurred." (when erc-insert-marker (let ((resize-mini-windows nil)) (save-restriction (widen) - (if (>= (window-point) erc-input-marker) - (save-excursion - (goto-char (point-max)) - (recenter (or erc-input-line-position -1))) - (when (and erc--scroll-to-bottom-last-window-start - ;; `selected-window' means the one being visited. - (eq (selected-window) - (car erc--scroll-to-bottom-last-window-start))) - (save-excursion - (goto-char (cdr erc--scroll-to-bottom-last-window-start)) - (let ((recenter-positions '(top))) - (recenter-top-bottom))))))))) + (when (>= (window-point) erc-input-marker) + (save-excursion + (goto-char (point-max)) + (recenter (or erc-input-line-position -1)) + t)))))) (defun erc-scroll-to-bottom () "Recenter WINDOW so that `point' is on the last line. -- 2.41.0