8

Scenario: I have several (more than 2) windows open. I actively work with two of them. How do I best jump from one window to another, and back, with one command?

I use ace-window; it's great but I don't want to press window number every time. I know about next-window / prev-window, but these are two different commands.

What I'm looking for is something that remembers what the previous windows was when I select another window, and gets back to it. Invoked repeatedly, it would switch between the last two windows, Alt-Tab-style.

Where do I look?

9000
  • 537
  • 2
  • 16
  • I use fn plus one of the arrow keys to go in any direction, including in and out of the minibuffer (if it is active) -- see the built-in library windmove. – lawlist Jan 11 '17 at 20:11
  • @lawlist: I know about windmove. What I'm looking for is a way not to think about the direction required, especially if the windows have a few other windows between them. – 9000 Jan 11 '17 at 20:20

3 Answers3

6

If you are already using ace-window, then you can use the command aw-flip-window to flip back and forth between two windows. By default this is bound to n in the ace-window aw-dispatch-alist.

That means that you can invoke ace-window and hit n instead of a window number to flip back to the previous window. You could also bind aw-flip-window to some other key.

Note that this will only flip back to a window that was previously selected by ace-window. If you often switch windows with other commands you may want a more general solution.

glucas
  • 20,563
  • 1
  • 54
  • 84
6

One way to write your own command is to use the built in get-mru-window function.

For example:

(defun my-flip-window ()
  (interactive)
  (let ((win  (get-mru-window nil nil t)))
    (when win (select-window win))))

This looks for the most-recently-used window in the current frame that is not the currently selected window.

Here is a variation that works across visible frames:

(defun my-flip-window ()
  (interactive)
  (let ((win  (get-mru-window 'visible nil t)))
    (when win
      (select-frame-set-input-focus (window-frame win))
      (select-window win))))

As mentioned in the comments, here's a variation that works when there's only one window (switching to the most recent buffer):

(defun flip-window ()
  (interactive)
  (let ((win  (get-mru-window 'visible t t)))
    (if win
        (progn
          (select-frame-set-input-focus (window-frame win))
          (select-window win))
      (mode-line-other-buffer))))
glucas
  • 20,563
  • 1
  • 54
  • 84
  • 1
    Nailed it! This one is much better than the one I put together. Nice find on get-mru-window. – Dan Jan 11 '17 at 20:41
  • 1
    I ended up adding this to my config with an additional variation: when there is only one frame/window (get-mru-window returns nil), then call mode-line-other-buffer. That way I have one key that flips back and forth between two buffers in any window configuration. – glucas Jan 12 '17 at 18:29
  • Great. I love that last variation @glucas. Thank you. Here is how I wrote it and it works. Is that the best way to do it? (defun my-switch-to-previous-window () (interactive) (let ((win (get-mru-window nil nil t))) (if win (select-window win) (mode-line-other-buffer)))) – prosoitos May 06 '19 at 19:53
4

Here's a simple command, lightly tested, that will switch you to the most recently visited window:

(defvar recent-window nil
  "The most recently visited window.")

(defun switch-to-recent-window ()
  "Switch to the most recently visited window, as stored in
`recent-window'."
  (interactive)
  (let ((current (car (window-list))))
    (if recent-window
        (select-window recent-window)
      (message (concat "No recent window selected, "
                       "so I'm setting this window "
                       "as the most recent.")))
    (setq recent-window current)))
Dan
  • 32,980
  • 7
  • 102
  • 169
  • Thank you! It works. Do you mind if I make a package out of it, with attribution? – 9000 Jan 11 '17 at 20:23
  • You're welcome. Sure, feel free to use it in a package, but be aware that the code in not (yet) very intelligent. If you switch to other windows with commands such as next-window or other-window, the change won't get picked up in the recent-window variable. There's no obvious hook to use, so fixing this part may involve defining advice for a whole bunch of other functions. – Dan Jan 11 '17 at 20:26
  • 1
    I think you could use buffer-list-update-hook, which is called when the active window changes (after select-window). That hook is called in other cases but could be used to keep track of the last window. – glucas Jan 11 '17 at 20:32