emacselisp

Select the previously-selected window in emacs


I need an emacs built-in function or elisp function that can take me to the previously-selected window. I thought that (select-window (get-lru-window)) would do it, but if I run it several times, seems to just cycle between windows instead of swapping back and forth between them, which is what I expect.

Any other ideas?


Solution

  • There doesn't seem to be a way to get the most recently selected window in emacs (as opposed to the least recently used returned by get-lru-window). Internally emacs tracks use_time on windows, and get-lru-window uses that to find the "oldest" window. But unfortunately that is not exposed in elisp.

    The window list is ordered in cyclic window ordering which doesn't help in your case.

    The buffer-list is however ordered most-to-least recently used buffer (or not really strictly, there is a (bury-buffer) function to move a buffer last).

    This means that, if you can transform your problem into something like "how can I switch to the buffer in a different window that was most recently the selected buffer", it should be possible.

    One way would be to do something like this:

    (defun switch-to-previous-buffer-in-a-different-window ()
      (interactive)
      (let* ((otherbuf (other-buffer (current-buffer) t))
         (otherwin (get-buffer-window otherbuf)))
    (if otherwin
        (select-window otherwin)
      (message "Last buffer (%s) is not currently visible" (buffer-name otherbuf)))))
    

    Or the shorter, and more featureful:

    (defun switch-to-previous-buffer-possibly-creating-new-window ()
      (interactive)
      (pop-to-buffer (other-buffer (current-buffer) t)))
    

    Here other-buffer is used to get the most recently used buffer (except current-buffer). This should work fine as long as you don't switch buffers in the windows, because then other-buffer will no longer return the buffer in the other window, but the buffer you switched from in current window.

    So instead of using other-buffer lets walk the buffer-list ourself to find the best candidate:

    (defun switch-to-the-window-that-displays-the-most-recently-selected-buffer ()
      (interactive)
      (let* ((buflist (buffer-list (selected-frame)))      ; get buffer list in this frames ordered
         (buflist (delq (current-buffer) buflist))     ; if there are multiple windows showing same buffer.
         (winlist (mapcar 'get-buffer-window buflist)) ; buf->win
         (winlist (delq nil winlist))                  ; remove non displayed windows
         (winlist (delq (selected-window) winlist)))   ; remove current-window
    (if winlist
        (select-window (car winlist))
      (message "Couldn't find a suitable window to switch to"))))
    

    Hope this helps.