Things Editors Don't Usually Have: Registers, Narrowing, Markers and Undo Trees.

Emacs offers some features for editing and managing your workspace and workflow that other editors usually do not not have. Some of these features may have similar correspondents in VSCode or the JetBrains editors, some like Vim may offer plugins with similar functionalities, but the following are all built-in to Emacs, and for most of them no extra package is necessary to get the most out of them.

Registers

You can think of registers as keybindings (key combinations) in which you can store almost anything. You can store a string in it, you can store a number, you can store your window or frame configuration and you can store macros in them. Imagine having an extra set of keys on your keyboard, and you can map on each key whatever you want, literally whatever, from a set of actions (macros), to your window configuration or a whole lorem ipsum paragraph (why not?), this is what registers basically allow you to have.

Strings

Let's say for example I am refactoring some code, specifically I have to change some log messages to include a code "ABC321" that will be meaningful to the users. I will also later in the day have to work on a new feature, and that code will have to be added to the log messages. Since my memory is pretty bad and I know I will forget the code or will mix up the characters, I decide to write it down the first time, select the region, and then save it to a register (key): C-x r s and then choose a key, in this example a or even keybinding where I can save it. Now, every time I have to insert that code string, I can just do C-x r i and then a. You can also bind the insert-register command to a more direct keybinding, or even to a single key if your keyboard offers multiple layers. In the end, working with registers provides an extra dimension to your keyboard.

/img/register-string-8.gif

Window configuration

Another pretty cool thing you can store in registers are your window configurations. If you already use project.el and tabs to manage your workspaces, you know that sometimes even that set up can be messed up by switching to different buffers, searching for things in dependencies, etc… So what you can do is use a register as a base camp. For example, today I have to work on a new feature in file awesome.go, after a while I find myself debugging an issue in a dependency package, I have opened at least 3 new buffers, split horizontally and vertically windows, resized them. Finally I find the issue, fix it and just want to go back to awesome.go and the terminal in a window below it and forget about this stroll through hell. Well, if at the beginning, first thing you do before starting to work, is C-x r w you save your window configuration to whatever key you want, and when you have defeated your demon in the depths of dependency madness, you can arise quickly and go back to your cozy configuration by C-x r j and then the register key you selected. The difference here is that this command is jump-to-register instead of insert-register, since a window configuration is something you jump to, and not that you insert.

Register persistence

There are a couple of ways of persisting your registers between sessions, the most immediate are to add one of the following:

(setq savehist-additional-variables
      '(register-alist))
(savehist-mode nil)
(setq desktop-save-mode t)

however there are some caveats:

With savehist you cannot persist window or frame configurations If you try to persist widnow or frame configurations, all registers will be lost. With desktop-save-mode all registers are saved, but window/frame configurations are not deserializable, so they become useless registers, but at least you don't loose your other registers.

While digging around to find out why this is the case, I found this post where it seems there might had been plans on supporting persistence in desktop.el (built-in package) and in session (which I cannot figure out whether it is supported still or not…), there is also psession as external package but it does not support window registers either. Therefore, unless you plan on implementing window register persistence yourself or use an external package, be sure you do not have window registers in your register-alist variable, otherwise all other registers will be lost.

Narrowing

If you are familiar with code folding, for example when you fold function definitions in your file, or class definitions to reduce the amount of visible lines, narrowing does a similar thing but more drastically. You select an area of your file, for example a 10 line function out of a 1000-line file, and narrowing will make the buffer display only that area, as if that was the whole file. The cool things is, you can still perform changes to the narrowed area and save as usual, and you can also manage your changes in git/magit as usual.

/img/narrowing-3.gif

Markers

Markers are like checkpoints in videogames that you can set (or that are automatically set when performing some actions) within and across your buffers. Since you have all these checkpoints, you can imagine it would be nice to be able to directly visit them without having to press arrows or scroll your way around or go find again that buffer where you had set the marker. A very simple example is the following: I am at around line 320, I need to remember what function "printHello" around line 1500 exactly does, so I search for "printHello", find it and then I want to go back to the line I was at before. I could command to go to line 320 because I kind of remember it was around there, but with markers, I can just set a marker before searching and once I am done looking at "printHello", jump back to where I was with C-x C-SPC

/img/marking-3.gif

Undo Tree

Undoing and redoing can be done by any editor. However Emacs can only do undo. The fact is, you do not need redo when you can just undo your undo. Right… That means that Emacs, unlike most editors, does not have separate stacks for undoing changes and redoing changes, if you perform a change and undo it, you can redo it by undoing your undo. You can try that by doing the following:

type: Hello
perform: C-/
perform: C-g
perform: C-/

Congrats, you just did redo! But lets see something more complex:

type: I am
perform: C-g
type: 33

But let's say I got confused, I am actually 32, my birthday is on Nov.26, so let's undo and write 32.

perform: C-/
type: 32

Oops, Nov.26 is actually today, so I am indeed 33! I can undo and retype 33, however in Emacs I can also just undo my 32, and undo my previous undo!

perform: C-/
perform: C-/

Done! I will have my correct age, 33, inserted (btw I am not 33).

This may seem a bit of a headache, but the main advantage is that, if you undo and type something, then undo and type by mistake, you can still recover what you did previously by undoing your undo, while in other editors typing after an undo is basically a death sentence on your chances of redo.

Nice-To-Have's with consult

The package consult (https://github.com/minad/consult), especially if used together with vertico and marginalia, provides useful and organized menus for a lot of Emacs built-ins. Registers and markers are included in the interfaces provided by consult, just use consult-mark or consult-global-mark to browse through your local or global marks across buffers. For registers, consult-register lists all the so-far saved registers organized by type.