I am an Emacs user of several years, but only recently discovered some features that I find incredibly convenient. I am somewhat embarrassed by my ignorance (and for that reason write this post anonymously), but suspect that others might not be familiar with these features, and so hope that sharing them here might be of use. Note that for most of this post, I'll write assuming you know the basics of Emacs -- if you don't, some of the following may be mysterious to you.

Magit

The feature I've found most useful, but is most widely-discussed, is Magit. Magit is an interface to git inside Emacs. Why do you need Magit when you already know how to use git on the command line?

  1. It's nice not to have to switch to the terminal to commit/pull/push.
  2. Magit commands are shorter than git commands (in the right context, you can just press "c c" to commit, rather than typing "git commit").
  3. Magit nicely shows you the state of your repository: Which changes have been staged, which staged changes have not yet been committed, the state of the remote branch, etc.
  4. Magit also nicely displays which things you can do with it. For instance, the first time you press "c" to commit, you are shown a window of options for your commit -- for example, would you like to override the author? To allow an empty commit? To disable running hooks? By default you can immediately press "c" again to do none of these things, but if you want to do something unusual, Magit shows you how.

In general, it is a much nicer experience than using git on the command line, and I strongly recommend it to Emacs users who regularly interface with git.

Tramp

A situation I am regularly in is that I want to edit files on a remote machine. Previously, to do this, I would SSH into the remote machine, open Emacs in the terminal, and edit that way. This was functional, but meant that I had to set up Emacs on every machine I wanted to work on, which was sometimes impractical. It turns out that there is a better way: when you open a new file in Emacs with C-x C-f, you can type in a path like /ssh:my_remote_machine:/home/my_name/my_dir/my_file.txt, and make edits to the file via ssh. This does not require installing anything, it's a built-in feature of Emacs called "Tramp", and it just works: for instance, when editing a file on a remote machine, you can use Magit to take actions in that machine's copy of the repository.

Admittedly, it's not perfect: on my machine, the connection sometimes stalls such that when I open a buffer or type anything, emacs hangs for an indeterminate amount of time. It's possible that this is fixable by using something other than Tramp, or by using tramp with a connection method other than SSH.

M-m

Here's a common situation for me to be in: I'll be editing code like the following:

def my_func(x,n,m):
    for i in range(n):
        for j in range(m - i):
            z = j * i
            x += 3 * z
            if j % 2 == 0:
                a = greeble(z) + greeble(j) + greeble(i) + f(n) + g(m)
                degreeble(a)
                x += a
    return x

Suppose I'm in the innermost code block, my cursor at the end of the first line, and I want to edit the initial a (perhaps I realize it should be (a, _)). My previous strategy was to press C-a to go to the very start of the line, M-f to go to the end of the first word in the line, and M-b to go to the start of that first word. This worked, but there's a better way: the command M-m takes you to the start of a line, but after all initial whitespace.

Subword mode

Code often features names written in camelCase: for example, a class name in Python might be something like MetaMicroBiomeFactoryGenerator. Sometimes, you want to go to one of the middle words in such a class name: for instance, you might have misspelled 'Biome', or realized that it should actually be a MetaNanoBiomeFactoryGenerator. By default, Emacs treats the whole name as a single word, so you need to move forward or backward character by character to fix your mistake, which is annoying. Luckily, there's a better way: in subword mode, each new capital letter inside a string counts as the start of a new word, so you can navigate using M-f and M-b to edit internal words in camelCase names. To always be in subword mode, you can add (global-subword-mode 1) to your init.el file.

How to avoid this kind of failure

Ideally, I would not have gone multiple years without knowing about these features of my text editor. It's worth reflecting some amount on how this could have been avoided.

Learn a bunch about the software before using it

I actually did this. The problem is, there are enough things to learn about Emacs that I just didn't get to them all before I was tired of spending time learning about Emacs.

Subscribe to feeds of people sharing things they like about Emacs

This could work: for example, I could regularly browse r/emacs. The problem is that people who frequent these forums are very unlike me: they use emacs for more things than I do, they like org mode, they have problems that I don't have, etc. This means that the features they want to talk about are usually not very useful for me, and so I get little value out of this.

Read introductions to Emacs

These are designed to be helpful: for instance, I believe I've gotten a few of these from Mastering Emacs. So it might be a good idea to now and again read these sorts of things about software you use.

Have other experienced Emacs users watch you do stuff in Emacs

This is probably most likely to be useful, but strikes me as a bit awkward / time-consuming.

New to LessWrong?

New Comment
5 comments, sorted by Click to highlight new comments since: Today at 5:46 AM

Have other experienced Emacs users watch you do stuff in Emacs

My brain suggests that one could implement this as an Emacs feature.  If it notices you doing "C-a M-f M-b" several times, then it tells you about M-m.  This could certainly be annoying if implemented badly—it would be like Microsoft's Clippy—but it seems conceivable that it could be implemented well.

I tried Magit for a while, but hardly use it anymore. It had some serious performance issues, especially when using pretty diffs via Delta. I've mostly switched to lazygit, which does work in a terminal over ssh or mosh. It's a separate program, not integrated into Emacs.

This worked, but there's a better way: the command M-m takes you to the start of a line, but after all initial whitespace.

I find it more intuitive to just make Home/C-a smarter:

;;"Redefine the Home/End keys to (nearly) the same as visual studio
;;behavior... special home and end by Shan-leung Maverick WOO
;;<sw77@cornell.edu>"
;;This is complex. In short, the 1st invocation of Home/End moves
;;to the beginning of the *text* line (ignoring prefixed whitespace); 2nd invocation moves
;;cursor to the beginning of the *absolute* line. Most of the time
;;this won't matter or even be noticeable, but when it does (in
;;comments, for example) it will be quite convenient.
(global-set-key [home] 'my-smart-home)
(global-set-key [end] 'my-smart-end)
(defun my-smart-home ()
  "Odd home to beginning of line, even home to beginning of
text/code."
  (interactive)
  (if (and (eq last-command 'my-smart-home)
           (/= (line-beginning-position) (point)))
      (beginning-of-line)
    (beginning-of-line-text)))
(defun my-smart-end ()
  "Odd end to end of line, even end to begin of text/code."
  (interactive)
  (if (and (eq last-command 'my-smart-end)
           (= (line-end-position) (point)))
      (end-of-line-text)
    (end-of-line)))
(defun end-of-line-text ()
  "Move to end of current line and skip comments and trailing space.
Require `font-lock'."
  (interactive)
  (end-of-line)
  (let ((bol (line-beginning-position)))
    (unless (eq font-lock-comment-face (get-text-property bol 'face))
      (while (and (/= bol (point))
                  (eq font-lock-comment-face
                      (get-text-property (point) 'face)))
        (backward-char 1))
      (unless (= (point) bol)
        (forward-char 1) (skip-chars-backward " \t\n"))))) ;;Done with home and end keys.

So it's just C-a to go where I usually want to, and then if that's not good, just drum your fingers with a second C-a to go to the true beginning of the line. Quite intuitive. 'Go to the start of the line - no, really go to the start of the line!'

Ah, beginning-of-line-text is nice. It skips over the initial # or // of comments and the initial * of Org headings. I've now bound it to M-m.

I did not know about M-m, thanks!