ace-window display mode12 Mar 2015
Why not show the
ace-windowdispatch keys in the mode line all the time?
Certainly, there's no reason not to have this option, and it actually makes the whole interface better, since it becomes less feedback-based:
- You glance at a window that you want.
- You know which key you have to press before you call
- You make a single-step call instead of:
- read the dispatch char,
- press the dispatch char.
The feature is implemented as
ace-window-display-mode - a minor mode that you can toggle on or
off whenever you feel like it.
Here's how it looks like:
As you can see, I've made
aw-keys list short on purpose, just to show you that the full path
will be displayed. See, for instance, the
*scratch* window: its path is
Since the implementation is quite short, I'll post it here and go over a few things that might interest people who write Elisp (on some level, please don't mock me for being obvious).
As per request of a curious reader, I've updated the code with the comments from below. Don't try this at home, excessive commenting is bad style.
;; Something that modifies the Emacs behavior should ;; preferrably be implemented as a minor mode. ;;;###autoload (define-minor-mode ace-window-display-mode "Minor mode for showing the ace window key in the mode line." ;; And since this minor mode isn't tied to a particular ;; buffer, I declare it as global. ;; ;; An interesting quirk is that I have to put *something* ;; between the docstring and the body, otherwise it won't ;; work. :global t ;; Dispatch on the variable symbol of the mode - ;; `ace-window-display-mode`. `define-minor-mode' will ;; define both a variable and function symbol. (if ace-window-display-mode (progn ;; Update the window parameters (aw-update) ;; Since `mode-line-format' is a buffer-local ;; variable, I set it with `set-default', in order ;; for the change to not just happen in the current ;; buffer. (set-default 'mode-line-format `((ace-window-display-mode (:eval (window-parameter (selected-window) 'ace-window-path))) ,@(default-value 'mode-line-format))) (force-mode-line-update t) ;; Each time a window is created or deleted, Emacs ;; will run the `window-configuration-change-hook' - ;; exactly what I need to update `mode-line-format'. (add-hook 'window-configuration-change-hook 'aw-update)) (set-default 'mode-line-format (assq-delete-all 'ace-window-display-mode (default-value 'mode-line-format))) (remove-hook 'window-configuration-change-hook 'aw-update))) (defun aw-update () "Update ace-window-path window parameter for all windows." (avy-traverse (avy-tree (aw-window-list) aw-keys) (lambda (path leaf) ;; Use `set-window-parameter' to store a variable for ;; each window. Buffer local variables would not work ;; here, since one buffer can be displayed in multiple ;; windows, and those would need a different key each. (set-window-parameter leaf 'ace-window-path (propertize (apply #'string (reverse path)) 'face 'aw-mode-line-face)))))
Since I'm writing something that modifies Emacs behavior when it's enabled, I first try to implement it as a minor mode. And since this minor mode isn't tied to a particular buffer, I declare it as global.
An interesting quirk is that I have to put something between the docstring and the body, otherwise
it won't work. In this case, I put
Next, follows that standard dispatch on the variable symbol of the mode -
define-minor-mode macro will make both variable and function definition for the symbol it's
- the variable is used to check if the mode is on.
- the function is used to turn the mode on / off.
Note the use of
assq-delete-all: this is for when some other package modifies the
ace-window does. In that case,
ace-window's entry wouldn't be the first
one any more.
mode-line-format is a buffer-local variable, I set it with
set-default, in order for the
change to not just happen in the current buffer.
Each time a window is created or deleted, Emacs will run the
exactly what I need to update
One final trick is to use
set-window-parameter to store a variable for each window. Buffer local
variables would not work here, since one buffer can be displayed in multiple windows, and those
would need a different key each.
I really like how the
avy-traverse interface ended up as: the same functions are used
for selecting window and setting
I hope that you enjoy the update, and keep those interesting ideas coming!