Configuring Emacs

(Last updated 2012-01-08)

I just went through the exercise of configuring Emacs on my Mac laptop, and thought I'd try to document what I did. If nothing else, it will be useful to have whenever I need to go through it again, but it could also be a good example for any newbies out there on how to get going customizing their Emacs installs.

Emacs is my main editor for code and text (Well, almost. For Java I find anything except Eclipse to be very masochistic, but Emacs works for all other programming languages). I'm not hardcore enough to use it for things like email, day planning or balancing my check book, so this write-up will just focus on getting a good, basic environment set up for writing code.

A good way to think about Emacs is that it's designed be customized. As soon as there's something you don't like (and there will be), the odds are high that you can change it to behave the way you want instead. And you should! With Emacs, ruthless and constant customization is what gets you the real productivity gains.

I try to make sure I understand what all my customizations actually do. It's very easy to just copy a big blob of code from someone else's .emacs file, but when I do that I always immediately forget about the fancy new functionality and end up not actually using it. Doing the homework seems to pay off.

If you're not familiar at all with Emacs, you may want to start by getting it installed, taking a look at how the .emacs config file works and maybe getting into a tiny bit of elisp before reading too much further. I'm doing this with GNU Emacs 23.2.1. I didn't bother with compiling it myself, but got the binary from emacsformacosx.com. I'm not going to spend time arguing for why Emacs is a good thing, others have done a much better job than me on that front.

Anyway, here's the current state of the complete .emacs file, and below the explanations for what's going on.

