When I work with a large monitor, I often divide my Emacs frame (what most people call a window) into two or more windows (divisions within a frame). I like this more than dealing with multiple Emacs frames, even if I could spread those frames across multiple monitors. I find it easier to manage the windows using keyboard shortcuts than to manage the tiling and display of frames.
One of the Emacs micro-habits I’m working on is getting better at switching between windows. When there are only two windows,
C-x o (
other-window) works just fine. However, when there are three or more, it can take a few repetitions of
C-x o to get to where I want. I could get around that by binding
M-o instead, replacing the default keymap for that. Or I could try to get the hang of other ways to move around.
Here’s an 8-minute video showing
Windmove lets you move around with cursor keys, if you set up the appropriate keyboard shortcuts. Ace-window works like ace-jump. In addition, you can use C-u to swap windows and C-u C-u to delete windows. Ace-jump works across windows, so that’s handy too.
Here’s my relevant code snippet for Windmove. I changed this to use
define-key instead of
(defvar sacha/windmove-map (make-sparse-keymap)) (define-key sacha/windmove-map "h" 'windmove-left) (define-key sacha/windmove-map "t" 'windmove-up) (define-key sacha/windmove-map "n" 'windmove-down) (define-key sacha/windmove-map "s" 'windmove-right) (define-key sacha/windmove-map "[left]" 'windmove-left) (define-key sacha/windmove-map "[up]" 'windmove-up) (define-key sacha/windmove-map "[down]" 'windmove-down) (define-key sacha/windmove-map "[right]" 'windmove-right) (key-chord-define-global "yy" sacha/windmove-map)
Here’s the cheat sheet I made for myself:
And here’s a simpler reference that you can personalize with your own shortcuts:
Naturally, after recording the video, I thought of a better way to manage my windows. I took advantage of the
def-repeat-command that abo-abo posted on (or emacs so that I could repeat keybindings easily. I modified the function to accept
nil as the first value if you don’t want the keymap to run a command by default, and to use
kbd for the keybinding definitions.
(defun sacha/def-rep-command (alist) "Return a lambda that calls the first function of ALIST. It sets the transient map to all functions of ALIST, allowing you to repeat those functions as needed." (lexical-let ((keymap (make-sparse-keymap)) (func (cdar alist))) (mapc (lambda (x) (when x (define-key keymap (kbd (car x)) (cdr x)))) alist) (lambda (arg) (interactive "p") (when func (funcall func arg)) (set-transient-map keymap t))))
Here’s my new binding for
yy. It lets me bounce on
y to use
other-window as normal, use the arrow keys to move between windows thanks to
windmove, and use
ace-window as well:
h is the regular ace-window,
s swaps, and
(key-chord-define-global "yy" (sacha/def-rep-command '(nil ("<left>" . windmove-left) ("<right>" . windmove-right) ("<down>" . windmove-down) ("<up>" . windmove-up) ("y" . other-window) ("h" . ace-window) ("s" . (lambda () (interactive) (ace-window 4))) ("d" . (lambda () (interactive) (ace-window 16))) )))