The following notes were taken while discussing Chapter 4 of the book Mastering Emacs by Mickey Petersen (2022 edition) in book discussion group meetings.
An index of notes for all chapters are available at notes.html.
{{ toc }}The following complete key sequences illustrate a few basic commands:
C-x C-f foo.txt RET: Edit file
named foo.txt.
C-x C-s: Save current buffer to file.
C-x b *scratch* RET: Switch to the buffer
named *scratch*.
C-x k *scratch* RET: Kill the buffer
named *scratch*.
C-x k RET: Kill current buffer. In fact, like the
previous key sequence above, typing C-x k first
prompts for the buffer name. However, the current buffer name is
selected as the default value already. As a result,
typing RET kills the current buffer.
C-x C-b: List buffers.
C-x C-c: Exit Emacs. This command offers to save all
unsaved buffers before exiting Emacs.
ESC ESC ESC: This command exits the current context.
What that means depends very much on the context. It performs
exactly one of the following actions: If there is an active
region, then it is deactivated; if a minibuffer is open, it gets
rid of it; if recursive edit is in progress, it quits one level of
recursive editing; if multiple windows are open, it deletes other
windows so that the current window becomes the only window in the
frame. The aforementioned conditions are tested one by one and as
soon as one of the conditions is met, the corresponding action is
executed and the other conditions are skipped.
C-/: Undo changes.
F10: Activate the menu bar.
In my experience, I have found that ESC ESC ESC is most
useful when a stray minibuffer is open but the cursor is on some
other buffer instead of the minibuffer and I need to close the
minibuffer. Here are some steps that demonstrate this usage:
Type M-x white and pause. We now have a partially
typed command in the minibuffer.
Now pretend that we get distracted by some imperfections in the
text buffer that was open earlier and we want to fix those
first. Type C-x o to move away from the minibuffer
and go back to the text buffer to perform some editing tasks.
In this step, we could have typed C-g to quit the
minibuffer first but we did not do that. We pretended to get
distracted by the text buffer and went straight to it from the
minibuffer by typing C-x o. At this point, the
cursor is in the text buffer and the minibuffer remains open at
the bottom. The open minibuffer can be distracting while
performing the text editing tasks. Typing C-g now
will not get rid of the minibuffer because the cursor is no
longer in the minibuffer.
Now one way to close the open minibuffer could be to
type C-x o to go back to the minibuffer window and
type C-g. However, there is a more direct way to
do this as explained in the next point.
Type ESC ESC ESC to get rid of the minibuffer at
the bottom. This works even when the cursor is not in the
minibuffer but is in the text buffer instead.
The chapter mentions the following order for detecting major mode:
Let us start from the bottom of the list and share some experimental results that illustrate how the major mode detection works.
Create a text file named foo.txt with the following
content:
#include <iostream>
int main() {
std::cout << "hello, world\n";
return 0;
}
Then open this file in Emacs (say, with C-x C-f foo.txt
RET). Emacs sets the major mode to Text
(i.e. text-mode).
Type M-: major-mode RET to confirm that indeed the
value of major-mode is text-mode.
This happens due to automatic mode detection which determines
the major mode based on the file name. In this case it sees
that the file name ends with .txt and
enables text-mode. We will discuss automatic mode
detection further in the
section Automatic Mode
Detection.
Now edit the previous file to add file-local variables in the header as follows:
// -*- mode: c++; c-basic-offset: 4 -*-
#include <iostream>
int main() {
std::cout << "hello, world\n";
return 0;
}
Now reload the buffer. You could simply kill the buffer
with C-x k and reopen the file with C-x C-f
foo.txt RET or alternatively, reload the buffer
with M-x revert-buffer RET yes RET.
After reloading the buffer, you should see that
the C++ mode (i.e. c++-mode) is
enabled. As a result, C++ syntax highlighting should be
visible. Further C-x h TAB should reformat the
code to use 4 spaces for each level of indentation.
File-local variables may be specified in the footer too as shown below:
#include <iostream>
int main() {
std::cout << "hello, world\n";
return 0;
}
// Local Variables:
// mode: c++
// c-basic-offset: 6
// End:
Now reloading the buffer should show that c++-mode
is enabled and typing C-x h TAB should reformat the
code to use 6 spaces for each level of indentation.
What happens if the file-local variables in the header and footer contradict each other? To test this out, edit the buffer to have the following content:
// -*- mode: c++; c-basic-offset: 4 -*-
#include <iostream>
int main() {
std::cout << "hello, world\n";
return 0;
}
// Local Variables:
// mode: python
// c-basic-offset: 6
// End:
Reloading the buffer should show that c++-mode is
active. Typing C-x h TAB should reformat the code
to use 6 spaces for each level of indentation. Therefore the
mode specified in the header remains effective. For other
variables, the ones specified in the footer have precedence.
Of course, the example above is intended for curiosity and exploration. In practical use, however, it is best to avoid assigning conflicting values to file-local variables in both the header and footer. Such inconsistencies can lead to confusion and make the effect of the variables difficult to understand.
TODO: More notes coming up here soon!