🕷 zenspider.com

by ryan davis



sitemap
Looking for the Ruby Quickref?

My Emacs Setup, pt 1

Published 2013-06-14 @ 12:00

Tagged emacs

This is part of the My Emacs Setup series.

Evan Light requested that I blog about my emacs setup and I’ve been sorta meaning to do that… so here goes.

First off, all of my elisp code is available on github. My emacs setup is very organic and has a fair amount of cruft here and there… so you may want to wait for the blog posts rather than diving in.

We’ll start at the top, with my .emacs.el file. To start, everything I have is under version control. It is symlinked in to the root of my home dir. Symlinking is done via ~/Bin/Config/setup, which is also under version control. This makes it easy to get up and running on a new login.

Let’s see what I’ve got:

emacs.el

rwd-aliases.el             rwd-autoloads.el rwd-bell.el
rwd-dirs.el                rwd-ess.el       rwd-expand.el
rwd-history.el             rwd-irc.el       rwd-keys.el
rwd-keywords.el            rwd-misc.el      rwd-modes.el
rwd-oddmuse.el             rwd-p4.el        rwd-packages.el
rwd-paste.el               rwd-ruby.el      rwd-tags.el
rwd-templates.el           rwd-text.el      rwd-todo.el
rwd-variables.el           rwd-windows.el   

hooks/                     misc/

autotest.el                compose-hooks.el loaddefs.el
multi-replace-regexp.el    neko.el          override-keymaps.el
project-local-variables.el rcov-overlay.el  sanity.el
toggle.el

I split up my stuff into a LOT of smaller files. If it is prefixed with “rwd-“ then it is one of my configs. If it isn’t, it is probably a library I’ve written. I’ll go into detail on a lot of these files in subsequent posts. For now, let’s get the top-level architecture out of the way.

OK. Elisp time! Digging into emacs.el:

1
(require 'autoload)                     ; = ;;;###autoload

Nearly everything I do is done via autoload. What does that mean? Autoload is a processor “interprets magic cookies of the form ‘;;;###autoload’ in lisp source files in various useful ways”. But… What does that mean? It means I can throw all of my stuff in smaller files but it all acts like it is thrown together in one large emacs file. It does a good job of not loading those files until they’re actually called upon.

1
2
3
4
5
6
7
8
9
(defvar user-init-dir (file-name-directory
                       (or (file-symlink-p user-init-file) user-init-file))
  "Root directory of emacs.el, after following symlinks, etc.")

(add-to-list 'load-path user-init-dir t)
(add-to-list 'load-path (concat user-init-dir "third-party") t) ; TODO: remove

(load (concat "misc/" (symbol-name system-type)) t)                ;; misc/darwin
(load (concat "misc/" (car (split-string (system-name) "\\."))) t) ;; misc/greed

This sets user-init-dir which I use in various places. Remember, my emacs file is a symlink so this resolves to the real location. I use that to add 2 items to my load-path and then load OS and host specific files, if they exist.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
(autoload 'find-lisp-find-files "find-lisp" nil t)
(autoload 'find-lisp-find-files-internal "find-lisp" nil t)

(defun rwd-recompile-init ()
  (interactive)
  (byte-recompile-directory (expand-file-name user-init-dir) 0))

(setq generated-autoload-file "loaddefs.el") ;; HACK for emacs 24.1

(defun rwd-autoloads ()
  "Regenerate the autoload definitions file if necessary and load it."
  (interactive)
  (let* ((autoload-file (concat user-init-dir generated-autoload-file)))
    (if (or (not (file-exists-p autoload-file))
            (catch 'newer
              (dolist (file (find-lisp-find-files user-init-dir "\\.el$"))
                (if (file-newer-than-file-p file autoload-file)
                    (throw 'newer file)))))
        (let ((generated-autoload-file autoload-file)
              (el-root-subdirs (find-lisp-find-files-internal
                                user-init-dir
                                'find-lisp-file-predicate-is-directory
                                'find-lisp-default-directory-predicate)))
          (apply 'update-directory-autoloads (cons user-init-dir el-root-subdirs))
          (load autoload-file) ; helps rwd-recompile-init dependencies
          (rwd-recompile-init)))
    (message "loading autoloads")
    (load autoload-file)
    (message "done loading autoloads")))

(rwd-autoloads)

This is the magic. The real power is in rwd-autoloads. It regenerates the autoload file for my whole elisp tree. All functions and blocks marked with the magic cookie are autoloaded into ~/Bin/elisp/loaddefs.el. This code could probably be written cleaner, but it works and stays out of my way.

rwd-recompile-init recompiles everything (as needed) in my ~/Bin/elisp directory. This speeds up emacs by a sizable measure.

1
(load "rwd-packages")

I’ll go into detail on this in a subsequent post. This is where all my third-party packages are loaded and maintained.

1
(rwd-autohooks)

I’ll go into detail on this in a subsequent post. This is where all my mode hooks are defined on a file-per-mode basis. It makes it really easy to break up and maintain all my hooks.

1
(custom-set-variables ...)

Lots of customize variables. I use customize as much as possible because it is easier to maintain and you get doco right there to keep you on track. It also keeps everything in one place.

1
(custom-set-faces ...)

This is just minor tweaks to the emacs defaults. I find emacs’ default color theme to be very readable, but it breaks some of my rules. Namely, red should only be for bad things, not strings or comments.

1
(put 'narrow-to-region 'disabled nil)

There are some actions that emacs finds “scary” to newbs. This is one of them and I’ve disabled the warning it gives when you try to narrow a region. You should try narrow-to-region. It is great for focusing on stuff in a large file.