Subject: Re: bug#64855: 30.0.50; ERC 5.6: Make scrolltobottom less erratic

From: "J.P." <[email-masked]>
Date: Fri, 18 Aug 2023 06:50:18 -0700

v4. Fix bug involving new option `erc-scrolltobottom-relaxed'. Specify
explicit hook depths for `erc--scrolltobottom-on-pre-command{,-relaxed}'
and `erc-move-to-prompt' in `pre-command-hook'. Remove assertions.

This still needs tests and a news entry.

>From 78e5fa32620b386b283f16383f16c713e628a0ff Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Fri, 18 Aug 2023 06:36:44 -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 | 222 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 208 insertions(+), 14 deletions(-)

Interdiff:
diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index 129e17fb5ec..891641f77f7 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -100,15 +100,15 @@ erc--scrolltobottom-window-info
 `window-point', inclusive.")
 
 (defvar erc--scrolltobottom-post-force-commands
-  '(electric-newline-and-maybe-indent)
+  '(electric-newline-and-maybe-indent default-indent-new-line)
   "Commands that force a scroll after execution at prompt.")
 
-(defvar erc--scrolltobottom-relaxed-skip-commands '(recenter-top-bottom))
+(defvar erc--scrolltobottom-relaxed-skip-commands
+  '(recenter-top-bottom scroll-down-command))
 
 (defun erc--scrolltobottom-on-pre-command ()
-  (cl-assert (not erc-scrolltobottom-relaxed)) ; delete me
-  (cl-assert (eq (selected-window) (get-buffer-window))) ; delete me
-  (when (> (point) erc-input-marker)
+  (when (and (eq (selected-window) (get-buffer-window))
+             (>= (point) erc-input-marker))
     (setq erc--scrolltobottom-window-info
           (list (list (selected-window)
                       (window-start)
@@ -120,17 +120,17 @@ erc--scrolltobottom-on-post-command
 item is associated with the selected window, restore start of
 window so long as prompt hasn't moved.  Expect buffer to be
 unnarrowed."
-  (cl-assert (not erc-scrolltobottom-relaxed)) ; delete me
-  (cl-assert (eq (selected-window) (get-buffer-window))) ; delete me
-  (if-let (((not (input-pending-p)))
-           (erc--scrolltobottom-window-info)
-           (found (car erc--scrolltobottom-window-info))
-           ((eq (car found) (selected-window)))
-           ((not (memq this-command erc--scrolltobottom-post-force-commands)))
-           ((= (nth 2 found) (count-screen-lines (window-start) (point)))))
-      (set-window-start (selected-window) (nth 1 found))
-    (erc--scrolltobottom-confirm))
-  (setq erc--scrolltobottom-window-info nil))
+  (when (eq (selected-window) (get-buffer-window))
+    (if-let (((not (input-pending-p)))
+             (erc--scrolltobottom-window-info)
+             (found (car erc--scrolltobottom-window-info))
+             ((eq (car found) (selected-window)))
+             ((not (memq this-command
+                         erc--scrolltobottom-post-force-commands)))
+             ((= (nth 2 found) (count-screen-lines (window-start) (point)))))
+        (set-window-start (selected-window) (nth 1 found))
+      (erc--scrolltobottom-confirm))
+    (setq erc--scrolltobottom-window-info nil)))
 
 (defun erc--scrolltobottom-on-pre-command-relaxed ()
   "Maybe scroll to bottom when away from prompt in an unnarrowed buffer.
@@ -139,28 +139,26 @@ erc--scrolltobottom-on-pre-command-relaxed
 `self-insert-command' (assuming `move-to-prompt' is active).
 When at prompt and current command is not `recenter-top-bottom',
 stash `erc--scrolltobottom-window-info' for the selected window."