;; Shut up
(setq ring-bell-function 'ignore)

;; Kill scrollbars
(set-scroll-bar-mode nil)
(size-indication-mode)
(column-number-mode)

;; Scroll one line at the time
(setq scroll-conservatively most-positive-fixnum)

;; Improved end-of-buffer scrolling
(global-set-key "\C-v"
  (lambda () (interactive)
    (condition-case nil (scroll-up)
      (end-of-buffer (goto-char (point-max))))))

(global-set-key "\M-v"
  (lambda () (interactive)
    (condition-case nil (scroll-down)
      (beginning-of-buffer (goto-char (point-min))))))

;; Kill backup files
(add-to-list 'backup-directory-alist '("." . "~/.emacs.d/backup"))

;; Display and edit stuff
(show-paren-mode t)
(setq-default show-trailing-whitespace t)
(setq-default indicate-empty-lines t)
(setq-default require-final-newline t)
(delete-selection-mode)

;; Buffer navigation
(ido-mode)
(setq ido-enable-flex-matching t)

(require 'uniquify)
(setq uniquify-buffer-name-style 'post-forward)

;; Window navigation
(winner-mode t)

;; Hippie Expand
(global-set-key "\M- " 'hippie-expand)

;; Highlight symbol mode
;; http://nschum.de/src/emacs/highlight-symbol
(add-to-list 'load-path "~/.emacs.d/site-lisp")
(require 'highlight-symbol)
(setq highlight-symbol-idle-delay 0.3)
(add-hook 'python-mode-hook 'highlight-symbol-mode)
(add-hook 'c-mode-hook 'highlight-symbol-mode)
(add-hook 'c++-mode-hook 'highlight-symbol-mode)

;; Other coding stuff
(global-set-key "\C-c;" 'comment-or-uncomment-region)
(global-set-key "\C-cc" 'compile)

(add-hook 'python-mode-hook 'subword-mode)
(add-hook 'c-mode-hook 'subword-mode)
(add-hook 'c++-mode-hook 'subword-mode)

;; Text edit stuff
(setq-default ispell-program-name "/opt/local/bin/aspell")

;; Force yourself to use the arrow keys
(global-set-key (kbd "") nil)
(global-set-key (kbd "") nil)
(global-set-key (kbd "") nil)
(global-set-key (kbd "") nil)

;; Server mode
(server-start)

First, shut up

(setq ring-bell-function 'ignore)

Not sure why the bell is still turned on by default, but turning it off is generally the first step to keeping your sanity. You could change it to be a "visible bell" instead of having it actually beep, but that's just annoying in a different way. This command simply turns everything off.

Kill scrollbars

(set-scroll-bar-mode nil)
(size-indication-mode)
(column-number-mode)

The scroll bars that are turned on by default are pretty useless, since the line number and the little percentage display shows where you're at in the file anyway. Calling "set-scroll-bar-mode" with a nil parameter gets rid of them.

You'll want to turn on "column-number-mode" and maybe even "size-indication-mode" instead, which shows which column you're in and the actual size of the file.

Scrolling

;; Scroll one line at the time
(setq scroll-conservatively most-positive-fixnum)

;; Improved end-of-buffer scrolling
(global-set-key "\C-v"
  (lambda () (interactive)
    (condition-case nil (scroll-up)
      (end-of-buffer (goto-char (point-max))))))

(global-set-key "\M-v"
  (lambda () (interactive)
    (condition-case nil (scroll-down)
      (beginning-of-buffer (goto-char (point-min))))))
Emacs default scrolling behavior is a bit, well, unorthodox. To fix this I first set "scroll-conservatively" to the "most-positive-fixnum" which switches the scrolling to the traditional one-line-at-the-time instead of Emacs more aggressive default. The second part of this snippet is a hack to make scrolling to the beginning and end of the buffer work like you expect it. The idiotic default will apparently be fixed in Emacs 24, but until that's released this will do the trick.

Display and edit stuff

(show-paren-mode t)
(setq-default show-trailing-whitespace t)
(setq-default indicate-empty-lines t)
(setq-default require-final-newline t)
(delete-selection-mode)

Now some commands to make the display and editing more pleasant. "show-paren-mode" gives you visual cues to which parenthesis matches the one your cursor is standing on. Critical for any Lisp programming obviously.

Setting "show-trailing-whitespace" to true means that all trailing whitespace will be shown in angry red (and running "M-x delete-trailing-whitespace" is an efficient way to clean them up). "indicate-empty-lines" is the equivalent for trailing lines at the end of the file, and "require-final-newline" makes sure a newline is added whenever you save a file if there isn't one there already. This will save you some trouble editing crontabs, and other picky things. Finally, turning on "delete-selection-mode" means that when you mark a region and hit delete, the region will actually get deleted.

Kill the backup files

(add-to-list 'backup-directory-alist '("." . "~/.emacs.d/backup"))

A vanilla Emacs setup will start polluting your file system with backup files. Whenever you edit a file, a backup of the previous version is kept around, with "~" appended to the name. It gets really annoying for anyone with at least a hint of OCD.

Running this command changes that behavior and tells the system to instead store all the backup files in the folder ~/.emacs.d/backup. What's actually happening here, elisp-wise, is that we're pushing a pair onto the backup-directory-alist, where the first part, ".", is a regular expression that matches all possible files and the second the folder where the backups should be stored.

Buffer navigation

(ido-mode)
(setq ido-enable-flex-matching t)

(require 'uniquify)
(setq uniquify-buffer-name-style 'post-forward)

If you're going to pick just one thing from this list to start using, go with ido-mode. "ido" means "interactively do" and it adds some really nice name completion mechanisms when opening files and switching between buffers. ido-mode is built on top of another similar package called iSwitchB, and there's a competitor called Icicles that could be worth looking at too.

Just turning on ido-mode gets you far, but I also switch on "ido-enable-flex-matching" which means that any characters in the right sequence will match when you're looking for a file or a buffer (so you can type "afi" to get to the file "AbstractFactoryImpl.java", for example).

Also listed here is the command to start up "uniquify" which automatically will rename two buffers that share the same file name to something unique and understandable. The default Emacs behaviour is that the second buffer just gets "<2>" appended to the file name, but that gets confusing quickly. Uniquify actually finds the piece of the path that differentiates the two files and shows that instead. I happen to prefer uniquify's "post-forward" style, but you can try the different possible ways to see which looks best to you.

Window navigation

(winner-mode t)

More often than not you'll find your carefully crafted window layout suddenly destroyed by some random command you just executed (ediff is the typical culprit for me). Turning on winner-mode makes that a bit less annoying.

This minor mode keeps track of your last window layouts and lets you switch between them quickly. So as soon as you're done with the ediff session that screwed everything up you can simply hit C-left arrow and the previous setup is magically recovered.

ediff is very nice, by the way. Make sure you take a look at it.

Hippie Expand

(global-set-key "\M- " 'hippie-expand)

Hippie Expand offers a crude form of text completion (like a poor man's Intellisense). When called, it will try to expand the current word at point by looking the contents of the open buffers and the kill-ring. Works surprisingly well even though it doesn't actually know anything about your code. I'm assigning it to M-space for quick access everywhere.

Nobody knows why it's called hippie-expand, by the way. It's written by a Swede, maybe that explains it.

Highlight Symbol mode

(add-to-list 'load-path "~/.emacs.d/site-lisp")
(require 'highlight-symbol)
(setq highlight-symbol-idle-delay 0.3)
(add-hook 'python-mode-hook 'highlight-symbol-mode)

This is the only non-standard package I'll install for now. Highlight-symbol-mode looks at the symbol at point, and highlights all other occurrences of it in the buffer. Extremely useful for quick visual feedback on where a variable was first declared, for example.

To get this to work you first need download the elisp code from http://nschum.de/src/Emacs/highlight-symbol. Put it in a folder called ~/.emacs.d/site-lisp. The listed commands simply sets up this folder as a place where elisp libraries are available, and then loads it up. Setting "highlight-symbol-idle-delay" to 0.3 means that it'll wait 0.3 seconds before starting to do any highlighting.

Finally, and a bit annoying, is that this is just a minor mode so you can't turn it on globally. You need to explicitly add it to the hooks for the major modes where we want it running. In this example I'm doing it for Python, but you probably want to do this for most modes.

Other coding stuff

(global-set-key "\C-c;" 'comment-or-uncomment-region)
(global-set-key "\C-cc" 'compile)

(add-hook 'python-mode-hook 'subword-mode)
(add-hook 'c++-mode-hook 'subword-mode)

This first line here simply adds a keybinding that calls the comment-or-uncomment-region command when I press C-c ;. The command does exactly what you'd expect: if the current region is not a comment it is commented out, and vice versa. It uses the comment style defined by the major mode you're currently using, so it works for all programming languages.

The second command is to bind C-cc to the compile command. This will let you specify a command to compile the current buffer, and sends the output to a special buffer called *compilation*, where you can step through error messages and so on.

Finally I'm enabling subword-mode for a bunch of major modes. This changes the way Emacs treats words written in CamelCase. Without subword-mode hitting M-d when point is on, let's say, "AbstractFactoryImpl" will delete the whole thing. But with subword-mode enabled only the first camel-cased word is deleted -- and you're left with "FactoryImpl". This is very useful if you're working on code written in this style.

Text editing

(setq-default ispell-program-name "/opt/local/bin/aspell")

Only one line of configuration here, but there's a few more tricks to make editing plain text better. First up: Get a spell checker installed. Emacs defers to ispell, aspell or whatever Unix program you prefer, so the first thing to do is to install one of those (probably easiest done using Macports). Once you've got that working, this line will tell Emacs which program to actually use, and you can then execute spell checking with M-$ or M-x ispell-buffer.

Another thing worth knowing about is longlines-mode. I don't do anything special to start up this mode, since it's not appropriate for every file. I simply turn it on when I need it with "M-x longlines-mode". This mode makes Emacs behave a bit more like a word processor. Lines are automatically wrapped, but no newline characters are ever inserted in the paragraphs. Not useful for coding, but very necessary when you're doing some writing.

Punish yourself

;; Force yourself to avoid the arrow keys
(global-set-key (kbd "") nil)
(global-set-key (kbd "") nil)
(global-set-key (kbd "") nil)
(global-set-key (kbd "") nil)

One thing that comes up a lot is Emacs's steep learning curve, and how you need to invest in getting comfortable with it. Here's a good way to get into that mindset: Turn off the arrow keys and force yourself to use C-f, C-b, C-n and C-p to navigate around the buffers instead. It took me a week or two to recover after I did this, but it seems like editing goes faster now since I don't leave home row that often anymore.

Arguably this is a bit extreme, so you may not want to do it your first week with Emacs. Or try it right before a critical deadline. Another downside is that once you get used to these keybindings you will constantly have other programs open new windows and print dialog boxes when you try to navigate their text fields. But that's the life we chose.

Daemon / server mode

(server-start)

Down the line you'll actually end up loading so much elisp that starting up a new Emacs process will take a few seconds. That's a bit too much, and if you're like me you soon be thinking about picking some other(!) editor just for all those fast one-off changes you need to make at the command line. That's not good.

No fear, server-mode to the rescue. This mode lets you keep one instance of Emacs running and have it act as a server, and whenever you need a new editor you start up lighter client versions that connect to the server to get their initial state. Startup is instant and you're able to share buffers between the server and clients.

To take advantage of this, the trick is simply to call "(server-start)" from your main Emacs instance. Then run "emacsclient -c -nw" instead of "emacs" from the shell whenever you need a new editor (remember to change $EDITOR in your shell configuration).

Even more advanced is "daemon-mode" in which the server is simply a daemon process with no actual GUI. This isn't very useful on a laptop, but can be a big win if you're using it on a desktop or server machine that you're logging into from multiple places.

Per Jacobsson