From Lunar Phases to Yank-Pop

By Susam Pal on 02 Apr 2023

Tiny Book Club

We have a tiny book club that meets every weekend to read and discuss the book Mastering Emacs, 2022 edition written by Mickey Petersen. We go through a few pages of the book every time we meet, do some demos, and talk about the concepts we learn from the book. In the 36 meetings that we have had so far, we have spent approximately 26 hours together carefully reading every line of the book, trying out the lessons on an actual editor, and experimenting with the new concepts. In the last 3½ months, we have completed four chapters of the book. We are currently reading the fifth chapter. In this post, I'll share what the journey has been like so far and a few interesting things we have learnt.

A big thanks to Mickey Petersen who very graciously granted me the permission to share his book on screen while we discuss the lessons from the book and try out the examples on the editor.

This is the second series of such meetings I have been hosting. The first one was about analytic number theory that began in March 2021. It ran for seven months and finally concluded in October 2021 after 120 meetings. I chose Emacs as the topic for the next series. The book Mastering Emacs by Mickey Petersen seemed like a great choice for it.

Our new discussion group for Emacs began on 16 Dec 2022. We have been meeting over Jitsi during the weekends. Each meeting is approximately 40 minutes long. With my desktop shared via Jitsi, I demonstrate all the concepts we find in the book in my Emacs editor. On an average, we see about 7 participants in each meeting. Some participants are regulars who join the meetings every weekend, follow the lessons, share their comments, etc. It has been a fun experience so far.

Contents

Variety of Professions

Most members of our discussion group come from the #emacs channels of Libera and Matrix networks. An interesting thing I noticed in our Emacs book discussion group is that we have a good mix of members from diverse backgrounds. In the previous series of meetings on analytic number theory, almost every participant had a career in software engineering. But in this discussion group about Emacs, we have members from various types of professions such as physics, molecular biology, finance, literature, etc. It is interesting how we had mostly software engineers in a mathematics discussion group but a variety of professionals in a software discussion group!

Some participants of our meetings have several years of experience with Emacs. Others are beginners. However, even those who are quite experienced with Emacs have found that they learnt many new techniques and concepts from the book. In the next few sections, I'll present some of those Emacs functions that were initially not known to some of the experienced Emacs users of our group but were found to be very useful after having learnt them from the book.

Lunar Phases

Yes, we can see the lunar phases calendar right within Emacs! I don't know if this was interesting to other members of our group, so I can only speak for myself here. As someone who has been interested in astronomy since my childhood days, I found this very exciting. Type M-x lunar-phases RET in your Emacs and a new buffer appears with an output like this:

Tuesday, March 7, 2023: Full Moon 12:39pm (UTC)
Wednesday, March 15, 2023: Last Quarter Moon 2:14am (UTC)
Tuesday, March 21, 2023: New Moon 5:27pm (UTC)
Wednesday, March 29, 2023: First Quarter Moon 2:33am (UTC)
Thursday, April 6, 2023: Full Moon 4:33am (UTC)
Thursday, April 13, 2023: Last Quarter Moon 9:17am (UTC)
Thursday, April 20, 2023: New Moon 4:16am (UTC) ** Solar Eclipse **
Thursday, April 27, 2023: First Quarter Moon 9:21pm (UTC)
Friday, May 5, 2023: Full Moon 5:32pm (UTC) ** Lunar Eclipse **
Friday, May 12, 2023: Last Quarter Moon 2:34pm (UTC)
Friday, May 19, 2023: New Moon 3:56pm (UTC)
Saturday, May 27, 2023: First Quarter Moon 3:24pm (UTC)

It also shows the upcoming eclipses! In fact, there is one coming up this month! Isn't this nice? I knew that Emacs has all sorts of fun stuff like M-x zone RET to zone out with a built-in screensaver, M-x tetris RET to play a clone of the famous puzzle game, M-: (animate-string "hello" 0) RET to display a string in a fun manner starting off as scattered pieces spread randomly across the buffer that then slide and come together to join and form the string. But to have something as obscure as lunar phases and eclipses available within the editor was a nice surprise! Thanks to the book, I now use this function often.

For people who are not familiar with Emacs notation for key binding, note that M-x lunar-phases RET means typing alt+x followed by typing lunar-phases and then pressing enter. The notation M- represents the meta modifier key which is mapped to alt on modern systems.

Returning to Mark

Most members knew that we can set a mark with C-SPC (i.e., ctrl+space) and then move around in the buffer with motion keys to highlight a region that we can cut with C-w or copy with M-w and paste it elsewhere with C-y. However, what was new to some members is the fact that we can also return to a mark just as easily. The key sequence to return to mark is C-u C-SPC. But there is a problem.

When we set a mark with C-SPC and start moving around with motion keys, the text between the mark and the current position of the cursor (known as point in Emacs) becomes a highlighted region in modern Emacs. This highlighted region can be annoying while browsing some code. So how do we use the mark as a place to return to? Barring unusual workarounds like disabling transient-mark-mode, is there a simple way? Yes, there is a simple trick. Type C-SPC C-SPC to set the mark! Typing C-SPC the first time sets the mark and activates the region. Typing it the second time deactivates the region. But Emacs remembers the mark that was set. Now continue with normal editing. Finally, type C-u C-SPC to return to mark.

The key sequences involved are pretty convenient. Typing C-SPC C-SPC involves holding down the ctrl key, then typing space twice, and finally releasing the ctrl key. Similarly, typing C-u C-SPC involves holding down the ctrl key, typing u, then space, and then releasing the ctrl key. Three keystrokes for each command. They become muscle memory in no time!

Working With Other Windows

In Chapter 4, The Theory of Movement, there is a section about working with other windows. There are a number of key bindings available under the prefix key C-x 4 that perform operations on another window instead of the current window. For example, C-x 4 C-f opens a file in another window. This could be a faster alternative to splitting the current window with C-x 2 or C-x 3 and then opening a file with C-x C-f. The single key sequence C-x 4 C-f takes care of splitting the current window into two if another window does not exist and opening the file there. Moreover if another window does exist, this key sequence just reuses that window to open the file there. Pretty nifty!

To see all the commands under the C-x 4 prefix key, type C-x 4 C-h. Yet another such command that I found quite convenient is C-x 4 d which opens Dired in another window. This can be useful when we need to browse a directory without hiding the current buffer.

Tab Bars

One of the many features of Emacs that most of us did not bother paying attention to earlier was the tab bar mode. Turns out it is pretty useful in managing multiple window configurations side-by-side. Each tab can be used as a workspace with a specific arrangement of windows that suits our workflow in that workspace. For example, we could arrange one tab to have three windows to display source code, a debugger, and the current directory in Dired mode. Then we could have another tab with two windows beside each other, perhaps one to display some source code and another to run the terminal.

The tab management commands are very similar to window management commands. Just like C-x 2 splits a window to create a new window, C-x t 2 creates a new tab. Just like C-x 0 deletes a window, C-x t 0 deletes a tab. Similarly, C-x t o switches to the next tab. Tabs can be renamed and moved too with some more key bindings. Chapter 4 has a section called Tab Bar Mode that introduces these operations in detail.

Back to Indentation

Almost everyone knew that C-a moves the cursor to the beginning of the current line. But not many of us knew about M-m which invokes the command back-to-indentation. This command moves the cursor to the first non-whitespace character on the current line. This is another new thing some of us learnt from the book. This can be quite useful while editing code.

Exchange Point and Mark

Let us say we set a mark somewhere with C-SPC and then move around to select a region. However, then we get distracted, possibly by some typo in our buffer and we begin fixing that. At this point, the highlighted region disappears. Say after fixing that typo, we want to resume with the region selection again. What do we do now? Do we go back to set the mark and begin selecting the region again? Not really. There is an easier way. We can just type C-x C-x to exchange the point and the mark and highlight the region in between. This has the effect of reactivating the region.

Note that C-x C-x exchanges the point and the mark, so although it conveniently reactivates the region, the point jumps to where the mark was set earlier. This could be quite far from where we want the cursor to be right now. If you don't like that the cursor moves far way to the mark, just type C-x C-x once again to exchange the point and mark one more time. This has the effect of returning the cursor back to wherever it was while keeping the region activated.

Search Toggles

Say, we begin an incremental search of the literal string f.. in the current buffer with C-s f.. but then we change our mind and decide that we want to perform a regular-expression-based search using the regular expression f..? Do we cancel the incremental search and begin a new regular-expression-based search using C-M-s? That's not necessary. Instead we can toggle the currently ongoing incremental search into a regular-expression-based search using the toggle key M-s r.

Another such nice toggle is M-%. You are likely aware of the global key binding M-% used to invoke the query-replace command that performs search-and-replace operation. However, when typed during an ongoing incremental search, M-% converts the ongoing incremental search to a search-and-replace operation. This is really useful sometimes. If we are searching for a complicated string, say, C-s std::vector<int> but then we suddenly realise that we want to perform a search-and-replace operation instead with the same string, we don't really have to quit the current incremental search and start a new search-and-replace operation. Instead we can simply change the current incremental search to a search-and-replace operation by typing M-%.

Similarly, we can toggle the case-sensitivity of the search using M-s c. If we type our search string in all lowercase (e.g., C-s foo), then Emacs performs a case-sensitive search by default. I think this is a reasonable default behaviour. This is what we want most of the time. When we do want case-sensitive search for a lowercase string, we can switch from the currently ongoing case-insensitive search to a case-sensitive search with the M-s c toggle.

The moment we introduce an uppercase character in our search string (e.g., C-s Foo), Emacs switches to case-sensitive mode. Although this behaviour may appear peculiar at first, it makes sense if you think about it. If we have bothered to type an uppercase character in our search string, we probably care about the case, so Emacs switches to case-sensitive search in this case. Once again, if this is not what we want, it is trivial to change the case-sensitive search to a case-insensitive one using the M-s c toggle.

There are a number of other toggles available. Chapter 4 has a pretty long subsection on incremental search. That section discusses these toggles among many other things.

Say, we start searching for the string web_server in some code buffer with the key sequence C-s web_server. But we soon realise that the code has the words web and server written together in all kinds of notation like web->server, web::server, web-server, and even web server (perhaps in inline comments). We now decide that we want to match all of them. In most other editors, we'll probably have to cancel the current search and resort to a clever regular-expression-based search. In Emacs, thanks to the toggles available in incremental search, we can type M-s w and the currently ongoing incremental search will change itself to word search mode where it now matches all these other ways those two words are written. In word search mode, Emacs searches for a sequence of words while ignoring any delimiters in between.

Occur Mode

A very useful feature that has been in Emacs for a long time and yet was unknown to many of us is the occur mode. Type M-s o foo RET and it will pull up all matches for the regular expression foo in the current buffer and display the matches in a new buffer. Now we can stay in the same buffer where we have our text and jump to the places where the matches are found using M-g M-n and M-g M-p.

It is also possible to convert an ongoing incremental search into an occur mode search using the toggle M-s o. For example, type C-s foo to start an incremental search for the string foo, then type M-s o and, lo and behold, we are now in occur mode searching for the string foo.

Imenu

Right after the section on occur mode, the book presents a section about Imenu which was also new to some of us. Type M-x imenu RET and then type TAB to invoke auto-completion and it shows a list of all interesting places in the buffer to jump too. For example, if the current buffer is a Python source code file, then the output of this command includes all functions in the Python file we can jump to. Use auto-completion to complete a function name and Imenu takes us to the place where the function is defined.

After completing the sections on occur mode and Imenu, I remember multiple members of our group mentioning that they now want to adopt occur mode and Imenu into their workflow. In fact, it may make sense to bind Imenu to a convenient key binding. The author of the book recommends binding it to M-i. However, I do use M-i sometimes to insert spaces until the next tab-stop column, so I'll suggest a different key binding that is more consistent with Emacs key binding conventions. These conventions suggest that key bindings of the form C-c letter are reserved for the users. Therefore, I suggest the key binding C-c i to invoke Imenu. Here is some Elisp code to create this key binding:

(global-set-key (kbd "C-c i") 'imenu)

Helm

Helm is a powerful filter-as-you-type framework. Most of us already knew about this package. It does too many things and has too many key bindings. We can barely scratch the surface in a small section like this. But since we discussed Imenu in the previous section, I'll mention here that Helm provides a rather nice interface to Imenu. Helm can be enabled with M-x helm-mode RET or with (helm-mode) in an Emacs initialisation file. Once enabled, C-x c i runs the helm-imenu command which provides an interactive interface with all options laid out in a vertical format. We can use the motion keys to select an option. We can then type enter to activate the selection and jump to the corresponding place in the buffer.

Helm also provides a nice interface for occur mode in the form of helm-occur command. The key sequence for it is C-x c M-s o, which one might argue is not a very convenient key binding. Nevertheless, the user interface to navigate the matches is pretty good.

Appending Kills

The key sequence C-M-w is used to ensure that if the next command happens to be a kill command, then the killed text is appended to the last stretch of text in the kill ring. This key sequence prevents the next kill from creating a new entry in the kill ring.

To understand what this command does we must first understand that after a kill command adds some new text to the kill ring, subsequent consecutive kills append to the same stretch of text in the kill ring, i.e., consecutive kills form a single large stretch of text in the kill ring. This can be tested by performing consecutive kills and then pasting with C-y. For example, M-d M-d M-d kills 3 words and creates a single stretch of text consisting of those 3 words. The consecutive kills keep adding to the same kill entry in the kill ring. If we type C-y now, it would yank the newest entry consisting of those 3 words from the kill ring and paste it into the buffer.

However, the moment a non-kill command is used, it seals the current entry in the kill ring. Any subsequent kill command creates a new entry in the kill ring. For example, M-d M-d M-d C-p M-d M-d C-p C-p C-y kills 3 words at first but then it moves to the previous line sealing that kill entry consisting of 3 words. Then it kills 2 more words and adds them to a new entry in the kill ring. Therefore, the final yank command pastes only those 2 words from the kill ring.

This can be a problem if we want to kill text from various parts of the buffer and yet create a single entry in the kill ring. That's when C-M-w comes useful. For example, M-d M-d M-d C-p C-M-w M-d M-d C-p C-p C-y kills 3 words and creates a single entry in the kill ring consisting of those 3 words. Then it moves one line up and kills 2 more words but this time it appends those 2 words to the existing entry in the kill ring. Finally, it moves two lines up and pastes the entire kill entry consisting of 5 words into the buffer.

Yank-Pop

Although most beginners and experienced users of Emacs know that killed text goes into the kill ring and we can yank the last kill from kill ring and paste it into the buffer using C-y, for many that's where the usage of kill ring stops. The kill ring, however, has much more utility than that. It is a ring, after all! We can keep killing text as we edit text and all killed text gets added to the kill ring. Now C-y always yanks the newest kill in the kill ring and pastes it in the buffer? Can we recall an older kill? Yes, using the M-y key sequence. This key sequence invokes the yank-pop command that replaces a just-yanked stretch of killed text with an older kill. It takes a little bit of getting used to but once this becomes muscle memory, the kill ring becomes a very powerful tool. We can keep dumping text to the kill ring and keep recalling text from it while performing our editing activities. The following exercise shows how C-y and M-y can be used together.

  1. Open a new file, say, with C-x C-f foo.txt RET and type these five words in a single line: foo bar baz qux quux.
  2. Then type C-a M-d C-g M-d C-g M-d. At this point three stretches of text have been inserted into the kill ring. The C-g between every M-d is there only to avoid appending kills to the existing stretch of text in the kill ring. This ensures that we have three separate kills in the kill ring.
  3. Now type C-y. The last kill, i.e., baz is now pasted into the buffer.
  4. Now without typing any other key sequence, type M-y. The earlier pasted text baz is now replaced with an older stretch of text from the kill ring. Thus baz is replaced with bar.
  5. Now once again type M-y. The earlier pasted text bar is now replaced with a further older stretch of text from the kill ring. Thus bar is replaced with foo.

Note in the previous steps how we are not supposed to type any other key between the first C-y and M-y. Similarly, while cycling through the kill ring, we must not type any other key between the consecutive M-y key sequences. While cycling through the kill ring, when we reach the oldest kill, the next M-y wraps around and brings back the newest kill.

Since Emacs 28, the key sequence M-y also supports browsing the kill ring and yanking any arbitrary entry from the kill ring. For example, after trying the above experiment, type C-g just to make sure that we are breaking any existing C-y or M-y cycle. Then type M-y and a minibuffer prompt appears to yank an arbitrary kill from the kill ring. If we remember the previous kill, we can type it out partially and type TAB to autocomplete it. Alternatively, we could also type TAB initially itself to browse all the kills in the kill ring.

Join Us

That was an account of our Mastering Emacs book club discussions so far and a few interesting things we learnt. We have only recently begun reading Chapter 5 that introduces several editing and text manipulation commands. This chapter is 75 pages long and it could take a month or two to complete this chapter. There are two more chapters after that which are shorter in their lengths. They discuss some practical aspects of Emacs along with a discussion on some popular packages. We still have a long way to go before we can complete this book.

If all of this sounds like fun, you are very welcome to join our meetings. Just head over to cc/mastering-emacs/ and there you'll find everything you need to know in order to be a part of our book discussion group and join our meetings. Looking forward to seeing you in our next meeting!


Update on 30 Dec 2023: Our discussions of this book concluded on 30 Dec 2023 after 72 meetings. See the post From Fill Prefix to Tramp for more highlights from these meetings.

Comments | #emacs | #meetup | #technology