Skip to content

discover.el: discover more of Emacs using context menus

by mickey on December 21st, 2013

ISearch context menu

On Discoverability

Over the past three years I have written tens of thousands of words encouraging Emacs users of all skill levels to learn more about Emacs: either adopting work flows I personally find useful, or by covering in great detail a particular feature or package in Emacs.

What’s interesting to me, looking back, is that despite all the detailed manuals that ship with Emacs and the self-documenting nature of Emacs — most of Emacs is just not that discoverable. It takes time and patience. Even if you use a feature often (and I think dired is a perfect example here) there are just so many overlooked nooks and crannies. For instance, did you know that there’s a command called M-x repunctuate-sentences? It puts two spaces at the end of each sentence. Useful, if you believe in that style (your author does not) — but hidden.

I am entirely self-taught in Emacs and never had the requisite “graybeard” to teach me Emacs. It took a concentrated effort to educate myself. You have to read the manual, yes, but that’s often not enough; you have to read the source, experiment with elisp, and then read the source some more. Now, don’t get me wrong: that’s fun and all, but you don’t always have time for that.

Emacs suffers from the classical case of hiding things behind other things. How do you discover stuff about dired? Why you just C-h m to describe the active modes in the buffer, and in there, hopefully, is an unabridged list of relevant key bindings to the mode you’re using. Or maybe you try your luck with the info manual; perhaps you just read the source. Yet… if it’s that “simple”, how come so few people move beyond the basics? Clearly the tools we provide aren’t working well enough. There are few things in Emacs that are truly difficult to grok. The undo ring confuses people until they “get” it; recursive editing might be another; but there’s generally not that many things — it’s just muscle memory, practice, and awareness.

Taking a brief step back. There’s a game out there called Dwarf Fortress (you may have heard of it.) It’s an awesome game: eschewing the modernity of graphics and, ahem, good usability design, for a complex menu-riddled interface and colorful ASCII symbols. Does that ring a bell? Most people try and fail to learn Dwarf Fortress for the same reason people fail to learn Emacs. And they fail because Dwarf Fortress does a poor job aiding discoverability. It’s a very rewarding and deep game that’s oh so close to attracting a much larger audience — much like Emacs.

So I’ve been thinking long and hard about this problem for a considerable while and what I can do to try and improve it, beyond just writing articles. My vision (or call it a moment of clarity) for what Emacs needs to do to improve its discoverability. That’s why I sat down and wrote a proof-of-concept prototype that captures what I think Emacs needs to do to make its myriad commands more accessible and open. I’ve built this prototype on top of the popup system used in Magit.

When I first started using Magit, a Git mode for Emacs, about a year ago I was enthralled by the clean and simple popup windows it used for actions, switches and arguments. I saw opportunities well beyond Magit; indeed, the lead maintainer of Magit, Jonas, is busy unstitching and rewriting it as we speak, having realized that many people find it useful.

Independently of him, I did the same work but rewrote parts of it to handle a different use case: Emacs itself. Instead of constructing command line arguments to git, why not build on the idea but use it for Emacs? So that’s exactly what I’ve done.

I call it discover.el – because that’s what I hope it’ll do; help you discover things.

discover.el

Overview

For now discover.el only supports a couple of key groups and one mode. I’ve decided to tackle dired, as it’s a complex key-based mode; the register keys in C-x r, as they’re hard for people to grasp and remember; and the Isearch keys in M-s, because they are more common. All three cover a cross section of common to uncommon; large to small. The ultimate goal is to blanket Emacs with these context menus. Now, I don’t imagine it as a set of training wheels for beginners but a tool for expert Emacs users as well. I have altered the code I inherited from Magits’ popup system so you can set related lisp variables through the minibuffer and toggle boolean variables through the interface. Doing that without context menus is a major pain in the neck. This system encourages the use of the more esoteric variables and hidden switches, and it’s all done through let-binding — so once the command’s run its course the values will revert to the old settings.

Now, as dired maps most of its commonly used keys to a single character, I have opted to rebind ?, an anaemic and unhelpful “help” system, to the new context menu.

For register & friends, I have opted to replace the key group wholesale. C-x r is now a bound key and will display the context menu when you type it.

For isearch, I also replace the key group. I have decided to take it one step further and expose a lisp variable case-fold-search. Toggle it if searches and matches should ignore case.

