Aaron Bedra's Emacs 24 Configuration

Table of Contents

Configuration

Emacs is a special beast. Taming it takes a lot of care. In an attempt to document/explain/share with the rest of the world, this is my attempt at configuration as a literate program. It also shows off the awesome power of org-mode, which makes all of this possible.

User details

Emacs will normally pick this up automatically, but this way I can be sure things are set properly.

(setq user-full-name "Aaron Bedra")
(setq user-mail-address "aaron@aaronbedra.com")

Environment

There are plenty of things installed outside of the default PATH. This allows me to establish additional PATH information so that everything functions as it should. Require common lisp mode. Emacs lisp is really only a subset of common lisp, and I need to have some of the additional functionality to make this configuration and its dependencies work properly.

(setenv "PATH" (concat "/usr/local/bin:" (getenv "PATH")))
(require 'cl)

Package Management

Since Emacs 24, the emacs lisp package archive (elpa) is included by default. This provides a nice way to install the additions needed to make things work properly. Since the default package archive doesn't include everything I need, the marmalade, and melpa repositories are also added.

(load "package")
(package-initialize)
(add-to-list 'package-archives
             '("marmalade" . "http://marmalade-repo.org/packages/"))
(add-to-list 'package-archives
             '("melpa" . "http://melpa.milkbox.net/packages/") t)

(setq package-archive-enable-alist '(("melpa" deft magit)))

Define default packages

This is the list of packages used in this configuration.

(defvar abedra/packages '(ac-slime
                          auto-complete
                          autopair
                          clojure-mode
                          clojure-test-mode
                          coffee-mode
                          deft
                          gist
                          go-mode
                          haml-mode
                          haskell-mode
                          htmlize
                          magit
                          markdown-mode
                          marmalade
                          nrepl
                          o-blog
                          org
                          paredit
                          puppet-mode
                          restclient
                          rvm
                          smex
                          sml-mode
                          yaml-mode)
  "Default packages")

Install default packages

When Emacs boots, check to make sure all of the packages defined in abedra/packages are installed. If not, have elpa take care of it.

(defun abedra/packages-installed-p ()
  (loop for pkg in abedra/packages
        when (not (package-installed-p pkg)) do (return nil)
        finally (return t)))

(unless (abedra/packages-installed-p)
  (message "%s" "Refreshing package database...")
  (package-refresh-contents)
  (dolist (pkg abedra/packages)
    (when (not (package-installed-p pkg))
      (package-install pkg))))

Start-up options

Splash Screen

I want to skip straight to the scratch buffer. This turns off the splash screen and puts me straight into the scratch buffer. I don't really care to have anything in there either, so turn off the message while we're at it. Since I end up using clojure-mode most of the time, set the default mode accordingly.

(setq inhibit-splash-screen t
      initial-scratch-message nil)

(when (locate-library "clojure-mode")
  (setq initial-major-mode 'clojure-mode))

Scroll bar, Tool bar, Menu bar

Emacs starts up with way to many things. Turn off the scroll bar, menu bar, and tool bar. There isn't really a reason to have them on.

(scroll-bar-mode -1)
(tool-bar-mode -1)
(menu-bar-mode -1)

Marking text

There are some behaviors in Emacs that aren't very intuitive. Since I pair with others that don't know how Emacs handles highlighting, treat regions like other text editors. This means typing when the mark is active will write over the marked region. Also, make the common highlighting keystrokes work the way most people expect them to. This saves a lot of time explaining how to highlight areas of text. Emacs also has it's own clipboard and doesn't respond to the system clipboard by default, so tell Emacs that we're all friends and can get along.

(delete-selection-mode t)
(transient-mark-mode t)
(setq x-select-enable-clipboard t)

Display Settings

I like a few slight modifications to the default display. First, a minor tweak to the frame title. It's also nice to be able to see when a file actually ends. This will put empty line markers into the left hand side.

(when window-system
  (setq frame-title-format '(buffer-file-name "%f" ("%b"))))

(setq-default indicate-empty-lines t)
(when (not indicate-empty-lines)
  (toggle-indicate-empty-lines))

Indentation

There's nothing I dislike more than tabs in my files. Make sure I don't share that discomfort with others.

(setq tab-width 2
      indent-tabs-mode nil)

Backup files

Some people like to have them. I don't. Rather than pushing them to a folder, never to be used, just turn the whole thing off.

(setq make-backup-files nil)

Yes and No

Nobody likes to have to type out the full yes or no when Emacs asks. Which it does quite often. Make it one character.

(defalias 'yes-or-no-p 'y-or-n-p)

Key bindings

Miscellaneous key binding stuff that doesn't fit anywhere else.

(global-set-key (kbd "RET") 'newline-and-indent)
(global-set-key (kbd "C-;") 'comment-or-uncomment-region)
(global-set-key (kbd "M-/") 'hippie-expand)
(global-set-key (kbd "C-+") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)

Misc

Turn down the time to echo keystrokes so I don't have to wait around for things to happen. Dialog boxes are also a bit annoying, so just have Emacs use the echo area for everything. Beeping is for robots, and I am not a robot. Use a visual indicator instead of making horrible noises. Oh, and always highlight parentheses. A person could go insane without that.

(setq echo-keystrokes 0.1
      use-dialog-box nil
      visible-bell t)
(show-paren-mode t)

Vendor directory

I have a couple of things that don't come from package managers. This sets up the directory and makes sure everything is loaded.

(defvar abedra/vendor-dir (expand-file-name "vendor" user-emacs-directory))
(add-to-list 'load-path abedra/vendor-dir)

(dolist (project (directory-files abedra/vendor-dir t "\\w+"))
  (when (file-directory-p project)
    (add-to-list 'load-path project)))

Themes

Load the wombat theme on start-up.

(load-theme 'wombat t)

Org mode

org-mode is one of the most powerful and amazing features of Emacs. I mostly use it for task/day organization and generating code snippets in HTML. Just a few tweaks here to make the experience better. Enable logging when tasks are complete. This puts a time-stamp on the completed task and lets org-agenda mark it. Since I usually am doing quite a few things at once, I added the INPROGRESS keyword and made the color blue. Setup a default agenda file for org-agenda called personal.org.

(global-set-key (kbd "C-c a") 'org-agenda)
(setq org-log-done t)
(setq org-todo-keywords
      '((sequence "TODO" "INPROGRESS" "DONE")))
(setq org-todo-keyword-faces
      '(("INPROGRESS" . (:foreground "blue" :weight bold))))
(setq org-agenda-files (list "~/Dropbox/org/personal.org"))

org-babel

org-babel is a feature inside of org-mode that makes this document possible. It allows for embedding languages inside of an org-mode document with all the proper font-locking. It also allows you to extract and execute code. It isn't aware of Clojure by default, so the following sets that up.

(require 'ob)

(org-babel-do-load-languages
 'org-babel-load-languages
 '((sh . t)))

(add-to-list 'org-babel-tangle-lang-exts '("clojure" . "clj"))

(defvar org-babel-default-header-args:clojure
  '((:results . "silent") (:tangle . "yes")))

(defun org-babel-execute:clojure (body params)
  (lisp-eval-string body)
  "Done!")

(provide 'ob-clojure)

(setq org-src-fontify-natively t)
(setq org-confirm-babel-evaluate nil)

Utilities

deft

deft provides random note taking with history and searching. Since I use org-mode for everything else, I turn that on as the default mode for deft and put the files in Dropbox.

(setq deft-directory "~/Dropbox/deft")
(setq deft-use-filename-as-title t)
(setq deft-extension "org")
(setq deft-text-mode 'org-mode)

Smex

smex is a necessity. It provides history and searching on top of M-x.

(setq smex-save-file (expand-file-name ".smex-items" user-emacs-directory))
(smex-initialize)
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "M-X") 'smex-major-mode-commands)

Ido

Ido mode provides a nice way to navigate the filesystem. This is mostly just turning it on.

(ido-mode t)
(setq ido-enable-flex-matching t
      ido-use-virtual-buffers t)

Column number mode

Turn on column numbers.

(setq column-number-mode t)

Temporary file management

Deal with temporary files. I don't care about them and this makes them go away.

(setq backup-directory-alist `((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)))

autopair-mode

This makes sure that brace structures (), [], {}, etc. are closed as soon as the opening character is typed.

(require 'autopair)

Power lisp

A bunch of tweaks for programming in LISP dialects. It defines the modes that I want to apply these hooks to. To add more just add them to lisp-modes. This also creates its own minor mode to properly capture the behavior. It remaps some keys to make paredit work a little easier as well. It also sets clisp as the default lisp program and racket as the default scheme program.

(setq lisp-modes '(lisp-mode
                   emacs-lisp-mode
                   common-lisp-mode
                   scheme-mode
                   clojure-mode))

(defvar lisp-power-map (make-keymap))
(define-minor-mode lisp-power-mode "Fix keybindings; add power."
  :lighter " (power)"
  :keymap lisp-power-map
  (paredit-mode t))
(define-key lisp-power-map [delete] 'paredit-forward-delete)
(define-key lisp-power-map [backspace] 'paredit-backward-delete)

(defun abedra/engage-lisp-power ()
  (lisp-power-mode t))

(dolist (mode lisp-modes)
  (add-hook (intern (format "%s-hook" mode))
            #'abedra/engage-lisp-power))

(setq inferior-lisp-program "clisp")
(setq scheme-program-name "racket")

auto-complete

Turn on auto complete.

(require 'auto-complete-config)
(ac-config-default)

Indentation and buffer cleanup

This re-indents, untabifies, and cleans up whitespace. It is stolen directly from the emacs-starter-kit.

(defun untabify-buffer ()
  (interactive)
  (untabify (point-min) (point-max)))

(defun indent-buffer ()
  (interactive)
  (indent-region (point-min) (point-max)))

(defun cleanup-buffer ()
  "Perform a bunch of operations on the whitespace content of a buffer."
  (interactive)
  (indent-buffer)
  (untabify-buffer)
  (delete-trailing-whitespace))

(defun cleanup-region (beg end)
  "Remove tmux artifacts from region."
  (interactive "r")
  (dolist (re '("\\\\│\·*\n" "\W*│\·*"))
    (replace-regexp re "" nil beg end)))

(global-set-key (kbd "C-x M-t") 'cleanup-region)
(global-set-key (kbd "C-c n") 'cleanup-buffer)

flyspell

The built-in Emacs spell checker. Turn off the welcome flag because it is annoying and breaks on quite a few systems. Specify the location of the spell check program so it loads properly.

(setq flyspell-issue-welcome-flag nil)
(setq-default ispell-program-name "/usr/local/bin/aspell")
(setq-default ispell-list-command "list")

Language Hooks

Ruby

Turn on autopair for Ruby. Identify additional file names/extensions that will trigger ruby-mode when loaded.

(add-hook 'ruby-mode-hook
          (lambda ()
            (autopair-mode)))

(add-to-list 'auto-mode-alist '("\\.rake$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.gemspec$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.ru$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Rakefile" . ruby-mode))
(add-to-list 'auto-mode-alist '("Gemfile" . ruby-mode))
(add-to-list 'auto-mode-alist '("Capfile" . ruby-mode))
(add-to-list 'auto-mode-alist '("Vagrantfile" . ruby-mode))

RVM

Enable Ruby Version Manager mode and tell it to use the default Ruby.

(rvm-use-default)

YAML

Add additional file extensions that trigger yaml-mode.

(add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.yaml$" . yaml-mode))

CoffeeScript Mode

The default CoffeeScript mode makes terrible choices. This turns everything into 2 space indentations and makes it so the mode functions rather than causing you indentation errors every time you modify a file.

(defun coffee-custom ()
  "coffee-mode-hook"
  (make-local-variable 'tab-width)
  (set 'tab-width 2))

(add-hook 'coffee-mode-hook 'coffee-custom)

Markdown mode

Enable Markdown mode and setup additional file extensions. Use pandoc to generate HTML previews from within the mode, and use a custom css file to make it a little prettier.

(add-to-list 'auto-mode-alist '("\\.md$" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.mdown$" . markdown-mode))
(add-hook 'markdown-mode-hook (lambda () (visual-line-mode t)))
(setq markdown-command "pandoc --smart -f markdown -t html")
(setq markdown-css-path (expand-file-name "markdown.css" abedra/vendor-dir))

Date: 2013-07-13T15:45-0500

Author: Aaron Bedra

Org version 7.9.3f with Emacs version 24

Validate XHTML 1.0