-  (cl-assert erc-scrolltobottom-relaxed) ; delete me
-  (cl-assert (eq (selected-window) (get-buffer-window))) ; delete me
-  (when (and (not (input-pending-p))
-             (< (point) erc-input-marker)
-             (memq this-command erc--scrolltobottom-relaxed-commands)
-             (< (window-end nil t) erc-input-marker))
-    (save-excursion
-      (goto-char (point-max))
-      (recenter (or erc-input-line-position -1))))
-  (when (and (> (point) erc-input-marker)
-             (not (memq this-command
-                        erc--scrolltobottom-relaxed-skip-commands)))
-    (setq erc--scrolltobottom-window-info
-          (list (list (selected-window)
-                      (window-start)
-                      (count-screen-lines (window-start) (point-max)))))))
+  (when (eq (selected-window) (get-buffer-window))
+    (when (and (not (input-pending-p))
+               (< (point) erc-input-marker)
+               (memq this-command erc--scrolltobottom-relaxed-commands)
+               (< (window-end nil t) erc-input-marker))
+      (save-excursion
+        (goto-char (point-max))
+        (recenter (or erc-input-line-position -1))))
+    (when (and (>= (point) erc-input-marker)
+               (not (memq this-command
+                          erc--scrolltobottom-relaxed-skip-commands)))
+      (setq erc--scrolltobottom-window-info
+            (list (list (selected-window)
+                        (window-start)
+                        (count-screen-lines (window-start) (point-max))))))))
 
 (defun erc--scrolltobottom-on-post-command-relaxed ()
   "Set window start or scroll when data was captured on pre-command."
-  (cl-assert erc-scrolltobottom-relaxed) ; delete me
-  (cl-assert (eq (selected-window) (get-buffer-window))) ; delete me
-  (when-let ((erc--scrolltobottom-window-info)
+  (when-let (((eq (selected-window) (get-buffer-window)))
+             (erc--scrolltobottom-window-info)
              (found (car erc--scrolltobottom-window-info))
              ((eq (car found) (selected-window))))
     (if (and (not (memq this-command erc--scrolltobottom-post-force-commands))
@@ -217,13 +215,13 @@ erc-add-scroll-to-bottom
                 (cl-pushnew 'self-insert-command
                             erc--scrolltobottom-relaxed-commands))
               (add-hook 'post-command-hook
-                        #'erc--scrolltobottom-on-post-command-relaxed -90 t)
+                        #'erc--scrolltobottom-on-post-command-relaxed 60 t)
               (add-hook 'pre-command-hook ; preempt `move-to-prompt'
-                        #'erc--scrolltobottom-on-pre-command-relaxed -90 t))
+                        #'erc--scrolltobottom-on-pre-command-relaxed 60 t))
           (add-hook 'pre-command-hook
-                    #'erc--scrolltobottom-on-pre-command nil t)
+                    #'erc--scrolltobottom-on-pre-command 60 t)
           (add-hook 'post-command-hook
-                    #'erc--scrolltobottom-on-post-command nil t)))
+                    #'erc--scrolltobottom-on-post-command 60 t)))
     (remove-hook 'window-configuration-change-hook
                  #'erc--scrolltobottom-away-from-prompt t)
     (remove-hook 'pre-command-hook
@@ -246,7 +244,7 @@ erc--scrolltobottom-on-pre-insert
                         (and-let*
                             ((erc-scrolltobottom-relaxed)
                              (c (count-screen-lines (window-start w)
-                                                    (window-point w) nil w)))
+                                                    (point-max) nil w)))
                           (if (= ?\n (char-before (point-max))) (1+ c) c))))
                 (get-buffer-window-list nil nil 'visible))))
 
@@ -328,7 +326,7 @@ erc-move-to-prompt
 
 (defun erc-move-to-prompt-setup ()
   "Initialize the move-to-prompt module."
-  (add-hook 'pre-command-hook #'erc-move-to-prompt nil t))
+  (add-hook 'pre-command-hook #'erc-move-to-prompt 70 t))
 
 ;;; Keep place in unvisited channels
 ;;;###autoload(autoload 'erc-keep-place-mode "erc-goodies" nil t)
-- 
2.41.0

>From 78e5fa32620b386b283f16383f16c713e628a0ff Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Sat, 22 Jul 2023 00:46:44 -0700
Subject: [PATCH 1/1] [5.6] Consider all windows in erc-scrolltobottom-mode

* lisp/erc/erc-goodies.el (erc-input-line-position): Mention secondary
role when new option `erc-scroll-to-bottom-relaxed' is non-nil.
(erc-scrolltobottom-relaxed): New option to leave the prompt
stationary instead of forcing it to the bottom of the window.
(erc-scrolltobottom-mode, erc-scrolltobottom-enable,
erc-scrolltobottom-disable): Use `erc--scrolltobottom-all' instead
of `erc-possibly-scroll-to-bottom' for `erc-insert-done-hook' and now
also `erc-send-completed-hook'.  Add
`erc--scrolltobottom-on-pre-insert' to `erc-insert-pre-hook' and
`erc-pre-send-functions'.  Call `erc-add-scroll-to-bottom' for
teardown as well.
(erc--scrolltobottom-relaxed-commands,
erc--scrolltobottom-window-info,
erc--scrolltobottom-post-force-commands,
erc--scrolltobottom-relaxed-skip-commands): New internal variables.
(erc--scrolltobottom-on-pre-command
erc--scrolltobottom-on-post-command): New functions resembling
`erc-possibly-scroll-to-bottom' that try to avoid scrolling repeatedly
for no reason.
(erc--scrolltobottom-on-pre-command-relaxed,
erc--scrolltobottom-on-post-command-relaxed): New commands to help
implement `erc-scroll-to-bottom-relaxed'.
(erc--scrolltobottom-away-from-prompt): New function to scroll to
bottom on window configuration changes.
(erc--scrolltobottom-all): New function to scroll all windows
displaying the current buffer.
(erc-add-scroll-to-bottom): Perform teardown as well when mode is
disabled.  Also scroll on `window-configuration-changed-hook'.
(erc--scrolltobottom-on-pre-insert): New generic function that
remembers the last `window-start' and maybe the current line before
inserting a message in order to restore it afterward.
(erc--scrolltobottom-confirm): New function, a replacement for
`erc-scroll-to-bottom', that returns non-nil when it's actually
recentered the window.
(erc-move-to-prompt-setup): Add `erc-move-to-prompt' to
`pre-command-hook' at a depth of 70.
(erc--keep-place-indicator-setup): Add overlay arrow `after-string' in
non-graphical settings in case users have time stamps or other content
occupying the left margin.  (Bug#64855)
---
 lisp/erc/erc-goodies.el | 222 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 208 insertions(+), 14 deletions(-)

diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index d9ededa8e68..891641f77f7 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -44,42 +44,233 @@ erc-input-line-position
 This should be an integer specifying the line of the buffer on which
 the input line should stay.  A value of \"-1\" would keep the input
 line positioned on the last line in the buffer.  This is passed as an
-argument to `recenter'."
+argument to `recenter', unless `erc-scrolltobottom-relaxed' is
+non-nil, in which case, ERC interprets it as additional lines to
+scroll down by per message insertion (minus one for the prompt)."
   :group 'erc-display
   :type '(choice integer (const nil)))
 
+(defcustom erc-scrolltobottom-relaxed nil
+  "Whether to forgo forcing prompt to the bottom of the window.
+When non-nil, and point is at the prompt, ERC scrolls the window
+up when inserting messages, making the prompt appear stationary.
+Users who find this effect too \"stagnant\" can adjust the option
+`erc-input-line-position', which ERC borrows to express a scroll
+offset when this option is non-nil.  Setting that value to zero
+lets the prompt drift toward the bottom by one line per message,
+which is generally slow enough not to distract while composing
+input.  Of course, this doesn't apply when receiving a large
+influx of messages, such as after typing \"/msg NickServ help\".
+Note that ERC only considers this option when initializing the
+`scrolltobottom' module and enabling `erc-scrolltobottom-mode'."
+  :group 'erc-display
+  :package-version '(ERC . "5.6") ; FIXME sync on release
+  :type 'boolean)
+
 ;;;###autoload(autoload 'erc-scrolltobottom-mode "erc-goodies" nil t)
 (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-done-hook #'erc-possibly-scroll-to-bottom)
+   (add-hook 'erc-insert-pre-hook #'erc--scrolltobottom-on-pre-insert)
+   (add-hook 'erc-pre-send-functions #'erc--scrolltobottom-on-pre-insert)
+   (add-hook 'erc-insert-done-hook #'erc--scrolltobottom-all)
+   (add-hook 'erc-send-completed-hook #'erc--scrolltobottom-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-done-hook #'erc-possibly-scroll-to-bottom)
-   (dolist (buffer (erc-buffer-list))
-     (with-current-buffer buffer
-       (remove-hook 'post-command-hook #'erc-scroll-to-bottom t)))))
+   (remove-hook 'erc-insert-pre-hook #'erc--scrolltobottom-on-pre-insert)
+   (remove-hook 'erc-pre-send-functions #'erc--scrolltobottom-on-pre-insert)
+   (remove-hook 'erc-insert-done-hook #'erc--scrolltobottom-all)
+   (remove-hook 'erc-send-completed-hook #'erc--scrolltobottom-all)
+   (erc-buffer-do #'erc-add-scroll-to-bottom)))
 
 (defun erc-possibly-scroll-to-bottom ()
   "Like `erc-add-scroll-to-bottom', but only if window is selected."
   (when (eq (selected-window) (get-buffer-window))
     (erc-scroll-to-bottom)))
 
+(defvar-local erc--scrolltobottom-relaxed-commands '(end-of-buffer)
+  "Commands triggering a force scroll to prompt.
+Only applies with `erc-scrolltobottom-relaxed' when away from prompt.")
+
+(defvar-local erc--scrolltobottom-window-info nil
+  "Alist with windows as keys and lists of window-related info as values.
+Values are lists containing the last window start position and
+the last \"window line\" of point.  The \"window line\", which
+may be nil, is the number of lines between `window-start' and
+`window-point', inclusive.")
+
+(defvar erc--scrolltobottom-post-force-commands
+  '(electric-newline-and-maybe-indent default-indent-new-line)
+  "Commands that force a scroll after execution at prompt.")
+
+(defvar erc--scrolltobottom-relaxed-skip-commands
+  '(recenter-top-bottom scroll-down-command))
+
+(defun erc--scrolltobottom-on-pre-command ()
+  (when (and (eq (selected-window) (get-buffer-window))
+             (>= (point) erc-input-marker))
+    (setq erc--scrolltobottom-window-info
+          (list (list (selected-window)
+                      (window-start)
+                      (count-screen-lines (window-start) (point)))))))
+
+(defun erc--scrolltobottom-on-post-command ()
+  "Restore window start or scroll to prompt and recenter.
+When `erc--scrolltobottom-window-info' is non-nil and its first
+item is associated with the selected window, restore start of
+window so long as prompt hasn't moved.  Expect buffer to be
+unnarrowed."
+  (when (eq (selected-window) (get-buffer-window))
+    (if-let (((not (input-pending-p)))
+             (erc--scrolltobottom-window-info)
+             (found (car erc--scrolltobottom-window-info))
+             ((eq (car found) (selected-window)))
+             ((not (memq this-command
+                         erc--scrolltobottom-post-force-commands)))
+             ((= (nth 2 found) (count-screen-lines (window-start) (point)))))
+        (set-window-start (selected-window) (nth 1 found))
+      (erc--scrolltobottom-confirm))
+    (setq erc--scrolltobottom-window-info nil)))
+
+(defun erc--scrolltobottom-on-pre-command-relaxed ()
+  "Maybe scroll to bottom when away from prompt in an unnarrowed buffer.
+When `erc-scrolltobottom-relaxed' is active, only scroll when
+prompt is past window's end and the command is `end-of-buffer' or
+`self-insert-command' (assuming `move-to-prompt' is active).
+When at prompt and current command is not `recenter-top-bottom',
+stash `erc--scrolltobottom-window-info' for the selected window."
+  (when (eq (selected-window) (get-buffer-window))
+    (when (and (not (input-pending-p))
+               (< (point) erc-input-marker)
+               (memq this-command erc--scrolltobottom-relaxed-commands)
+               (< (window-end nil t) erc-input-marker))
+      (save-excursion
+        (goto-char (point-max))
+        (recenter (or erc-input-line-position -1))))
+    (when (and (>= (point) erc-input-marker)
+               (not (memq this-command
+                          erc--scrolltobottom-relaxed-skip-commands)))
+      (setq erc--scrolltobottom-window-info
+            (list (list (selected-window)
+                        (window-start)
+                        (count-screen-lines (window-start) (point-max))))))))
+
+(defun erc--scrolltobottom-on-post-command-relaxed ()
+  "Set window start or scroll when data was captured on pre-command."
+  (when-let (((eq (selected-window) (get-buffer-window)))
+             (erc--scrolltobottom-window-info)
+             (found (car erc--scrolltobottom-window-info))
+             ((eq (car found) (selected-window))))
+    (if (and (not (memq this-command erc--scrolltobottom-post-force-commands))
+             (= (nth 2 found)
+                (count-screen-lines (window-start) (point-max))))
+        (set-window-start (selected-window) (nth 1 found))
+      (recenter (nth 2 found)))
+    (setq erc--scrolltobottom-window-info nil)))
+
+;; FIXME this is currently of little value because it doesn't restore
+;; the relative position of window point after changing dimensions.
+;; It would be preferable to instead stash the previous ratio of
+;; window line to body height and later recenter proportionally.  But
+;; that may not be worth the added bookkeeping.
+(defun erc--scrolltobottom-away-from-prompt ()
+  "Scroll to bottom unless at prompt."
+  (unless (input-pending-p)
+    (erc--scrolltobottom-confirm)))
+
+(defun erc--scrolltobottom-all (&rest _)
+  "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
+      (when-let
+          ((erc--scrolltobottom-window-info)
+           (found (assq window erc--scrolltobottom-window-info))
+           ((not (erc--scrolltobottom-confirm (nth 2 found)))))
+        (setf (window-start window) (cadr found)))))
+  ;; Necessary unless we're sure `erc--scrolltobottom-on-pre-insert'
+  ;; always runs between calls to this function.
+  (setq erc--scrolltobottom-window-info nil))
+
 (defun erc-add-scroll-to-bottom ()
-  "A hook function for `erc-mode-hook' to recenter output at bottom of window.
+  "Arrange for scrolling to bottom on window configuration changes.
+Undo that arrangement when disabling `erc-scrolltobottom-mode'.
 
 If you find that ERC hangs when using this function, try customizing
 the value of `erc-input-line-position'.
 
-This works whenever scrolling happens, so it's added to
-`window-scroll-functions' rather than `erc-insert-post-hook'."
-  (add-hook 'post-command-hook #'erc-scroll-to-bottom nil t))
+Note that the prior suggestion comes from a time when this
+function used `window-scroll-functions', which was replaced by
+`post-command-hook' in ERC 5.3."
+  (if erc-scrolltobottom-mode
+      (progn
+        (add-hook 'window-configuration-change-hook
+                  #'erc--scrolltobottom-away-from-prompt nil t)
+        (if erc-scrolltobottom-relaxed
+            (progn
+              (when (or (bound-and-true-p erc-move-to-prompt-mode)
+                        (memq 'move-to-prompt erc-modules))
+                (cl-pushnew 'self-insert-command
+                            erc--scrolltobottom-relaxed-commands))
+              (add-hook 'post-command-hook
+                        #'erc--scrolltobottom-on-post-command-relaxed 60 t)
+              (add-hook 'pre-command-hook ; preempt `move-to-prompt'
+                        #'erc--scrolltobottom-on-pre-command-relaxed 60 t))
+          (add-hook 'pre-command-hook
+                    #'erc--scrolltobottom-on-pre-command 60 t)
+          (add-hook 'post-command-hook
+                    #'erc--scrolltobottom-on-post-command 60 t)))
+    (remove-hook 'window-configuration-change-hook
+                 #'erc--scrolltobottom-away-from-prompt t)
+    (remove-hook 'pre-command-hook
+                 #'erc--scrolltobottom-on-pre-command t)
+    (remove-hook 'post-command-hook
+                 #'erc--scrolltobottom-on-post-command t)
+    (remove-hook 'pre-command-hook
+                 #'erc--scrolltobottom-on-pre-command-relaxed t)
+    (remove-hook 'post-command-hook
+                 #'erc--scrolltobottom-on-post-command-relaxed t)
+    (kill-local-variable 'erc--scrolltobottom-relaxed-commands)
+    (kill-local-variable 'erc--scrolltobottom-window-info)))
+
+(cl-defmethod erc--scrolltobottom-on-pre-insert (_input-or-string)
+  "Remember the `window-start' before inserting a message."
+  (setq erc--scrolltobottom-window-info
+        (mapcar (lambda (w)
+                  (list w
+                        (window-start w)
+                        (and-let*
+                            ((erc-scrolltobottom-relaxed)
+                             (c (count-screen-lines (window-start w)
+                                                    (point-max) nil w)))
+                          (if (= ?\n (char-before (point-max))) (1+ c) c))))
+                (get-buffer-window-list nil nil 'visible))))
+
+(cl-defmethod erc--scrolltobottom-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--scrolltobottom-confirm (&optional scroll-to)
+  "Like `erc-scroll-to-bottom', but use `window-point'.
+Expect to run in some window, not necessarily the user-selected
+one.  Scroll to SCROLL-TO (or 0) lines from the window's top.
+Return non-nil when recentering has occurred."
+  (when erc-insert-marker
+    (let ((resize-mini-windows nil))
+      (save-restriction
+        (widen)
+        (when (>= (window-point) erc-input-marker)
+          (save-excursion
+            (goto-char (point-max))
+            (recenter (+ (or scroll-to 0) (or erc-input-line-position -1)))
+            t))))))
 
 (defun erc-scroll-to-bottom ()
   "Recenter WINDOW so that `point' is on the last line.
 
-This is added to `window-scroll-functions' by `erc-add-scroll-to-bottom'.
-
 You can control which line is recentered to by customizing the
 variable `erc-input-line-position'."
       ;; Temporarily bind resize-mini-windows to nil so that users who have it
@@ -135,7 +326,7 @@ erc-move-to-prompt
 
 (defun erc-move-to-prompt-setup ()
   "Initialize the move-to-prompt module."
-  (add-hook 'pre-command-hook #'erc-move-to-prompt nil t))
+  (add-hook 'pre-command-hook #'erc-move-to-prompt 70 t))
 
 ;;; Keep place in unvisited channels
 ;;;###autoload(autoload 'erc-keep-place-mode "erc-goodies" nil t)
@@ -213,12 +404,15 @@ erc--keep-place-indicator-setup
   (add-hook 'window-configuration-change-hook
             #'erc--keep-place-indicator-on-window-configuration-change nil t)
   (when-let* (((memq erc-keep-place-indicator-style '(t arrow)))
+              (ov-property (if (zerop (fringe-columns 'left))
+                               'after-string
+                             'before-string))
               (display (if (zerop (fringe-columns 'left))
                            `((margin left-margin) ,overlay-arrow-string)
                          '(left-fringe right-triangle
                                        erc-keep-place-indicator-arrow)))
               (bef (propertize " " 'display display)))
-    (overlay-put erc--keep-place-indicator-overlay 'before-string bef))
+    (overlay-put erc--keep-place-indicator-overlay ov-property bef))
   (when (memq erc-keep-place-indicator-style '(t face))
     (overlay-put erc--keep-place-indicator-overlay 'face
                  'erc-keep-place-indicator-line)))
-- 
2.41.0