GNU Emacs

Author: Taylor Venable
Contact: taylor@metasyntax.net
Copyright: Creative Commons Attribution / Share-Alike

Contents

A Brief Note

This page is a work-in-progress conversion from the old HTML version found here into reStructuredText. There are at this point lots of HTML-isms lying around (you'll find HTML tags, for instance) so please just ignore those for now until I can polish this more. In the mean time, this should be considered the authoritative version of the Emacs page, because while I'm polishing I'm also adding and updating.

Introduction

Emacs (short for Editing Macros, or sometimes alternatively, Escape Meta Alt Control Shift) are probably the most powerful editors ever created by humankind. It is the Evangelion of programmers' programmable editors. You can use it to write code, read email, and perform psycho-analysis. Emacs can even save your soul if you choose to embrace it. So why exactly is Emacs so great?

Calling EMACS an editor is like calling Earth a hunk of dirt.

—Chris DiBona

Well, it's mostly because Emacs is written largely in its own dialect of Lisp, and as such has at its core a specialized Lisp interpreter. This causes it to weigh in a bit heavily (the CVS version with full debugging can run at over 48 MB of RAM after some extended use) but also gives the benefit of being extensible to an unprecedented level. Some view this as being a bad thing, and happily stick with slimmer editors like vi. I myself am perfectly alright with memory usage in the 32 to 64 meg range, because frankly I think it's more than worth it. Now, I have used both Emacs and Vim for several years, and I still frequently use Vim for quick editing. But when I really get down to development brass tacks, it's GNU Emacs that I choose.

The Emacs configuration file, read at startup to restore user customizations, is interpreted in Emacs Lisp. As a result, writing complex configurations requires some knowledge of how Emacs Lisp works. If you've ever used a functional programming language before, like Scheme or Common Lisp, you'll find that Emacs Lisp is quite similar in terms of language architecture. The only big differences are the wide variety of specialized functions available in Emacs Lisp. As I've been working hard on trying to master Emacs, I've got a nice little configuration file built up from my experiments. Go ahead and use it to follow along with these examples, or as a basis for your own Emacs customization files. (Please note that some of the examples below have been refactored and in some cases combined in my configuration file.)

Sites About Emacs

For those new to Emacs, here are a few websites that describe the editor family (and specific implementations) in more detail:

Sources of Help

For help using Emacs, there are many options. One is to use the mailing list for whatever version you're using. Those with GNU Emacs can use help-gnu-emacs@gnu.org. Those interested in posting bugs or reading more internal news, subscribe to emacs-devel@gnu.org. If you're using an Emacs project, such as the GNUS mail and news reader, try subscribing to that project's mailing list: ding@gnus.org.

There is also an IRC channel on FreeNode: #emacs. Numerous other Emacs projects have IRC channels as well, for example #gnus (also on FreeNode).

Getting To Know Emacs

The greatness of Emacs can, to the uninitiated, be astonishing to the point of paralysis. Where does one get started? Well, first you've got to learn the keystrokes. When you see "C-x" that means hold the control key and press x. The upper-case C here is called an accelerator. Another popular accelerator is "M" for meta (that is, Alt for most people or Option for Apple users). If you want to, you can prefix the next keystroke by pressing escape, rather than holding down meta. In the event of a longer keystroke sequence, like "C-x C-f" just do the first stroke then perform the second stroke. Simple, right?

To really start learning Emacs, try hitting "C-h t" for the Emacs learn-by-doing tutorial. Once you've worked your way through that, you're pretty much good to start editing. Because Emacs is entirely self-documenting, help can be obtained at any time for nearly any function, variable, or keybinding. For example, to find out what keys currently do what, type "C-h b" (all the help keybindings start with "C-h"). And then that's pretty much it. You can happily type your day away and whenever you get stuck, just invoke one of these help keystrokes to find out what your mind is lacking.

Swap Those Control & Caps Lock Keys!

After a few days of otherwise joyful Emacs use, you may find that your pinky finger screams in anguish every time you reach for the control key. Since Emacs makes frequent use of control sequences, avoiding pain and the danger of repetitive injury strain (an ailment that afflicts some of the greatest Unix hackers) is very important. Nearly all real Unix keyboards (like the incredibly cool Happy Hacking Keyboard) put the all-important control key on the home row to help alleviate these problems, but PC keyboards annoyingly stick the control key in the very farthest corners, making life worse for Emacs users. But if you're on Unix, fixing this problem is easy: just remap the keys!

Using xmodmap

If you're using the X window system, you can use the xmodmap program to remap your keyboard. Doing this is fairly straight forward, just place the following lines into your $HOME/.xmodmaprc file:

! swap left control and caps lock

remove Lock = Caps_Lock
remove Control = Control_L

keysym Control_L = Caps_Lock
keysym Caps_Lock = Control_L

add Lock = Caps_Lock
add Control = Control_L

Now add the following line to your .xinitrc or .xsession file: "xmodmap $HOME/.xmodmaprc". The next time you start X, pressing your left control key will set the caps lock, and holding the caps lock key will set the control accelerator. Yippie!

Using setxkbmap

The program setxkbmap can do a lot of cool things, including swapping the Control and Caps Lock keys. To do so, use the following incantation:

$ setxkbmap -option ctrl:swapcaps

Swapping Control And Caps Lock On The BSD Virtual Terminal

To switch the functions of your caps lock and control keys on the BSD virtual terminal, you need to play with the keymap used by the console system in use. On systems like NetBSD and OpenBSD using wscons can very easily do this through the wsconsctl program. English keyboard layouts have builtin options for swapping the caps lock and control keys. These are specified with the extension ".swapctrlcaps" to the normal keymap. To use them, set the keyboard encoding value in NetBSD like so: "wsconsctl -w encoding=us.swapctrlcaps" or in OpenBSD like this: "wsconsctl keyboard.encoding=us.swapctrlcaps".

If on the other hand, you happen to be using syscons on FreeBSD, the process is a little more involved, but still very easy. Just find the file that corresponds to the keymap you are currently using in the /usr/share/syscons/keymaps directory. Copy this file and swap the lines that indicate the left control and caps lock keys. If you're using the US ISO keymap, left control is keycode 029 and caps lock is keycode 058. Swap these code values so that caps lock is set to code 029 and left control is code 058. Then save the result into a new file in the same directory, maybe with a name like "us.swapctrlcaps.kbd". Now use kbdcontrol to install the new keymap: "kbdcontrol -l us.swapctrlcaps". If you're shy about editing important files (what?) then you can download my swapped keymap based on the US ISO keymap.

Unicode & XFT Support

The very latest development version of Emacs (this has a version number starting with 23) has continued new Unicode support, as well as experimental support for XFT fonts. To check out these developments and see how they work for your system, first check out the code from CVS, using the emacs-unicode-2 branch.

cvs -z3 -d:pserver:anonymous@cvs.savannah.gnu.org:/sources/emacs co -r emacs-unicode-2 emacs

Now run ./configure like usual, but make sure to add the options that enable XFT fonts. To do this, you must be building with GTK support. Then add the options --enable-font-backend and --with-xft. Lastly, build like usual (using make bootstrap and make install).

You also need to enable XFT support at runtime by passing the --enable-font-backend support to Emacs when you start it. (Note: In 23.0.50 and newer, you no longer have to supply this option at run time.) You'll also have to set the font, either by passing it on the command line (via the --font option) or through your X resources file. To use the latter method, put the following into your .Xresources file and run xrdb like usual:

Emacs.font: DejaVu Sans Mono-10

Now sit back and enjoy those beautiful smoothed fonts!

Fontifying Special Words

Vim and some other editors have builtin support for highlighting special words like TODO and FIXME in source code files. It's somewhat surprising, considering everything can do right out of the box, that Emacs doesn't have this feature by default. But like pretty much anything else in Emacs you can add it yourself with little hassle.

Essentially, what you have to do is add a special font-lock keyword for the phrases you want to highlight. This is easily enough done with the font-lock-add-keywords function, but we run into a little problem when using this method. It can only change one mode at a time! Now it's Lisp to the rescue with the mapcar function, which takes a given function and applies it to each element in a given list. Remembering to set up a separate face for our special words first, we can do something like this:

(make-face 'special-words)
(set-face-attribute 'special-words nil
            :foreground "White" :background "Firebrick")
(let ((prog-modes '( c-mode c++-mode java-mode ada-mode sh-mode tcl-mode
                     cperl-mode python-mode ruby-mode lisp-mode ))
                  (pattern "\\<\\(FIXME\\|TODO\\|NOTE\\|WARNING\\):"))
(mapcar
  (lambda (mode)
    (font-lock-add-keywords mode `((,pattern 1 'special-words prepend))))
      prog-modes))

Notice the list prog-modes which contains all the modes we want to highlight these words for. The regex we're using is stored in the variable pattern. Then it's a simple matter of running each of these modes in turn through the lambda function we provide to activate highlighting on the specified pattern.

Handling A Bunch Of Major Modes

Since the main power of Emacs lies in its extensibility, you may find (over time) that you build up quite a collection of things to autoload for different file extensions. For example, I have external major modes for CSS, FVWM, Lua, Perl, PHP, Prolog, Python, and Ruby. It's a complete pain to have to enter these all manually into Emacs' configuration, and luckily with a little work you can streamline it easily.

(mapcar
(lambda (mode-list)
(progn
(autoload (car mode-list) (symbol-name (car mode-list))
(concat "Major mode for editing " (cadr mode-list) "source code."))
(add-to-list 'auto-mode-alist
          `(,(cadr (cdr mode-list)) . ,(car mode-list)))))
'((css-mode     "Cascading Style Sheets"  "\\.css$")
  (fvwm-mode    "FVWM Configuration"      "\\.fvwm/config$")
  (lua-mode     "Lua"                     "\\.lua$")
  (cperl-mode   "Perl"                    "\\.p[lm]$")
  (php-mode     "PHP"                     "\\.php$")
  (prolog       "Prolog"                  "\\.pdb$")
  (python-mode  "Python"                  "\\.py$")
  (ruby-mode    "Ruby"                    "\\.rb$")))</pre>

