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)))))
quit
(C-g
).ace-window
option to pick a window in a different frame.My fix is to add
– Colin Fraizer Feb 20 '15 at 20:52unwind-protect
around theselect-window
andido-find-file
and to useselect-frame-set-input-focus
if(not (eq (window-frame start-window) (window-frame new-win))
.unwind-protect
and moved the(aw-switch-to-window start-window)
to a cleanup too. – Colin Fraizer Feb 20 '15 at 20:59aw-switch-to-window
is already callingselect-frame-set-input-focus
, so you may not need that part. – glucas Feb 20 '15 at 21:12aw-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. – Colin Fraizer Feb 20 '15 at 21:20aw-switch-to-window
it will also switch frames, so in my latest update I use that everywhere. – glucas Feb 20 '15 at 21:24ace-command-other-window
to interactively run an arbitrary command in another window. – glucas Feb 21 '15 at 19:38