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.
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.
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
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.