Skip to content

discover.el: discover more of Emacs using context menus

Dec 21 13
by mickey

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 :)

An introduction to Magit, an Emacs mode for Git

Dec 6 13
by mickey

If you’re lucky (or unlucky, depending on your viewpoint) enough to be using Git as part of your workflow, you may have come across Magit, an Emacs interface to Git. Magit’s an excellent interface to Git, but it does assume you know exactly what you’re doing with Magit and, ultimately, Git.

Magit has a fine Info manual that covers all the many actions Magit supports, but like a lot of manuals it doesn’t help with workflow; it assumes you’re already familiar with Magit and that you know exactly what to do and how to go about doing it.

Magit is also under active development. It pays to be on the cutting edge because as of Dec 2013 there is a forthcoming release that adds a lot of cool new stuff to Magit that makes it even better. Therefore, this tutorial will assume you’re using the bleeding edge.

To install the master branch version of Git, I suggest you use Melpa. Alternatively you can pull the latest from their github repository and follow their (simple) build instructions.

Here’s the first part of my tutorial on Magit. It will cover the status window; staging and unstaging items; committing changes; and the history view.

Getting Started

First and foremost: Magit does not hide the complexities of Git; in fact, you most certainly need to know exactly what Git is doing in order to truly use Magit effectively. I like to think of Magit as a tool that removes the tedium of interacting with Git’s rather poor commandline interface. It does this very, very well.

To use Magit, run M-x magit-status. This command will open up a window (or prompt you for a Git repository if the buffer’s file directory is not under Git control) and display Magit’s status screen. It is through this interface that you will use Magit. If you’re a user of Emacs VC then you must know that, frustratingly, Magit makes no effort to integrate itself into Emacs’s VC (Version Control) abstraction layer. Say what you want about VC, but it works across a wide range of source control systems and provides a unified interface to all of them. To use Magit you must do it through M-x magit-status.

The Magit Status

An example of Magit's status window

The first thing you’ll notice about the Magit status window is that it plays nice with your window configuration when you open it, and when you close it with q. Almost all the actions you can carry out in Magit is done through a one-key system that opens up a “command console” window at the bottom, letting you further refine your command before you carry it out. This is a fantastically well-done interface and is probably the killer feature that makes Magit so great. I like it so much that I have copied the underlying interface code for use in some of my own Emacs hackery. It’s really, really nice.

The status window will give you an overview of your repository, including: staged/unstaged changes; unpulled/unpushed commits; stashes; and a header containing: local and optional remote, the latest tag, if any; and HEAD.

The older, stable version does little to aid discoverability, but in the bleeding edge you can type ? to get an annotated list of actions. I found it really difficult to use Magit in the beginning because I had to stumble my way through random menus until I found the thing I was looking for. The annotated list is, however, not complete. There are some commands (important ones, depending on your git workflow) missing from the list — particularly E, for interactive rebase.

Staging and Unstaging Items

Putting stuff into Git is something you’ll do often, and Magit has a selection of keybindings and tools to help you make that easier. The key take away is that you can stage “items” — not just the whole file, but the hunks in a diff, for selective staging. The killer feature here is how it displays this information, using its “levels” system. Magit lets you expand and collapse staged and unstaged files with TAB. For more granular control, you can use M-1 through to M-4 for all the files; and 1 to 4 for the selected one.

Magit showing diff hunks

Level 1 hides everything in a category (say, “staged” files); Level 2 expands to show just the filenames in a category (this is the default); Level 3 will show the git hunk headers; and Level 4 will show all the diff hunks. I use Levels 2 and 4 the most, but if you’re using TAB Magit will pretty much “do what you want.”

You have a range of keybinds available to make your life easier. n and p will move between the next and previous section (such as a hunk); M-n and M-p move between sibling sections, such as between each file in level 4, or between each section (like staged or unstaged). You can use + and - to enlarge or shrink each hunk and 0 to reset to the default. You can also type H to refine the hunk for additional diff highlighting. Pressing RET will go to the file where the change is made. It works on both hunks and files.

To stage or unstage you can type s or u to stage/unstage the item (be it a whole file, or just a hunk) — however, there’s one more very useful tip. If you use the region to select a portion of a hunk and then press stage/unstage then Magit will automatically stage or unstage just that selected region! That’s extremely useful for fine-grained control when a diff hunk itself is not good enough.

Finally, sometimes you’ve made changes you don’t care to ever commit; like staging and unstaging above, you can discard hunks and files (revert to HEAD) and delete untracked files from your filesystem. To do this, press k. This command works for more than just staging/unstaging — for instance, you can also remove a stash with it.

Committing Changes

To open up the commit menu, type c. You’ll be given a laundry list of switches, most of which you probably won’t need to use very often. What is useful are the actions. You can do much more than merely commit (c) staged changes:

  • You can extend (e) the current commit HEAD is pointing to
  • You can amend (a) the commit message
  • You can reword (r) it, if you don’t like the commit message
  • and you can both fixup (f) and squash (s) against the current commit. If you have previously markewd a commit with . this commit will be used instead.

Extending a commit basically envelops the changes you’re trying to stage into the current commit HEAD. So if you forgot to commit some stuff that belongs to the commit you just did — use extend. If you want to amend the commit message as well, use amend.

Rewording it will do so without committing your staged changes. Use this if you fat-fingered a commit message and you want to change it.

If you want to create a “fixup!” or “squash!” commit against the latest commit you have made — for later use with rebase and --autosquash — use the fixup or squash commands. If you’re not into rewriting your git history, and if you never use rebase, then these two commands are probably not very useful to you.

Logging

Magit's History screen
I think one of the areas where Magit really shines is its multitude of switches to filter, sort and search your git history. Not only does it display this information, but it lets you act on it interactively. To access the log menu, type l.

The first handy shortcut you should know is l l. That opens the “short log”. In it, you will see a one-line commit message; the name of author; how long ago the commit happened; the tree structure of the git log; and various labels, like where HEAD is and where the branch markers are.

If you ever screw up, git reflog is there to save the day, and Magit does a stellar job overlaying a nice UI on top of the reflog mechanism (l h.)

Both the reflog and the normal log has a wealth of useful keybinds.

There are many things you can do with an individual commit in the log:

  • . will mark the commit for use with commands like commit fixup and commit squash (c f and c s)
  • x will reset your head to the selected commit
  • v will revert the commit
  • d will diff between the selected commit and your working tree
  • a will apply the selected commit's changes to to your working tree
  • A will cherry pick the commit on top of your working tree
  • E will interactively rebase from HEAD to the selected commit. Very useful if you want to rewrite history
  • C-w will copy the commit hash to the kill ring
  • SPC will show the full commit message

A note on marking: the mark command will persist even if you close the log window. It's a powerful tool but it's easy to forget you've marked something.

If you navigate up/down the log with M-n and M-p magit will automatically show the commit in a separate window.

Conclusion

Magit's a great tool for experienced Git users. If you're new to Git, then Magit may help you make sense of how Git works, but it'll never teach you Git. The only thing that impedes Magit, in my opinion, is the lack of discoverability; despite exposing a million different Git arguments, switches and toggles, it ironically does not teach you how to find and use itself. I found it quite hard to replace the Git commandline (not because I like it -- I actually think it's awful) but because the commands and actions I wanted to do were quite well-hidden. The cutting edge version is much better, with ? actually giving you an annotated list of (some, but still not all) the different key menus. But it's a big improvement. If you're on the fence about Magit, or if you've tried and failed to adopt it, I suggest you give it another go. I plan on covering more of Magit in future posts.

Smart Scan: Jump between symbols in a buffer

Oct 31 13
by mickey

A few years ago I wrote Effective Editing I: Movement and in that article I included a bunch of code for a feature I called “Smart Scan.” Back then I didn’t bother putting it on Github so I just left it as source code embedded in the article. I’ve now realized that hundreds have stuck it in their .emacs file but without the benefit of any potential updates, and with no way to actually contribute to the package.

Basically, Smart Scan let’s you jump between symbols in your current buffer that matches the one point is on. It does it unintrusively and without any prompts or other fancy UI gimmicks. Simply put your point on a symbol you want to search for in your buffer and type either M-n or M-p to move forward or backward respectively. Give it a shot. I have moved it Github here. Patches welcome :) Enjoy!