So far it works great. In fact, it works really well. There are no immediate disadvantages that I can see. It even works with macros.

It is a bit unpolished (as you’d expect from a prototype), and for now the commands and the descriptions mirror those of the original bindings, so I may end up tweaking the descriptions. Another is the ordering; for now, it’s loosely grouped together, but there’s a lot of scope for improvement. It’s my goal to start adding unbound commands to their respective areas to encourage their use.

So how is it like using it then? I also think it feels very natural. It’s an immense aid for things like dired. Once you get used to having it, it’s as though it’s always been there. The added bonus is, if you’re ever good enough to not need the popups, you can stop using discover.el. But you may not want to. I have several ideas I want to implement, such as:

Save/restore toggles and arguments
By letting you tie save points to various things you do, you can create multiple roles depending on what you need them for. The added benefit is that it shouldn’t be too hard a thing to add.
At-a-glance consoles
Use the context menus to display information in addition to actions, switches and arguments. Why not manage your debugging through a context menu? Make it persist between actions and you can show/hide it whenever you need it. Or why not let you step through, over, or edit each action in an Emacs macro?
Custom context menus for your most-used comands
Use discover to create your own context menus for your own commands
Interact with external command line tools
Like Magit, but for other external commands. Plenty of opportunity to do something really cool.

So it’s a prototype. I need more people to help test it and help with bug fixes and feature additions.

Even if you’re an expert Emacs user I still think there’s a lot of value to be had from using this tool; there’s bound to be features you didn’t know about, and the ability to toggle variable and set variables outright is extremely useful, as the changes you make are let-bound and will only affect the next action you call.

The Future of discover.el

Aside from fulfilling the ideas I mentioned earlier, and fixing outstanding bugs, the biggest task is to migrate existing key groups and mode-specific keys to improve discoverability. The good news is this isn’t too difficult. Most of it can be done with C-h m and a macro; or even better, a bit of elisp magic to generate what we need.

But the big one is people using it. I think this has a real potential to greatly improve the user interaction in Emacs, for beginners and experts alike. Regardless of whether you’re using it or not — tell your coworkers and friends. Tweet about it, too, if you use that. If you’re old fashioned and prefer to use a bugle — that’s fine too.

How do I get it ?

UPDATE: Discover is now available in MELPA!

You can get it from the discover.el github page. For now there are no fancy packages – sorry. I’ll need to get it added to el-get.

The discover.el package also requires makey.el, the bastard child of Magit’s key popup system.

To install it, clone both packages and add them to your load path, then add this to your init file:

And you’re done. Use the isearch or register keys as you normally would. You can access the new dired context menu by pressing ? in dired.

Go forth and discover :)

35 Comments
  1. YoungFrog permalink

    Thanks for this tool. I’ll try it at least for dired because I always feel that I’m very inefficient with it.

    In order to make it work, I had to (load “makey”) explicitly too, and not just (require ‘makey-key-mode). I guess it is so because the file “makey.el” doesn’t match the feature name “makey-key-mode”.

    • mickey permalink

      Thanks. I’ll clean up the packages so it’s easier to use in time – for now I just wanted to throw it out there to see if there’s any interest.

      Thanks for the bug report!

  2. > For instance, did you know that there’s a command called
    > M-x repunctuate-sentences? It puts two spaces at the
    > end of each sentence. Useful, if you believe in that style
    > (your author does not) — but hidden.

    I didn’t believe in that style, until I started using Emacs. In auto-fill-mode, the space immediately following a period is a non-breaking space; for the wrapping to work correctly around the end of sentences, you need the second space.

    • Ivan Andrus permalink

      Only if you have sentence-end-double-space' set to t’ (the default). Personally I like the style since it allows me to distinguish between then end of a sentence and an abbreviation.

  3. You might also want to check this out: https://github.com/kbkbkbkb1/guide-key It’s a pretty similar idea, still a bit rough as well.

    Instead of manually adding “popups”, it generates them automatically from the keymaps—which has the advantge of working for every prefix map in emacs, but the disadvantage of not having specialy tailored switches and options. Combining both of these (somehow) would be really rad.

    • mickey permalink

      Hi Matus,

      Interesting. Nice to see other people have tried to tackle this problem.

      Updating discover to pull keybinds programmatically is on the list, but I think a curated approach is generally better for Emacs’s own stuff — not everything is bound to keys, and organizing the keys so they’re easier to find and read is another bonus.

      Thanks for the link!

      • Mathias Dahl permalink

        I have tried discover.el now and I like the basic idea. I think however that what Matus mentions might be what makes people adopt this, or not. To get traction, authors of popular packages must make them “discoverable” and I think it will be hard to make them do this (I hope I am wrong however.) Also, as Matus says, If it was possible to combine both approaches, we might have something that works well.

        I just typed “%” in plain dired, the first key in some of the regular expression commands. It just sat there, of course, waiting for another key. I know that I can type C-h to see a list of the next keys that are supported for the “%” prefix key, but for a new user it might not be self-evident. It would be cool if Emacs could automatically popup that list, formatted as nicely as in your package, either after a slight delay, or directly.

        • mickey permalink

          I think a compromise is what we need:

          Manually set up most of Emacs to support it – I only added a few to prove the concept works – and optionally toggle a switch to have Emacs automatically do it for external packages.

        • You can do this with guide-key:

  4. Interesting idea, will have to give it a go later.

    A somewhat unrelated question, I like the font you have in your images. What font is it, and what OS are you running on?

    • mickey permalink

      Microsoft’s Consolas font and some version of Ubuntu.

      • Thanks, Mickey. Consolas on OSX doesn’t look this crisp, neither does my current font – Monaco. Oh well…

        • mickey permalink

          I don’t know much about macs, but Windows uses Cleartype to make sure the font looks good — in fact, it looks poor without it. That might be why. I assume Ubuntu uses some sort of sub-pixel rendering as well.

  5. Dan Doherty permalink

    Mickey,

    I love this! I can never remember the rectangle/register stuff and this is a nice unobtrusive way to learn new keys.

    I hope you keep this up, it would be a nice thing to have in emacs core.

    Regards,

  6. Thank you very much for this effort! I’d like to become more efficient with Emacs and will surely try discover.el.

    When I was pair-programming with a colleague and he used my Emacs setup I felt embarrassed by the complexity and non-discoverability of Emacs.

    While discover.el is surely a step in the right direction, I think another step should be consistency. Eclipse has a User Interface Guidelines to enforce consistency between different plugins. I’m not aware of such a styleguide for Emacs. And indeed every mode seems to come with its own philosophy, keybindings and concepts.

    I have seen many good ideas in ergoemacs.org. It might be good to review those for inclusion in Emacs itself.

    Have a nice Christmas!

  7. Mathias Dahl permalink

    By the way, since this is a very interesting idea, have you tried to discuss it on the emacs devel mailing list?

  8. bakhti permalink

    this reminded me of guide-key I’ve learned about from Sacha’s chat with Magnar. The thing with guide-key is that you should already know about some feature and it just helps you to recall the ending of required option.
    Looking forward to discover your discover.el module.
    Thanks you.

  9. Jean-Michel permalink

    I’ve just loaded it through melpa (?) and tested it, and it’s really nice !

    Thks a lot, because I feel, like many others, that I’m very poor at using dired, C-x r … and so on !

    Really a very usefull package.

    Hvave a nice christmas.

  10. Jean-Michel permalink

    BTW a nice next candidate could be Ibuffer, no ?

    • mickey permalink

      Yeah, absolutely. It’s actually quite easy adding new ones yourself – if you want to have a go at it. Crack open discover.el and have a look – it’s very easy.

  11. Xu Ning permalink

    you should mention it’s available at melpa now in the article.

  12. Phil Jackson permalink

    The guy who originally wrote that Magit key menu stuff is probably really popular with the ladies and super cool.

    • mickey permalink

      I’ve heard he brags a bit too ;)

      • Phil Jackson permalink

        He’s by far the most humble person you will ever meet.

  13. Liwp permalink

    Nice work! I’m especially excited about learning to use dired properly.

    Just in case anyone else runs into the same issues I did:

    1. ISearch doesn’t trigger for me, because I have remapped ISearch to C-s. If I use M-s it triggers just fine. Note: paredit-mode remaps M-s to paredit-splice-sexp. I think mickey mentioned that picking up active keybindings programmatically is on the roadmap in one of the comment above.

    2. C-x r doesn’t trigger for me at all. I have no idea why – I haven’t remapped C-x r to anything. Any ideas?

    • mickey permalink

      Yeah Paredit rudely steps all over existing keybinds. Very frustrating.

      If you have a newer version of the library from MELPA you have to enable global-discover-mode first. This won’t fix your paredit-mode problem as they’ll fight over the keybind for M-s.

      It’s a fundamentally hard problem to solve as everyone has a different Emacs configuration. I’ll see if there isn’t a way to let people have their cake and eat it.

    • jbm permalink

      Hi Liwp,

      I came across these issues as well. In my case the conflict with C-x r was caused by a pair of bindings from undo-tree. The following removed the conflict:

      (define-key undo-tree-map (kbd “C-x r”) nil)

      Of course, there may be a different mode (or modes) affecting you. C-x r C-h will probably point you in the right direction.

      • Thanks for the undo-tree-map finding. Your snipped fixed my problem.

        • This “fix” doesn’t make sense to me. C-x r is a prefix key, i.e. you have to hit an additional key after C-x r in order to invoke a command (e.g. C-x r j to jump-to-register).

          Undo-tree doesn’t bind C-x r to anything. It does bind C-x r u and C-x r U. But this doesn’t clobber the C-x r binding in any way, it just adds a new binding that starts with the C-x r prefix. All the other register-related bindings that start with the C-x r prefix continue to work as before. (Tested extensively – I use undo-tree-mode and registers all the time!)

  14. Ivan Andrus permalink

    My own personal take on discoverability (and having some fun), is https://bitbucket.org/gvol/emacs-achievements (available from MELPA). It gives you achievements for using commands. I think it’s kind of fun, but I see two main problems with it.

    1. It requires every achievement to be written by hand (hence adding new achievements takes a lot of time which I don’t have (who does?)).
    2. It doesn’t guide you to actually finding the commands.

    I’m going to try discover.el and see if it’s possible for me to leverage discover.el (or vice versa).

  15. jbm permalink

    Mickey,

    Thanks for this – I think it’s a great idea.

    I’m so used to having paredit-splice-sexp (or sp-splice-sexp in non-Lisp modes) on M-s that I didn’t even really know I was shadowing something useful. However, it’s so ingrained in my muscle memory now that I might prefer moving the isearch map over it.

    Is there a good way to have discover do exactly what it would have done for M-s but on another key?

    • jbm permalink

      Never mind, I think I figured it out:

      (discover-add-context-menu
      :context-menu (assq ‘isearch discover-context-menus)
      :mode nil
      :mode-hook nil
      :bind “C-c s”)

      I didn’t think it had worked but I just needed to eval (global-discover-mode) again.

    • mickey permalink

      I’ll have to come up with a better way of making these things changeable.

      The problem as always is that there is an infinite number of changes that people make to their emacs that it’s almost impossible for me to account for all of them.

      I’ll have to chew on this and see what I can think of.

      RE discovering other binds on the same key: aside from maybe crawling the various mode maps of enabled minor modes, the major mode and the global map — I don’t think so.

  16. Samuel permalink

    Hey there,

    really like discover. It’s a great addon to my workflow.

    I would like to take it a step further and develop custom menus.

    You have said above, that this is generally possible.

    My knowledge of lisp is just to poor to do that, so I might need some explanation here.

    From what I see in the source, as far as I do understand it, all context menus are set up in discover-context-menus

    I would probably be able to come up with writing my own one, for just having a bunch of Commands, I want to envoke when opening that menu.

    Probably would look like this:

    (defconst my-discover-context-menus
    ‘(
    (my-custom
    (description “My custom commands”)
    (actions
    (“Some Start”
    (“D” “Insert Date” insert-date))))))

    I tried to then just set up some global menu, as described in the documentation of discover-add-context-menu

    Looked like this:

    (discover-add-context-menu
    :context-menu (my-custom)
    :bind \”C-c i\”)

    This unfortunately is not working and complains with error “void-function my-custom”

    As I said, my lisp is pretty limited, so I do not understand what went wrong here.

    Perhaps you can provide some help on how to set this up.

    Custom context menu imo provide a great way of having additional commands on relatively easy to reach keybindings, that do not get in the way. So I would be happy if I could make this work.

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS