Notes on Mastering Emacs: Chapter 4: The Theory of Movement

By Susam Pal on 25 Mar 2023

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.

Contents

Basics

The following complete key sequences illustrate a few basic commands:

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:

  1. Type M-x white and pause. We now have a partially typed command in the minibuffer.

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

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

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

Major Mode Load Order

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.

File-Local Variables

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

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

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

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

Occur Mode

TODO: More notes coming up here soon!