Notes on Mastering Emacs: Chapter 5: The Theory of Editing

By Susam Pal on 16 Sep 2023

The following notes were taken while discussing Chapter 5 of the book Mastering Emacs, 2022 edition (written by Mickey Petersen) in book discussion group meetings.

An index of notes for all chapters are available at notes.html.

Contents

Killing Text

Killing text is equivalent to what we call as cutting text in other editors. Killing some text removes the text from the buffer and adds it to the kill ring. The kill ring is the clipboard of Emacs.

To discover kill commands using the apropos functionality, type C-h a ^kill-.

Here is a list of commands introduced in the first section of this chapter:

I have observed that some Emacs users do not bother using M-w to copy to kill ring. Instead they type C-w C-/ to cut the text and immediately undo the cut which effectively leaves the buffer unchanged but inserts a copy of the text that was cut into the kill ring. For example, while C-a C-SPC C-n C-n M-w copies two lines into the kill ring, so does C-a C-SPC C-n C-n C-w C-/. The latter key sequence avoids having to use M-w but it is worth noting that this key sequence does not work in a readonly buffer while the former does. To quickly see the difference, open /etc/hosts as a non-root and non-privileged user and try both the key sequences. The former key sequence does not modify the buffer, so it works perfectly in a readonly buffer. The latter key sequence modifies the buffer when we type C-w, so it does not work in a readonly buffer.

I have also observed that many Emacs users do not bother learning C-S-<backspace> because they can achieve the same results using C-a C-k. Further, C-S-<backspace> does not work in terminal Emacs due to terminal limitations. The key sequence C-a moves the cursor to the beginning of the line and C-k kills everything until the end of the line.

There is a difference between deleting and killing. The first two commands C-d and <backspace> delete characters but the deleted characters are not added to the kill ring. The remaining commands in the list above kill text, i.e., remove the text from the buffer and add it to the kill ring. The killed text can be pasted into the buffer using C-y. For example, M-d M-d M-d C-p C-p C-y kills the next three words and pastes them two lines above.

Append Kill

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.

To understand what this command does we must first understand that after a kill command adds a new stretch of 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 C-p C-p C-y kills 3 words, creates a single stretch of text consisting of those 3 words in the kill ring, and pastes that text two lines above.

However, the moment a non-kill command is used, it seals the stretch of text in the kill ring. Any subsequent kill command begins a new stretch of text. For example, M-d M-d M-d C-p M-d M-d C-p C-y kills 3 words at first but then it moves to the previous line sealing that kill text consisting of 3 words. Then it kills 2 words and creates a new stretch of text 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 stretch of text that we want to paste somewhere. 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-y kills 3 words and creates a single stretch of text 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 stretch of text in the kill ring. Finally, it moves two lines up and pastes the entire stretch of text consisting of 5 words into the buffer.

Digit and Negative Arguments

Here are some complete key sequences that demonstrate digit and negative arguments:

Yanking Text

There are two key bindings to learn here. The key sequence C-y executes the yank command which yanks the last stretch of text from the kill ring.

In the apropos system, paste is a synonym of yank. Type C-h v apropos-synonyms RET to see all the synonyms define for the apropos system. Thus C-h a paste RET includes the results for yank too.

Yank Pop

The key sequence M-y executes the yank-pop command which replaces a just-yanked kill with an older kill. This key sequence helps us to cycle through the kill ring and fetch older and older kills to be pasted into the buffer.

Here is an experiment to see how we can use C-y and M-y can be used together:

  1. Open a new buffer 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 to avoid appending kills to the existing stretch of text in the kill ring. This ensures that we have three separate stretches of text in the kill ring.
  3. Now type C-y. The last stretched of kill text, 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.

Maximum Length of Kill Ring

Type C-h v kill-ring-max RET to see the maximum length of the kill ring. It is 60 by default.

Killing Lines

Since C-S-<backspace> works only in GUI Emacs and not in terminal Emacs due to terminal limitations, in the section Killing Lines the author recommends installing the package whole-line-or-region which modifies the behaviour of C-w to kill the current line if there is no active region.

This package can be installed with the following command:

M-x package-install whole-line-or-region RET

Then a mode offered by this package can be enabled by adding this line to the Emacs initialisation file:

(whole-line-or-region-global-mode)

After Emacs is started with the updated initialisation file, typing C-w kills the current line if there is no active region. However, if there is an active region then C-w retains the default behaviour of killing the region.

Although the author recommends this package, I do not use this package. I have found C-a C-k to be very effective for killing the current line. However, it is worth noting that for non-empty lines, C-k does not include the newline in the kill by default. If we want to remove the newline too, we must type C-k another time. Therefore, to faithfully reproduce the behaviour of C-w (of whole-line-or-region) or that of C-S-<backspace>, we need to type C-a C-k C-k.

It is possible to change the default behaviour of C-k such that when we type it at the beginning of a line, the trailing newline is included in the kill. To do so, add this to the Emacs initialisation file:

(setq kill-whole-line t)

After Emacs is started with this initialisation file, C-k kills a whole line along with the trailing newline only if cursor is at the start of a line. In other words, with this setting, C-a C-k always kills a whole line along with the trailing newline.

Transpose

Here are some transpose commands:

While using C-t remember that the point is the logical place between two characters. For example if the cursor blinking on the letter e of the word hello, then the point is between the letters h and e. When we type a new character, the new character is inserted where the point is. The key sequence C-t interchanges the characters on both sides of the point, i.e., it exchanges the character the cursor is blinking on with the character just before it.

There is a subtle difference between the way C-x C-t works and the way the other commands work. The other commands exchange the current or previous object with the next one. However, C-x C-t exchanges the current line with the previous one.

Note that the cursor moves to the end of the next object after performing an exchange. This allows the object that moved forward to be dragged further forward by repeated application of the same command. Note again that while the other commands drag the thing at point forward, C-x C-t drags the previous line forward.

If the cursor is on a space between "foo" :: "bar", note that M-t will transpose it to "bar" :: "foo" because it ignores symbols.

Filling

Here are some complete key sequences that perform paragraph filling:

Commenting

Here are some key bindings to add comments to code in various ways:

Here are some variables that control the behaviour of comment-related commands:

To demonstrate how changing comment-style changes the commenting behaviour try M-x (setq comment-style 'indent) RET, then select a region, and type M-;. The selected region will be commented out with a comment box.

However running M-x (setq comment-style 'aligned) RET, selecting a region in a C buffer, and typing M-; does not seem to do anything interesting.

Search and Replace

Here are some complete key sequences that demonstrate search and replace commands:

The following key bindings work while a query replace operation is in progress:

Just like incremental search (C-s or C-M-s), search and replace performs case folding, i.e., performs case-insensitive match if the search string is a lowercase string. However, the moment we include an uppercase character in the search string, search and replace performs case-sensitive search and replace.

Regular Expressions

This section presents some examples of regular-expression-based search as well as search-and-replace. Here is a simple text buffer where the commands to be presented later can be tried out.

foo-bar-baz
foo-baar-baz
foo-baaar-baz
foo-baaaar-baz
foo-baaaaar-baz
foo-baaaaaar-baz

web
server
webserver
web server
web_server
web->server
web::server
web.server
securewebserver
secure web server
web server port 80

web-server
web-api-server
secure-web-server
web-server-port-80
web-server-port-http
web-server-port-HTTP-80

(1, 2, 3)
[4, 5, 6]
{7, 8, 9}
((10 + 20) * 30)
<40, 50, 60>

"hello, world"
'hello, world'

; comment
# comment
// comment
/* comment */

Here are some complete key sequences that demonstrate regular expressions in search operations:

All examples above that contain the regular expression \s followed by a character matches a character that belongs to a specific syntax class. For example \s. matches characters that belong to the punctuation syntax class. The syntax class for each character is decided by the current major mode. Thus the same character may belong to different syntax classes in different modes. For example, while the character # belongs to the punctuation syntax class in text mode, it belongs to the comment syntax class in Python mode.

To find out which syntax class a particular character belongs to, place the cursor on the character and type C-u C-x =. The syntax field in the output buffer shows the syntax class of the character.

Here are some complete key sequences that demonstrate various search-and-replace features:

Changing Case

Here are some commands to change case of text:

Note that the commands C-x C-l (downcase-region) and C-x C-u (upcase-region) are disabled by default. Follow the prompts to try it or enable it. A quick way to try it is to type SPC. Also, adding the following to the Emacs initialisation file permanently enables it.

(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)

Counting

Here are some commands to count lines, words, characters, patterns, etc:

Deleting and Keeping Lines

The commands that are presented in this section can be tested with a buffer like this:

foo
bar

foo
bar

foo
foo

bar
foo



baz
baz
baz

Here are the commands:

To try each command on the entire buffer, first type C-x h to select the entire buffer as the region and then type a command mentioned above.

Splitting and Joining Lines

Here is a list of commands that help with splitting and joining lines:

The key sequence C-x C-o is very useful for removing spurious blank lines between paragraphs.

Note that M-^ also works on a region. When a region is active, it joins all lines in the region.

Examining and Fixing Whitespace Issues

Here is a list of commands that are useful in examining whitespace in the current buffer:

After typing M-x whitespace-toggle-options RET, type a key to tell it what to do. For example, type N and it will start or restart whitespace-mode with the visualisation of newline toggled. Type ? to see the list of all key inputs it supports.

The key sequence M-x whitespace-toggle-options RET may be typed anytime regardless of whether whitespace-mode is currently enabled or not. If whitespace-mode is not enabled, running whitespace-toggle-options automatically enables it. If whitespace-mode is already enabled, then running whitespace-toggle-options and toggling an option, restarts local whitespace-mode with the updated option setting.

Here are some commands to report and clean up whitespace issues:

As mentioned in the list above, the whitespace cleanup functions read the variable whitespace-style to decide which whitespace issues to fix. Say, we do not want to fix trailing whitespace issue but do want to fix other whitespace issues selected by default (e.g., empty lines at the beginning or end of buffer, spaces before tab, etc.), then we need to update the whitespace-style variable as follows:

(setq whitespace-style (delete 'trailing whitespace-style))

Now running whitespace-cleanup or whitespace-cleanup-region is going to skip fixing trailing spaces but it will perform the other cleanups determined by the value of whitespace-style.

Keyboard Macros

The behaviour of keyboard macro key sequences depend on the current context. So they are presented as table below.

Key Command While not recording While recording
F3 kmacro-start-macro-or-insert-counter Start recording Insert counter
F4 kmacro-end-or-call-macro Call macro End recording
C-x ( kmacro-start-macro Start recording Do nothing
C-x ) kmacro-end-macro End recording Do nothing
C-x e kmacro-end-and-call-macro Call macro End recording and call macro

The key sequences in the table above can be divided into three groups:

Given these details, there are broadly two ways these macro key sequences can be used. They are shown in the table below.

Operation Using Function Keys Using Control Keys
Start recording F3 C-x (
Stop recording F4 C-x )
Call macro F4 C-x e
Stop recording and call macro F4 F4 C-x e
Repeat call macro F4 e

If you are comfortable using function keys, you might want to follow the second column in the table above. Otherwise, you might want to follow the third column in the table above.

The last row is not mentioned in the book but the fact that e may be used to repeat a macro call performed with C-x e is documented in the Emacs manual: Keyboard Macros: Basic Use.

Note that F3 inserts a counter value and increments the counter value by 1 or by the number specified via a digit argument. Here is an example key sequence that may be typed in a buffer with multiple lines to demonstrate this:

  1. Type C-x ( to start macro recording.
  2. Type C-a F3 . SPC M-c C-n to insert macro counter which 0 by default, followed by dot and space at the beginning of the line, capitalise the first word, and move to the next line.
  3. Type C-x e to stop macro recording and call the recorded macro. Now 1, dot, and space is inserted at the beginning of the line, the first word of the current line is capitalised, and the cursor moves to the next line.
  4. Type e to repeat the macro call. Keep typing e to repeat the macro call.

The behaviour of the the macro commands change with universal arguments and digit arguments as follows:

Type C-x C-k C-h to discover keyboard macro commands and their key bindings. The list below shows some of the interesting ones mentioned in the book. In the list below, complete key sequences are used, so that they serve as a demonstration of the macro commands.

Note that all of the above commands work fine even when no macro recording is in progress. For example, earlier we saw that F3 inserts the macro counter value only when a macro recording is in progress. However, C-x C-k TAB inserts the macro counter value even when a macro recording is not in progress.

Another interesting feature mentioned in the book is querying for user input while recording a keyboard macro. The key sequence to query the user is C-x C-k q or C-x q. Here are a few complete key sequences that may be used to demonstrate this feature:

In the above examples, when the macro playback prompts queries for user input, we can also type C-l to recentre the screen, C-r to enter recursive edit, or C-M-c to exit recursive edit.

Note that the key sequence C-l behaves a little differently from the regular C-l. Unlike the regular C-l, successive invocations of this key sequence during macro query does not cause the window to reposition at various places (centre, top, and bottom by default) in a cyclical order. Successive invocations of C-l during macro query, leaves the screen centred.

Here are some key sequences to save and recall macros:

Finally, here are some commands to edit keyboard macros:

A few additional commands:

Text Expansion

Abbrev

Here are some Abbrev commands:

Note that for the expansions to work Abbrev mode should be enabled, say with M-x abbrev-mode RET.

Here are some complete key sequences that demonstrate how we can use Abbrev to define an abbreviation, i.e., text that automatically gets replaced by another text:

Although not mentioned in the book, these commands can be used with a numeric prefix argument to specify the number of words before the cursor to be picked for expansion for the abbreviation we are about to define. Here are some complete key sequences that demonstrate this:

DAbbrev

There are two key bindings discussed in the book:

The last command above takes a little while to get used to it. The following steps demonstrate how it works.

  1. Create a text buffer with the following line:

    abacus apple appliance application
  2. Type ap followed by C-M-/, the word expands to appl since that is the longest common prefix among the matching words.
  3. Type C-M-/ again. The matching words apple, appliance, and application are presented as possible completions in a temporary buffer named *Completions*.
  4. Now type ic, so that the word before the cursor becomes applic, and type C-M-/ again. Now the word before the cursor expands to application because that is the only possible completion now.

Note that by default DAbbrev looks for matching words in other open buffers too and offers them as completions.

Hippie Expand

Unlike DAbbrev, Hippie Expand goes beyond open buffers to look for expansions. The variable hippie-expand-try-functions-list contains a list of expansion functions that hippie-expand uses to look for completions. The book suggests remapping M-/ to invoke hippie-expand with this Elisp code:

(global-set-key [remap dabbrev-expand] 'hippie-expand)

By default, Hippie Expand can complete file names, complete lines, etc. For example, if there is a line for which the current line is a prefix (leading whitespace is ignored while checking for matches), then the current line is expanded to the other matchine line.

Repeated invocations of this command cycles between the matches.

As mentioned earlier, the variable hippie-expand-try-functions-list determines which expansion algorithms are used. Here is an example that demonstrates how we can alter this variable:

(setq hippie-expand-try-functions-list '(try-complete-lisp-symbol))

The above rather unrealistic example severely restricts the expansions Hippie Expand can perform. With the above example, word expansion, line expansion, file name completion, etc. are disabled. Only Elisp symbols are expanded. For example, typing white followed by M-/ first expands the word to whitespace because all matching Elisp symbols have that as the longest common prefix. Typing M-/ over and over again, completes the expansion further with various Elisp symbols.

As mentioned before, the above example is highly atypical. The above example is only meant for demonstrating how this variable can be set. Typically, users add more functions to this variable to add more expansion capabilities.

Indenting

Electric Indentation

Emacs automatically indents code as we type. The major mode decides the automatic indentation behaviour. The automatic identation is provided by a global minor mode named electric-indent-mode which is enabled by default.

Indenting Current Line

Typing TAB indents the current line. In many modes like emacs-lisp-mode, python-mode, text-mode, etc. the command indent-for-tab-command is bound to it. But there are modes that bind another command to TAB. For example, in c-mode, the command c-indent-line-or-region is bound to TAB.

The behaviour of indent-for-tab-command is determined by the variables tab-always-indent. It is t by default which causes TAB to just indent the current line. If set to nil, hitting TAB indents the current line only if the point is before the first non-whitespace character of the line. Otherwise it inserts tabs or spaces to move the point to the next tab stop column. If set to 'complete, typing TAB first tries to indent the current line but if the line is already correctly indented, then it tries to complete the thing at point.

When indent-for-tab-command is bound to TAB and when indent-for-tab-command decides to indent the current line, it calls the function in the variable indent-line-function to perform the indentation. Here is a table that shows what indent-line-function contains in a few major modes where indent-for-tab-command command is bound to TAB:

major-mode indent-line-function
emacs-lisp-mode lisp-indent-line
python-mode python-indent-line-function
text-mode indent-relative

While lisp-indent-line and python-indent-line attempt to indent the current line according to the syntax of the language, indent-relative inserts tabs and spaces to move the point to the next indentation point where the indentation point is defined as the next non-whitespace character following whitespace. This can be useful in aligning the point with words in the previous line. If the previous line has no indentation point (e.g., the previous line is an empty line or does not have whitespace), then tab-to-tab-stop is invoked which inserts tabs or spaces to move the point to the next tab stop column.

The command tab-to-tab-stop command introduced in the previous paragraph can also be invoked with M-i.

Use Only Spaces for Indentation

By default, Emacs uses a mix of tabs and spaces for indentation and alignment. When it needs to align the first non-whitespace character of a line with a certain token in the previous line, it would insert as many tabs as it can followed by a few spaces if necessary to attain the desired alignment. To force Emacs to always use spaces for indentation and alignment, add the following Elisp code to the Emacs initialisation file:

(setq-default indent-tabs-mode nil)

Tab Width

The variable tab-width is used in various contexts while performing indentation and alignment. For example, when indent-tabs-mode is enabled, for every tab-width columns of indentation required, Emacs inserts a tab to indent the code.

Also, when indent-tabs-mode is set to nil, typing M-i inserts as many spaces as necessary to move the point to the next tab stop column where the distance between two tab stops is assumed to be tab-width.

Edit Tab Stops

The behaviour of M-i can be customised further by manually defining tab stop columns. Type M-x edit-tab-stops RET first. A buffer named *Tab Stops* appears. The second and third line of this buffer contains a ruler to indicate the column numbers. Type : (i.e., colon) in the first line whereever you want to define tab stops. Then type C-c C-c to install the changes. Now when M-i is typed in a text buffer, each time it inserts as many tabs (if indent-tabs-mode is t) or spaces as necessary to move the point to the next tab stop column as defined earlier in the *Tab Stops* buffer.

Indent Region

Typing TAB when a region is active indents the region according to the major mode's indentation rules. It invokes the same command as the one invoked when we type TAB to indent a line. The command bound to it takes care of indenting region. For example, if TAB is bound to indent-for-tab-command, the latter checks if a region is active and if it is, then it simply calls indent-region.

The indent-region command can be invoked explicitly using C-M-\. If fill-prefix has been set, say with C-x ., then it is added to every line in the region being indented. With a numeric prefix argument, each line in the region is indented to the column indicated by the argument. For example, C-M-1 C-M-0 C-M-\ indents each line of the region to column 10.

Indent Rigidly

When we want to rigidly control how a region must be indented, we can type C-x TAB to perform rigid indentation. Doing so allows us to bypass the indentation rules of the major mode. Instead we control exactly how the indentation must be done. The following complete key sequences demonstrates a few examples of rigid indentation:

Sorting

Assuming a region is active, here are some complete key sequences for various sorting commands:

Aligning

The two simple commands for aligning text introduced first in the book are:

Consider the following Elisp buffer:

(defvar person '(("name" . "Alice")
                 ("city" . "London")
                 ("country" . "UK")))

If we type C-x h followed by M-x align RET, or if we put the cursor on any line of the above code and type M-x align-current RET, we get the following result:

(defvar alice '(("name"    . "Alice")
                ("city"    . "London")
                ("country" . "UK")))

There is also an align-regexp command that allows us to parts of lines by regular expressions. The following experiments demonstrate this command.

  1. First create a buffer with the following text:
    Alice:London:UK
    Bob:Paris:France
    Carol:Tokyo:Japan
    
  2. Type C-x h followed by C-u M-x align-regexp \(\s-*\): RET 1 RET 1 RET y RET. The result looks like this:

    Alice :London :UK
    Bob   :Paris  :France
    Carol :Tokyo  :Japan
    

    Note that the regular expression capturing group \(\s-*\) appears as the default in the minibuffer. We only add : to it. Similarly the two occurrences of 1 appear as default values. The first 1 is the default for determining which parenthesis group to modify. The second 1 is the default for amount of spacing to be used during alignment. The y in the end specifies that we want to repeat the alignment throughout the line.

  3. Type C-/ to undo the changes done in the last step. Then type C-x h followed by M-x align-regexp : RET. This is a shorter equivalent to the previous command. The output is same as before.
  4. Type C-/ to undo the changes done in the last step. Then type C-x h followed by C-u M-x align-regexp :\(\s-*\) RET 1 RET 1 y RET. Note that the only difference this time is that we place the colon before the parenthesis group. The result looks like this:

    Alice: London: UK
    Bob:   Paris:  France
    Carol: Tokyo:  Japan
    
  5. Type C-/ to undo the changes done in the last step. Then type C-x h followed by C-u M-x align-regexp \(\s-*\): RET 1 RET 0 y RET. Note that the only difference this time is that we place the colon before the parenthesis group. We specify 0 as the amount of spacing this time, so a minimum of zero spacing is used for alignment when possible. The result looks like the following. Notice the lack of space after Alice and Carol.

    Alice:London:UK
    Bob  :Paris :France
    Carol:Tokyo :Japan
    
  6. Type C-/ to undo the changes done in the last step. Then type C-x h followed by C-u M-x align-regexp \(\s-*\): RET 1 RET 5 y RET. Note that the only difference this time is that we place the colon before the parenthesis group. We specify 5 as the amount of spacing this time, so a minimum of 5 spaces are used for alignment.

    Alice     :London     :UK
    Bob       :Paris      :France
    Carol     :Tokyo      :Japan
    

Zap to Char

The steps below demonstrate the zap-to-char command that is bound to the key sequence M-z. This command kills up to and including the given character.

  1. Create a buffer with the following text:

    foo bar baz qux quux
  2. Type M-< to go to the beginning of the buffer and then type M-z r to kill text up to and including the first occurrence of the letter r. The buffer now looks like this:

      baz qux quux
  3. Type M-< to go to the beginning of the buffer and then type M-z x to kill text up to and including the first occurrence of the letter x. The buffer now looks like this:

     quux
  4. Now type C-e SPC C-y to reinsert the killed text at the end of the line. The buffer now looks like this:

     quux foo bar baz qux

    Note that the last step yanks both chunks of text that were killed in the previous two steps. This is due to the fact that consecutive kills append to the same stretch of text in the kill ring. This fact was discussed earlier in section Append Kill

  5. Now type M-< to go back to the beginning of the buffer again. Then type M-2 M-z a. The numeric argument 2 specifies that we want to zap up to the second occurrence of the letter a. The buffer looks like this:

    z qux
  6. Type C-e SPC C-y to reinsert the text killed in the previous step at the end of the line. The buffer looks like this now:

    z qux quux foo bar ba
  7. Type M-- M-2 M-z x to zap backward up to the second occurrence of the letter x. The buffer looks like this now:

    z qu

Zap up to Char

Here are some steps that demonstrate the zap-up-to-char command. This command kills text up to, but not including, the given character.

  1. Create a buffer with the following text:

    foo bar baz qux quux
  2. Type M-< to go to the beginning of the buffer. Then type M-x zap-up-to-char RET b. The result now looks like this:

    bar baz qux quux
  3. Type M-2 M-x zap-up-to-char RET q. The result now looks like this:

    quux
  4. Type C-e SPC C-y to reinsert the killed text at the end of the buffer:

    quux foo bar baz qux 
  5. Type M-- M-2 M-x zap-up-to-char RET b. The buffer now looks like this:

    quux foo b

The author of the book suggests binding this command to M-S-z with the following Elisp code:

(global-set-key (kbd "M-S-z") 'zap-up-to-char)

The above code, however, does not create the binding successfully. Therefore, use the following Elisp code instead:

(global-set-key (kbd "M-Z") 'zap-up-to-char)

Now the commands presented in this section above can be typed as follows:

Spell Check

The spell checking commands of Emacs require a spell checking program to be installed on the system. Emacs supports the spell checking programs aspell, ispell, hunspell, and enchant-2. If multiple programs are present, it looks for them one by one in the order specified in the previous sentence and picks the first one that is found. The following spell checking commands are introduced in the book:

Dictionary Lookup

The following complete key sequences demonstrate some of the dictionary commands introduced in the book:

The dictionary commands first attempt to connect to a locally running dictionary server. If the connection does not succeed, it prompts for consent to connect to dict.org. Typing y at the prompt allows the command to proceed and complete the command.

Quoted Insert

Here are some complete key sequences that demonstrate quoted insert:

The following list includes some links that were discussed during the book discussion group meetings: