I'm trying to make Workgroups2 more convenient by displaying a list of workgroups in the mini-buffer on pressing the prefix key (C-c z), e.g.:

List of workgroups

This makes it convenient to use the index 0-9 to switch workgroups:

(defvar wg-prefixed-map

   ;; workgroup switching
   (kbd "C-j")        'wg-switch-to-workgroup-at-index
   (kbd "j")          'wg-switch-to-workgroup-at-index
   (kbd "0")          'wg-switch-to-workgroup-at-index-0
   (kbd "1")          'wg-switch-to-workgroup-at-index-1
   (kbd "2")          'wg-switch-to-workgroup-at-index-2
   (kbd "3")          'wg-switch-to-workgroup-at-index-3
   (kbd "4")          'wg-switch-to-workgroup-at-index-4
   (kbd "5")          'wg-switch-to-workgroup-at-index-5
   (kbd "6")          'wg-switch-to-workgroup-at-index-6
   (kbd "7")          'wg-switch-to-workgroup-at-index-7
   (kbd "8")          'wg-switch-to-workgroup-at-index-8
   (kbd "9")          'wg-switch-to-workgroup-at-index-9
"The keymap that sits on `wg-prefix-key'.")

(defun wg-fill-keymap (keymap &rest binds)
  "Return KEYMAP after defining in it all keybindings in BINDS."
  (while binds
    (define-key keymap (car binds) (cadr binds))
    (setq binds (cddr binds)))

The list can be generated with:


Given C-c z as the prefix key for Workgroups2, is it possible to bind it to


so that it displays the list of workgroups in the mini-buffer? C-c z should still be the prefix after the binding.

This question is similar to Can the prefix of a key-sequence have an effect?. The comments suggest set-transient-map or keymapp. If either of these is useful, please kindly show how the above code can be modified to implement the function. Thank you.

  • The question is unclear to me. If you use (define-prefix-command 'wg-prefixed-map) and then you do (define-key MAP (kbd "C-c z") 'wg-prefixed-map) for each minibuffer keymap MAP that you are interested in, then you get your prefix-key behavior in the minibuffer. How that relates to another use of C-c z as the prefix key for "Workgroups2", or how or why you want to bind that same key to (wg-fontified-message (wg-workgroup-list-display)), which would have to return a command or keymap, is unclear. – Drew Mar 29 '16 at 20:34
  • @Drew C-c z is the default prefix key for Workgroups2. When I C-c z, I use j, 0, 1, etc, to execute a command. Now I want C-c z to show a list of workgroups in the mini-buffer using wg-fontified-message while waiting to accept the next key. – Yang Mar 29 '16 at 20:43
  • Still unclear to me, but it sounds like you want to advise each of the commands bound to j, 0, etc., to have them first display what you want to display. – Drew Mar 29 '16 at 21:00
  • @Drew Before I press 0, 1, etc, and after I press the prefix key C-c z, I would like a list of workgroups (e.g., 0: Default 1: Test 1 2:Test 2 as shown in the image) displayed in the mini-buffer. – Yang Mar 29 '16 at 21:18
  • Then bind C-c z to a single command that reads a key (e.g. 0 etc.) and dispatches to a function that does what 0 etc. does today. And reread the question you cited: Can the prefix of a key-sequence have an effect?. A key sequence is bound to a command or to a keymap, or it is unbound. A command can read keys. A keymap performs no actions. – Drew Mar 29 '16 at 21:40

One way to do it is, instead of binding C-c z to a prefix key, bind it to a command that displays what you want and then calls set-transient-map to read a key sequence and interpret it in another map. Any key that isn't bound in the other map will be interpreted in the global map, so rather than wg-prefixed-map, you should provide a keymap where unknown bindings are made undefined.

(defun wg-prefix-show-information ()
  "Display information and read a key from \\[wg-filled-map].

  (message …)
  (set-transient-map `(keymap (t . undefined) ,@wg-filled-map)))

This isn't ideal because it doesn't integrate well with help. For example C-h C-c z will say that wg-prefix-show-information is that function above, hence the prominent mention of wg-filled-map in the function's docstring. Also C-c z C-h will not propose a list of bindings (I think this can be fixed by setting help-form but I haven't investigated further). If the user types a multi-key sequence slowly, they'll be shown the keys they typed not including the initial C-c z which might be confusing.

If all you need to do is display something in the echo area, an alternative approach would be to leverage the prompt string of a keymap. This can only be a constant string, but if it only needs to be regenerated due to a few events as opposed to recomputed on the fly, you can make those events change the keymap object:

(defvar wg-filled-map
    (let ((map (make-sparse-key-map "nothing going on")))
(defun wg-something-changed-hook ()
  (setcdr wg-filled-map (format "the system state is …")))

If you want some fancier processing, an alternative approach is to switch to the minibuffer or to a new, transient buffer where wg-prefix-map is the local map. This is what isearch does, for example (with a much more complex use case as one typically enters many keys, not just one). Another package that uses this kind of approach is magit.

| improve this answer | |
  • Thanks, Gilles. I have taken your first approach. I think even using wg-prefixed-map works for me. If a key isn't bound, it says x is undefined, so that's fine. – Yang Mar 30 '16 at 1:45
  • I recommend against the use of (t . undefined) in your transient map. As a matter of fact, set-transient-map was introduced in large part to try and reduce the use of such "catch all" bindings because they have undesirable side-effects (the most obvious one is that they prevent function-key-map and input-decode-map from doing their job). – Stefan Apr 12 '16 at 13:13

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