This is similar to the snippet above for fontifying special words in source code. Here we apply a lambda function to each element in a list of lists. Each sublist (as it were) contains the symbol for the mode, a very brief string description, and a regexp to match for autoloading it. Simple enough, right?

Automatic Boilerplates

Emacs provides support for an auto-insert-mode to automatically add boilerplate code to a new file. Which file is used depends on the auto-insert-alist variable, which is a list of associated lists. There are two ways to do the dotted-list, which you can read about in the documentation for the variable; I use the (REGEX . COMMAND) form. Here we go!

(require 'autoinsert)
(setq auto-insert-directory "~/templates/")
(setq auto-insert-query nil)
(defun template-list (insert-directory)
(let (lst)
  (dolist (elt (directory-files insert-directory nil "[^\\.]" nil) lst)
  (setq lst (append lst `((,(concat "\\." elt "$") . ,elt)))))))

(setq auto-insert-alist (template-list auto-insert-directory))
(auto-insert-mode)

The first line requires that auto-insert support be present. The second sets the directory where all the boilerplate files are stored. The third line indicates that boilerplates should be automatically inserted without prompting.

The template-list function is really the heart of the customization. It takes the boilerplate directory as it's parameter, and creates a null list to hold what will become auto-insert-alist. For each file in the directory that doesn't start with a dot, it adds a dotted-list to the auto-insert-alist: this dotted-list consists of regex matching the filename extension, and the associated file to use as a boilerplate. Since the templates are named in files which match the extension, only a bit of manipulation is necessary to come up with a regex via the concat function.

Automatic Indentation

If you write a lot of code in Emacs, you'll probably tire quickly of having to hit tab after starting each new line in your source. To get around this, you could teach yourself to use "C-j" instead of RET to insert newlines, but that's somewhat counter-intuitive. Isn't there a way to just auto-indent code? Yes, there is. Just rebind the return key to whatever "C-j" normally does. The lookup-key function will help you figure out what function to bind to.

One might ask why we don't simply swap the values for "C-j" and RET. The answer is that if we do that, nested hook calls (like c-mode-hook before java-mode-hook) will cause the swap to happen twice, the second reversing the effects of the first. If you want, you can assign the value of RET to an unbound key like "C-'" (that is, control apostrophe) before reassigning RET, or just simply use "M-x newline" whenever you want to insert only a newline.

Using local-set-key we can reassign the RET key to whatever is normally invoked by pressing "C-j". To figure out exactly what that is, we check two keymaps: the mode-specific one and the global one. Now, I've seen some people just substitute newline-and-indent for the lookup-key function here (which is the global keymap binding), but some modes (like Ruby mode) bind their own special function for "C-j". Since that's the effect we're going for here, that's the method I've used. Hence, we check the local mode keymap before the global one.

(mapcar
(lambda (mode)
(let ((mode-hook (intern (concat (symbol-name mode) "-hook")))
  (mode-map  (intern (concat (symbol-name mode) "-map"))))
  (add-hook mode-hook
     `(lambda nil
       (local-set-key (kbd "RET")
          (or (lookup-key ,mode-map "\C-j")
              (lookup-key global-map "\C-j")))))))
         '(ada-mode c-mode c++-mode cperl-mode emacs-lisp-mode java-mode html-mode
           lisp-mode php-mode ruby-mode sh-mode sgml-mode))

Unfortunately, this method creates a little more work for us, because we have to keep track not only of the mode to use, but also the keymap we're looking at. To keep from having to explicitly type both of these in the list parameter to mapcar, I've done a bit of symbol magic. (This took me almost two hours to finally figure out so I'm pretty proud of it.) Inside the mapcar function we create two variables mode-hook and mode-map which evaluate to symbols that represent the appropriate hook and keymap, respectively. In constructing these symbols, we take the current value from mapcar and create a symbol by appending either "-hook" or "-map" to the end of it. We can safely use this to determine the correct hook and keymap symbols for a given mode because of the convention that nearly everybody uses for defining mode hooks and keymaps. For example, when mapcar gives us lisp-mode we convert that to a string, stick "-map" onto the end of it, intern a new symbol from the result, and assign that symbol to the mode-map variable. Then we evaluate this variable in the body of the lambda expression (that will be added to the hook) and hence make the correct named keymap (lisp-mode-map) appear verbatim inside the hook's lambda!

Using Exuberant Ctags for Speedbar

Alright, we can all agree that Etags is great, but quite frankly, Exuberant Ctags is better. But of course, Emacs is so configurable that you can have Speedbar use whichever tagging facility your heart desires. Setting it up to use Exuberant Ctags instead of the default Etags is simple enough:

(setq speedbar-use-imenu-flag nil)
(setq speedbar-fetch-etags-command "/usr/bin/ctags-exuberant")
(setq speedbar-fetch-etags-arguments '("-e" "-f" "-"))

Set these parameters before you launch Speedbar.

Sending Mail Messages

Compared to reading mail, sending it is rather easy to set up. First, you need to determine how you'll be sending your message: using a local program (like sendmail) or through SMTP (to a remote host). If you answered the former, you're pretty much all set right out of the box! Check the customize / applications / mail buffer for configuration. But if you chose the latter, transmitting mail via an external SMTP host, you've got a bit more work to do.

If your SMTP host requires authentication (which most seem to do nowadays), and if you're using GNU Emacs 21 or older, you need to fetch some more up-to-date Elisp files. Simon Josefsson and Stephen Cranefield have made modifications to the Emacs smtpmail source to add support for SMTP authentication. You can find information on <a class="external" href="http://josefsson.org/emacs-rfc2554.html">Josefsson's Emacs RFC-2554</a> page. It basically boils down to downloading and enabling three different Emacs Lisp source files. Just grab them from Emacs CVS and place them into the same directory; then prepend their location to the beginning of your load-path. When their functionality is required, the new files will be used instead of the old ones. (To boost speed a bit so its more on par with the builtin smtpmail functionality, you can call byte-compile-file on them from Emacs.) Now you can use SMTP authentication to send email messages!

Sending email via SMTP requires some configuration in your <code class="filename">.emacs</code> file. Here's a decent example:

(setq message-send-mail-function 'smtpmail-send-it)
(setq smtpmail-default-smtp-server "smtp.host.name")
(setq smtpmail-local-domain "local.host.name")
;; (setq smtpmail-debug-info t) ; puts debug info in *trace ...* buffer
(setq smtpmail-auth-credentials '(("smtp.host.name" 25 "user" "password")))

(setq mail-host-address "local.host.name")</pre>

This is pretty self-explanatory. The debugging functionality is helpful is you run into some kind of an error from the SMTP server, as the *trace ...* buffer prints out the entire transcript from the client/server interaction. You can now use the command message-mail to compose an email message. Use <code class="keystroke">C-c C-c</code> to send it via the enabled method.

Reading Mail Messages

There are several different ways to read your email from Emacs, the most popular of which is GNUS. But GNUS is by design a news reader, meaning that there are some hurdles to overcome if you are familiar with more standard email readers like Mutt or Thunderbird. The first thing you have to do is tell GNUS how to fetch and store your email; this is done by setting the gnus-select-method variable. (Actually this variable represents the primary method for getting messages; secondary methods are set through the gnus-secondary-select-methods variable.) Next you can set where your mail goes via the nnmail-split-methods variable. This is a list whose elements are lists which contain a target group and a regex to match. Any messages matching the regex will be stored in the given group. The last entry should have an empty regex so all remaining mail will go to that group.

Since GNUS behaves like a news reader, you have to subscribe to the groups which will receive email. You can subscribe to a group by using <code class="keystroke">S s</code> and then typing the name of that group. Note that by default only groups with unread messages will be displayed in the group buffer. To show all groups (both read and unread) press <code class="keystroke">L</code>. You can select a particular group with <code class="keystroke">&lt;RET&gt;</code> and unsubscribe from it by placing the cursor on its line and pressing <code class="keystroke">u</code>.

(require 'gnus)

(setq gnus-directory "~/email/")
(setq gnus-fetch-old-headers t)
(setq gnus-inhibit-startup-message t)
(setq gnus-outgoing-message-group "sent")
(setq gnus-select-method '(nnfolder ""))
(setq gnus-treat-display-smileys nil)

(setq nndraft-directory "~/email/")

(setq nnmail-split-methods
'(("spam" "^Subject: \\[SPAM\\]")
("inbox" "")))

(setq gnus-group-line-format "%M%S%p%P%3N / %3R : %(%-16G%)\n")

(add-hook 'gnus-group-mode-hook
  #'(lambda nil (setq show-trailing-whitespace nil)))
(add-hook 'gnus-summary-mode-hook
  #'(lambda nil (setq show-trailing-whitespace nil)))
(add-hook 'gnus-article-mode-hook
  #'(lambda nil (setq show-trailing-whitespace nil)))

Here's an example configuration. I put all of these definitions into my <code class="filename">.emacs</code> file; some of these variables (like inhibit-startup-message) have to be defined there, but others don't. The hooks at the end are to shut off trailing whitespace display when using GNUS, because for some reason a lot of email has whitespace at the end of lines.

Mail Aliases

People don't like to have to remember long complex strings of sometimes random data; that's why programmers invented website bookmarks and mail aliases. There's a couple different ways to use them in GNUS. One is to use the Insidious Big Brother Database (perhaps better known as BBDB) to manage your contacts in a small database. Another option is to use the simple mail alias system provided by your <code class="filename">.mailrc</code> file. Because it's simpler, more portable, and doesn't require code outside the GNU Emacs base, I'm only going to spend time on this second method.

If you've used other mail programs, you may already have some aliases stored in your <code class="filename">.mailrc</code> file. In case you don't, the syntax is simple: just create a line that takes the form alias SHORT LONG, where SHORT is the shortened alias name, and where LONG is the actual email address. Once you've got that file, you again have two options for using it.

One method is really truly using old-school mail aliases, where the aliases are expanded just before the message is sent. You don't have to do anything extra to enable this &ndash; it should happen by default. The second method is somewhat more useful: it treats mail aliases as abbreviations, expanding them automatically when you insert a word-delimiting character like the comma or space. In order to activate this functionality, you have to set a hook for message-mode:

(add-hook 'mail-mode-hook 'mail-abbrevs-setup)

Now when you're typing in recipient addresses, if you type the name of an alias from your <code class="filename">.mailrc</code> file and hit comma or space, the alias will be expanded to the address it represents. Much faster than searching through an address book, and certainly much easier than having to remember all those crazy addresses people make up!

NNTP Troubles

With GNUS 5.11 running under Emacs 22.0.94.1 and Emacs 23.0.0.1 I have a problem regarding my NNTP connection. As far as I can tell, GNUS keeps the connection to the NNTP server open for as long as possible, but the NNTP server will stop paying attention after a while. GNUS doesn't detect this, and when you try to refresh your Usenet subscriptions, GNUS will hang, waiting for the server to send it data, until you eventually C-g it into submission. To automatically kill the hang, set the variable nntp-connect-timeout to some value in seconds &mdash; when this period of time expires, GNUS will give up.

That doesn't actually solve the problem, though, because the connection is still active, and GNUS will continue to try to get data from this connection. To refresh your Usenet subscriptions, you need to close the connection to the NNTP server. This can be done either by calling the nntp-close-server function, or by entering the server buffer and closing it there. After the server connection is closed, you can re-open it (again, either by the nntp-open-server function or through the server buffer) and everything will work again. Until the server lets the connection die again.

(setq nntp-connection-timeout 30)
(add-hook 'gnus-after-getting-new-news-hook 'nntp-close-server)
(add-hook 'gnus-started-hook 'nntp-close-server)

One decent fix is to use the above server-close method, adding nntp-close-server to the gnus-after-getting-new-news-hook. This will automatically close the connection after GNUS is done checking the NNTP server; and the next time you go to check for new news, the server will automatically be re-opened. So far, this seems to be an effective workaround for the NNTP connection problem.

The Emacs Multimedia System

EMMS is an Emacs-based front-end to play multimedia files. EMMS reads metadata from files and uses that information to list them in the current playlist. Unfortunately, it's a bit slow at reading that metadata, so to increase the speed we can bulk read a bunch of the data ahead of time and store it in EMMS' cache using this Python script I wrote.

Installation

You can download EMMS using Darcs, a distributed version control system written in Haskell. To fetch the source code, use the following command:

$ darcs get http://www.kollektiv-hamburg.de/~forcer/darcs/emms

You'll most likely need to edit the Makefile before you build. If you get errors about nnheader-concat not being defined, run this code snippet within the emms directory to convert that function call into an equivalent, more widely available alternative:

sed -e 's/nnheader-concat \([^ ]\+\)/concat (file-name-as-directory \1)/' \
  -i.bak `grep -Hl "nnheader-concat" *.el`

Now you can do the usual make && sudo make install goodness. Note that this is fixed in more recent versions.

Keybindings

(global-set-key (kbd "<f1>") 'emms-previous)
(global-set-key (kbd "<f2>") 'emms-start)
(global-set-key (kbd "<f3>") 'emms-stop)
(global-set-key (kbd "<f4>") 'emms-next)

Players

The following I use for defining which players will be used. You'll have to throw the mplayer entries in if you want to do things like play Internet radio.

(setq emms-player-list '(emms-player-mpg321
                         emms-player-ogg123
                         emms-player-mplayer-playlist
                         emms-player-mplayer))

Modeline Display

I like to see what's playing in the modeline. This function mostly works, only I can't figure out why it disappears when the track changes by itself.

(setq emms-mode-line-mode-line-function
      (lambda nil
        (let ((track (emms-playlist-current-selected-track)))
          (let ((title (emms-track-get track 'info-title)))
            (if (not (null title))
                (format emms-mode-line-format title)
              (if (not (null (string-match "^url: " (emms-track-simple-description track))))
                  (format emms-mode-line-format "Internet Radio")
                (format emms-mode-line-format "Unknown")))))))

Track Description

This function describes how to display a track entry in the playlist. I like to have mine in the format "Artist: Album - [Num] Title".

(setq emms-track-description-function
      (lambda (track)
        (let ((artist (emms-track-get track 'info-artist))
              (album  (emms-track-get track 'info-album))
              (number (emms-track-get track 'info-tracknumber))
              (title  (emms-track-get track 'info-title)))
          (if (and artist album title)
              (if number
                  (format "%s: %s - [%03d] %s" artist album (string-to-int number) title)
                (format "%s: %s - %s" artist album title))
            (emms-track-simple-description track)))))

Additionally, we can change the face for the playlist to be a little cooler.

(set-face-attribute 'emms-playlist-track-face    nil :font "DejaVu Sans-10")
(set-face-attribute 'emms-playlist-selected-face nil :background "White" :foreground "Firebrick")

Adding Tracks from Dired

You can add your own keybinding to Dired to make it add the tracks in a subdirectory when, for example, you press the "e" key. Here's the method to do that:

(defun dired-add-to-emms-playlist nil
  "Adds directory tree rooted at the selected directory to the current EMMS playlist."
  (interactive)
  (let ((file (expand-file-name (dired-get-filename))))
    (if (and file (file-directory-p file))
        (emms-add-directory-tree file)
      (emms-add-file file))))

(add-hook 'dired-mode-hook 'my-dired-mode-hook)

(defun my-dired-mode-hook()
  (define-key dired-mode-map (kbd "e") 'dired-add-to-emms-playlist))

Now whenever you're browsing your music hierarchy in Dired you can press the "e" key when the cursor is over a directory to add that entire directory's (and subdirectories') contents to the playlist. If you press "e" when over a regular file, that file will be added to the playlist.

Metadata Loading

This code is my own custom metadata loader. I wrote a Python script which examines a file and gathers the metadata for that file. This I found much more convenient, accurate, and generally faster than the loaders used by EMMS by default. Plus I could easily refactor this into a cache preloader.

(defun metadata (track)
  (when (eq 'file (emms-track-type track))
    (with-temp-buffer
      (when (zerop
             (apply (if (fboundp 'emms-i18n-call-process-simple)
                        'emms-i18n-call-process-simple
                      'call-process)
                    "metadata.py"
                    nil t nil
                    (list (emms-track-name track))))
        (goto-char (point-min))
        (while (looking-at "^\\([^=\n]+\\)=\\(.*\\)$")
          (let ((name (intern (match-string 1)))
                (value (match-string 2)))
            (when (> (length value)
                     0)
              (emms-track-set track
                              name
                              (if (eq name 'info-playing-time)
                                  (string-to-number value)
                                value))))
          (forward-line 1))))))

(setq emms-info-functions '(metadata))

Other Useful Modes

imaxima

imaxima is a mode for running Maxima within Emacs, and capturing the output as LaTeX images embedded into the frame. This lets you run something very similar to wxMaxima from within Emacs, only the output is prettier and can be readily converted into LaTeX code. You can grab imaxima mode from the author's website or from my unofficial mirror section. When you compile this, if you have your Emacs installed in a non-standard location, you will want to run the configure script with the following options:

$ export EMACS=/opt/emacs/bin/emacs
$ ./configure --prefix=/opt/emacs

Doxymacs

If you want to highlight Doxygen comments in your source code, Doxymacs is where it's at.

Cool Stuff & the Kitchen Sink

So you can use Emacs to edit text. That's good. You can also use Emacs to handle mail and news. That's great. What else can you use Emacs for?

Unofficial Mirror

Here are some archives of Emacs packages that I'm mirroring unofficially.

Screenshots

But Isn't Emacs Too Big?

If you're an unbeliever, and think Emacs is too large and unwieldy, consider the following:

20 MB is 10 cent worth of disc space. For these 10 cents, you get the most powerful text editor in the world, an IDE that supports more programming languages "out of the box" than all other IDEs in the world combined, the most feature-rich News and Mail reader ever, a web browser, a calendar that knows more cultures than you have heard of, and your own personal psychotherapist. If you think 10 cents is too much for a text editor that has been specially optimized for every text processing need in your remaining life, you ought to reevaluate your value system.

—Per Abrahamsen

Also consider the following interesting (non-scientific) memory statistics. They come from GNU Emacs 22.0.94.1 running under Linux 2.6.17 on an i686 machine:

Program & Features Virtual Memory Size (KB) # of Emacsen
GNU Emacs + GTK + Speedbar + GNUS 31768 1
Opera + shared QT library 117972 3.7
Eclipse 3.2 + Java 6 + SWT (GTK x86) 489264 15.4
Firefox 2.0 + Web Developer + NoScript 168412 5.3
The GIMP 2.2 + Scripts 79200 2.5
Quod Libet + 3000 songs 215044 6.8

How many Emacsen are you running right now?

<a href="http://www.gnu.org/software/emacs/"><img class="float" src="/images/logos/emacs.png" alt="[GNU Emacs Logo]"/></a>