7

Thanks to @itsjeyd, I've come to love ace-window, but now I want more.

I use C-x 4 f and C-x 4 b to invoke the commands ido-find-file-other-window and ido-switch-buffer-other-window, but I want to pick the window to be used. That is, I want to use ido to pick the file or buffer name and (probably) something like ace-window to select the window to be used.

Today, I have to:

  1. Invoke ace-window to select the window I want to change.
  2. Invoke ido-find-file or ido-switch-to-buffer.
  3. Invoke ace-window to go back to the original window.

Is there a better way? If not, I will likely try to write something to do what I want and put it on github.

1 Answer 1

5

How about this:

(defun ace-command-other-window (cmd &optional one-win-cmd)
  "Execute CMD in another window.
If provided, call ONE-WIN-CMD instead when there is only one window."
  (interactive "CM-x (other window) ")
  (catch 'done
    (when (and one-win-cmd
               (not (window-parent)))
      (call-interactively one-win-cmd)
      (throw 'done t))
    (let ((start-window (selected-window)))
      (unwind-protect
           (progn
             (aw-switch-to-window
              (aw-select  " Ace - Command "))
             (call-interactively cmd))
        (aw-switch-to-window start-window)))))

(defun ace-find-file ()
  "Find a file in another window."
  (interactive)
  (ace-command-other-window #'ido-find-file
                            #'ido-find-file-other-window))

(defun ace-switch-buffer ()
  "Switch buffers in another window."
  (interactive)
  (ace-command-other-window #'ido-switch-buffer
                            #'ido-switch-buffer-other-window))

When you have only one window, these call the normal ido commands to split the window and switch to the specified file or buffer. If you have two windows, they will switch file/buffer in the other window but keep the current window active. With three or more windows, you'll be prompted to choose a target window using ace.

Suggested bindings: C-x 4 M-x for ace-command-other-window, and then rebind C-x 4 f and C-x 4 b for the other two.

Update

My original approach was to use ace to switch to an arbitrary window and then call the desired command. This doesn't behave as you might expect. For example, if you call ace-find-file you end up starting in the default directory of the target window rather than the currently active one.

Here is an alternative implementation that flips things around to choose the target file/buffer first, then displays it in an ace-selected window.

(defun ace-switch-buffer ()
  "Switch to another buffer in another window."
  (interactive)
  (if (not (window-parent))
      (ido-switch-buffer-other-window)
      (let ((start-win (selected-window))
            (buf (ido-read-buffer "Buffer: "))
            (win (aw-select " Ace Buffer: ")))
        (unwind-protect
             (progn
               (aw-switch-to-window win)
               (switch-to-buffer buf))
          (aw-switch-to-window start-win)))))



(defun ace-find-file ()
  "Find a file and display it in another window."
  (interactive)
  (if (not (window-parent))
      (ido-find-file-other-window)
      (let ((start-win (selected-window))
            (buf (find-file-noselect (ido-read-file-name "File: ")))
            (win (aw-select " Ace File: ")))
        (unwind-protect
             (progn
               (aw-switch-to-window win)
               (switch-to-buffer buf))
          (aw-switch-to-window start-win)))))
8
  • 1
    I love these functions, but I found two problems: 1. They leave you with the wrong window selected if you quit (C-g). 2. They don't work right if you use the global (multi-frame) ace-window option to pick a window in a different frame. My fix is to add unwind-protect around the select-window and ido-find-file and to use select-frame-set-input-focus if (not (eq (window-frame start-window) (window-frame new-win)). Commented Feb 20, 2015 at 20:52
  • I re-select the original frame as a "cleanup" of the unwind-protect and moved the (aw-switch-to-window start-window) to a cleanup too. Commented Feb 20, 2015 at 20:59
  • Nice, I only tested with one frame. Note that aw-switch-to-window is already calling select-frame-set-input-focus, so you may not need that part.
    – glucas
    Commented Feb 20, 2015 at 21:12
  • The problem I fixed---probably inelegantly---was: if focus was in frame A and aw-select picked a window in frame B, ido would try to use frame B's minibuffer, but keyboard input went into frame A's selected window. A better solution---which I didn't work out---would be to use frame A's minibuffer for ido regardless. My versions of the functions are here. Commented Feb 20, 2015 at 21:20
  • 1
    Just for grins, here's the variation I'm using now: gist.github.com/glucas/09aea018251cf85c7290 With this you can also call ace-command-other-window to interactively run an arbitrary command in another window.
    – glucas
    Commented Feb 21, 2015 at 19:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.