Re: Position buffer contents at bottom of window
Joost Kremers <[email protected]> Wed, 24 Jun 2026 15:26:14 +0200
| Newsgroups | gmane.emacs.help |
|---|---|
| Message-ID | <[email protected]> |
On Wed, Jun 24 2026, Stéphane Marks wrote: > On Wed, Jun 24, 2026 at 6:53 AM Joost Kremers <[email protected]> > wrote: > >> Hi list, >> >> I've been trying to create a function that fills a buffer and then >> positions the last line of the buffer at the bottom of the window. >> >> Doing this manually works just fine: >> >> ``` >> (defun my--recenter-window-to-bottom (&optional window) >> "Align contents of BUFFER to the bottom of WINDOW." >> (interactive (list (selected-window))) >> (when (window-live-p window) >> (with-current-buffer (window-buffer window) >> (when-let* ((_ (>= (window-end window t) (point-max))) >> (edges (window-body-pixel-edges window)) >> (window-top (nth 1 edges)) >> (window-bottom (nth 3 edges)) >> (text-height (cdr (window-text-pixel-size window >> (window-start window)))) >> (dy (- window-bottom window-top text-height))) >> (message "↑%d ↓%d ↕%d dy%d" window-top window-bottom text-height >> dy) >> (pixel-scroll-precision-scroll-up dy))))) >> ``` >> >> I can bind this to a key and then calling this function does exactly what I >> want it to do. >> >> The problem is that it does not seem to work from Lisp, at least not in the >> context I'm using it. Specifically, I have a function in the buffer-local >> value of `window-buffer-change-functions` that basically erases the buffer >> and fills it with content. At the end, it calls `(goto-char (point-max))` >> and then sets a timer for 0 seconds to run the function above. >> >> I'm using the timer because the buffer-fill functions is called from >> `window-buffer-change-functions` which, AFAIU, is called during redisplay, >> so I was hoping the timer would ensure that redisplay is done before >> `my--recenter-window-to-bottom` is called. >> >> Things, however, just don't work... The numbers reported in the `message` >> call are different than when I call the function interactively, and the >> window is scrolled incorrectly, or not at all. >> >> I'm probably doing something very wrong here, but I'm unsure what. If >> anyone can cast an eye and point me in the right direction, I'd be >> grateful. > > > Have you ensured that the window is the correct one? You didn't share the > timer code, so it is possible that you could be passing in the correct > window at that point rather than the function being triggered by the timer > when the selected window isn't the one you want. This is the gist of the function that fills the buffer: ``` (defun my-update-buffer (&optional window) (setq window (or window (selected-window))) (when (window-live-p window) ;; This function is called from `window-buffer-change-functions', which ;; may run with the old buffer current, so use WINDOW to get the right ;; buffer. (with-current-buffer (window-buffer window) [Fill buffer with content] (set-window-point window (point-max))) ;; `window-buffer-change-functions' is run during redisplay, so defer ;; viewport adjustment until the window state has settled. (run-at-time 0 nil #'chat--recenter-window-to-bottom window))) ``` So the timer is the last call in this function. `window` is the window argument passed from `window-buffer-change-functions`. (Note, BTW, that this is with Emacs 30. I know in Emacs 31 `window-buffer-change-functions` is treated a bit differently.) -- Joost Kremers Life has its moments