Emacs Config

This is my emacs configuration. After many years with vim then a year with spacemacs & prelude, I came to the realisation that I needed to construct my own to really get it1.

After a few aborted attempts to split the config into separate files, I settled on the literate-programming-with-single-file approach via Sacha Chua.

Documenting this is mostly for my benefit, but I hope others might find it useful constucting their own. The live version is on GitHub, with this version updated periodically.

Not that we needed all that for the trip, but once you get locked into a serious drug collection, the tendency is to push it as far as you can.

Hunter S. Thompson, Fear and Loathing in Las Vegas


Make it easy to edit this file!

  (defun find-config ()
    "Edit config.org"
    (find-file "~/dotfiles/config.org"))

  (global-set-key (kbd "C-c I") 'find-config)

Configure package sources

Add repositories from which we'll load packages. I prefer to live on the bleeding edge so have only enabled melpa. Setting package-enable-at-startup to nil prevents a second package load and slightly improves startup time.

  (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
  (setq package-enable-at-startup nil)

Bootstrap use-package

If use-package is not installed, install it.

  (unless (package-installed-p 'use-package)
    (package-install 'use-package))

Set custom settings to load in own file

This stops emacs adding customised settings to init.el. I try to avoid using customize anyway, preferring programmatic control of variables. Creating it as a temporary file effectively disables it (i.e. any changes are session local).

  (setq custom-file (make-temp-file "emacs-custom"))

Add custom packages to load path

By default Emacs only includes files directly under user-emacs-directory (usually ~/.emacs.d/), so we need to add any folders containing custom packages.

I put my scripts under ~/dotfiles/lisp/ and symlink it with ln -s ~/dotfiles/lisp ~/.emacs.d/lisp.

  (add-to-list 'load-path "~/.emacs.d/lisp/")


Don't display the help screen on startup.

  (setq inhibit-startup-screen t)

On  I use ⌘ as meta and prefer ⌥ to do nothing so I can still insert special characters like easily.

  (setq mac-command-modifier 'meta
        mac-option-modifier 'none)

I prefer lines to wrap.

  (global-visual-line-mode 1)

Let's turn off unwanted window decoration.

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

I don't want the error bell.

  (setq ring-bell-function 'ignore)

Make the yes or no prompts shorter.

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

A common frustration with new Emacs users is the filename# files created. This centralises the backup files created as you edit.

  (setq backup-directory-alist '(("." . "~/.emacs.d/backup"))
    backup-by-copying t    ; Don't delink hardlinks
    version-control t      ; Use version numbers on backups
    delete-old-versions t  ; Automatically delete excess backups
    kept-new-versions 20   ; how many of the newest versions to keep
    kept-old-versions 5    ; and how many of the old



crux has useful functions extracted from Emacs Prelude. Set C-a to move to the first non-whitespace character on a line, and then to toggle between that and the beginning of the line.

  (use-package crux
    :ensure t
    :bind (("C-a" . crux-move-beginning-of-line)))

I never want whitespace at the end of lines. Remove it on save.

  (add-hook 'before-save-hook 'delete-trailing-whitespace)

Key chords

Key chords let us bind functions to sequential key presses like jj. It makes evil mode being turned off much more palatable.

  (use-package use-package-chords
    :ensure t
    (key-chord-mode 1))

We bind individual mode chords via use-package but some globals are useful like JJ to jump to the previous buffer.

  (defun jc/switch-to-previous-buffer ()
    "Switch to previously open buffer.
  Repeated invocations toggle between the two most recently open buffers."
    (switch-to-buffer (other-buffer (current-buffer) 1)))

  (key-chord-define-global "JJ" 'jc/switch-to-previous-buffer)

Command completion

smart M-x suggests M-x commands based on recency and frequency. I don't tend to use it directly but counsel uses it to order suggestions.

  (use-package smex
    :ensure t)

ivy is a generic completion framework which uses the minibuffer. Turning on ivy-mode enables replacement of lots of built in ido functionality.

  (use-package ivy
      :ensure t
      :diminish ivy-mode
      (ivy-mode t))

By default ivy starts filters with ^. I don't normally want that and can easily type it manually when I do.

  (setq ivy-initial-inputs-alist nil)

counsel is a collection of ivy enhanced versions of common Emacs commands. I haven't bound much as ivy-mode takes care of most things.

  (use-package counsel
    :ensure t
    :bind (("M-x" . counsel-M-x))
    :chords (("yy" . counsel-yank-pop)))

swiper is an ivy enhanced version of isearch.

  (use-package swiper
    :ensure t
    :bind (("M-s" . swiper)))

hydra presents menus for ivy commands.

  (use-package ivy-hydra
    :ensure t)

Suggest next key

Suggest next keys to me based on currently entered key combination.

  (use-package which-key
    :ensure t
    :diminish which-key-mode
    (add-hook 'after-init-hook 'which-key-mode))

Better undo

undo-tree visualises undo history as a tree for easy navigation.

  (use-package undo-tree
    :ensure t
    :chords (("uu" . undo-tree-visualize))
    :diminish undo-tree-mode:
    (global-undo-tree-mode 1))

One of the most important features of an advanced editor is quick text navigation. avy let's us jump to any character or line quickly.

  (use-package avy
    :ensure t
    :chords (("jj" . avy-goto-char-2)
             ("jl" . avy-goto-line)))

ace-window lets us navigate between windows in the same way as avy. Once activated it has useful sub-modes like x to switch into window deletion mode.

 (use-package ace-window
    :ensure t
    :chords ("jk" . ace-window)
    (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))

Easier selection

expand-region expands the region around the cursor semantically depending on mode. Hard to describe but a killer feature.

  (use-package expand-region
    :ensure t
    :bind ("C-=" . er/expand-region))

TODO File tree

I don't use this a whole lot, preferring to navigate via searches such as counsel-find-file, but it's occasionally useful to have a file tree.

I should consider https://github.com/Alexander-Miller/treemacs.

  (use-package neotree
    :ensure t
    (global-set-key (kbd "C-c t") 'neotree-toggle))

When I open the tree try to jump to current file.

  (setq neo-smart-open t)

Use a simple theme for the file tree.

  (setq neo-theme 'arrow)


I like the dracula theme - dark with neon highlights.

  (use-package dracula-theme
    :ensure t
    (load-theme 'dracula t))

I'm trying out apropospriate.

  (use-package apropospriate-theme
    :ensure t)

I'm now using my own translation of Panda Theme (now on melpa!).

  (use-package panda-theme
    :ensure t
    (load-theme 'panda t))

Set a nice font.

  (set-frame-font "Operator Mono 12" nil t)

Set a preferred unicode font.

  (set-fontset-font t 'unicode "STIXGeneral" nil 'prepend)

Display pretty symbols for things like lambda.

  (setq prettify-symbols-unprettify-at-point 'right-edge)
  (global-prettify-symbols-mode 0)

   (lambda ()
     (mapc (lambda (pair) (push pair prettify-symbols-alist))
           '(("def" . "𝒇")
             ("class" . "𝑪")
             ("and" . "∧")
             ("or" . "∨")
             ("not" . "¬")
             ("in" . "∈")
             ("not in" . "∉")
             ("return" . "⟼")
             ("yield" . "⟻")
             ("for" . "∀")
             ("!=" . "≠")
             ("==" . "=")
             (">=" . "≥")
             ("<=" . "≤")
             ("[]" . "⃞")
             ("=" . "≝")))))

Powerline is a port from vim, and improves the modeline. Without specifying powerline-default-separator the separators don't show correctly for me.

  (use-package powerline
    :ensure t
    (setq powerline-default-separator 'utf-8))

feebleline is a minimalist mode line replacement.

  (use-package feebleline
    :ensure t)

Add emoji support. This is useful when working with html.

  (use-package emojify
    :ensure t)

Sometimes it helps to focus on the thing currently under the cursor. This turns off syntax highlighting for everything but the current thing. It's useful sometimes but a bit buggy in certain modes. I wonder if I could improve the config / find a better alternative?

  (use-package focus
    :ensure t)

Sometimes I like to use a nyan cat to indicate progress through the buffer.

  (use-package nyan-mode
      :ensure t)

Highlight the current line.

  (global-hl-line-mode 1)


Programming specific interface improvements

When programming I like my editor to try to help me with keeping parentheses balanced.

  (use-package smartparens
    :ensure t
    :diminish smartparens-mode
    (add-hook 'prog-mode-hook 'smartparens-mode))

Highlight parens etc. for improved readability.

  (use-package rainbow-delimiters
    :ensure t
    (add-hook 'prog-mode-hook 'rainbow-delimiters-mode))

Highlight strings which represent colours. I only want this in programming modes, and I don't want colour names to be highlighted (x-colors).

  (use-package rainbow-mode
    :ensure t
    (setq rainbow-x-colors nil)
    (add-hook 'prog-mode-hook 'rainbow-mode))

Keep things indented correctly for me.

  (use-package aggressive-indent
      :ensure t)

Expand parentheses for me.

  (add-hook 'prog-mode-hook 'electric-pair-mode)

Smart dash guesses _ vs - depending on context.

  (use-package smart-dash
    :ensure t
    (add-hook 'python-mode-hook 'smart-dash-mode))

Project management

Projectile handles folders which are in version control.

  (use-package projectile
    :ensure t

Tell projectile to integrate with ivy for completion.

  (setq projectile-completion-system 'ivy)

Add some extra completion options via integration with counsel. In particular this enables C-c p SPC for smart buffer / file search, and C-c p s s for search via ag.

There is no function for projectile-grep, but we could use counsel-git-grep which is similar. Should I bind that to C-c p s g?

  (use-package counsel-projectile
    :ensure t
    (add-hook 'after-init-hook 'counsel-projectile-mode))

fzf is a fuzzy file finder which is very quick.

  (use-package fzf
    :ensure t)

Environment management

By default Emacs doesn't read from the same environment variables set in your terminal. This package fixes that.

  (use-package exec-path-from-shell
    :ensure t

Jump to source

Individual language packages often support IDE features like jump to source, but dumb-jump attempts to support many languages by simple searching. It's quite effective even with dynamic libraries like JS and Python.

  (use-package dumb-jump
    :ensure t
    :diminish dumb-jump-mode
    :bind (("C-M-g" . dumb-jump-go)
           ("C-M-p" . dumb-jump-back)
           ("C-M-q" . dumb-jump-quick-look)))


Magit is an awesome interface to git. Summon it with `C-x g`.

  (use-package magit
    :ensure t
    :bind ("C-x g" . magit-status))

Display line changes in gutter based on git history. Enable it everywhere.

  (use-package git-gutter
    :ensure t
    (global-git-gutter-mode 't)
    :diminish git-gutter-mode)

TimeMachine lets us step through the history of a file as recorded in git.

  (use-package git-timemachine
    :ensure t)

Syntax checking

Flycheck is a general syntax highlighting framework which other packages hook into. It's an improvment on the built in flymake.

Setup is pretty simple - we just enable globally and turn on a custom eslint function, and also add a custom checker for proselint.

  (use-package flycheck
    :ensure t
    (add-hook 'after-init-hook 'global-flycheck-mode)
    (add-hook 'flycheck-mode-hook 'jc/use-eslint-from-node-modules)
    (add-to-list 'flycheck-checkers 'proselint)
    (setq-default flycheck-highlighting-mode 'lines)
    ;; Define fringe indicator / warning levels
    (define-fringe-bitmap 'flycheck-fringe-bitmap-ball
      (vector #b00000000
    (flycheck-define-error-level 'error
      :severity 2
      :overlay-category 'flycheck-error-overlay
      :fringe-bitmap 'flycheck-fringe-bitmap-ball
      :fringe-face 'flycheck-fringe-error)
    (flycheck-define-error-level 'warning
      :severity 1
      :overlay-category 'flycheck-warning-overlay
      :fringe-bitmap 'flycheck-fringe-bitmap-ball
      :fringe-face 'flycheck-fringe-warning)
    (flycheck-define-error-level 'info
      :severity 0
      :overlay-category 'flycheck-info-overlay
      :fringe-bitmap 'flycheck-fringe-bitmap-ball
      :fringe-face 'flycheck-fringe-info))

Proselint is a syntax checker for English language. This defines a custom checker which will run in texty modes.

Proselint is an external program, install it with pip install proselint for this to work.

  (flycheck-define-checker proselint
    "A linter for prose."
    :command ("proselint" source-inplace)
    ((warning line-start (file-name) ":" line ":" column ": "
              (id (one-or-more (not (any " "))))
              (message (one-or-more not-newline)
                       (zero-or-more "\n" (any " ") (one-or-more not-newline)))
    :modes (text-mode markdown-mode gfm-mode org-mode))


Company mode provides good autocomplete options. Perhaps I should add company-quickhelp for documentation (https://github.com/expez/company-quickhelp)?

It would also be good to improve integration with yasnippet as I don't feel I'm making the best use there.

  (use-package company
    :ensure t
    (add-hook 'after-init-hook 'global-company-mode)

    (setq company-idle-delay t)

    (use-package company-go
      :ensure t
      (add-to-list 'company-backends 'company-go))

    (use-package company-anaconda
      :ensure t
      (add-to-list 'company-backends 'company-anaconda)))

I don't want suggestions from open files / buffers to be automatically lowercased as these are often camelcase function names.

  (setq company-dabbrev-downcase nil)


Unlike autocomplete which suggests words / symbols, snippets are pre-prepared templates which you fill in.

I'm using a community library ([[https://github.com/AndreaCrotti/yasnippet-snippets]]) with lots of ready made options, and have my own directory of custom snippets I've added. Not sure if I should unify these by forking yasnippet-snippets.

Type the shortcut and press TAB to complete, or M-/ to autosuggest a snippet.

  (use-package yasnippet
      :ensure t
      :diminish yas-minor-mode
      (add-to-list 'yas-snippet-dirs "~/.emacs.d/yasnippet-snippets")
      (add-to-list 'yas-snippet-dirs "~/.emacs.d/snippets")
      (global-set-key (kbd "M-/") 'company-yasnippet))


In JS indent to 2 spaces.

  (setq-default js-indent-level 2)

JS2 mode improves on the built in JS mode.

  (use-package js2-mode
    :ensure t
    :mode "\\.js\\'"
    (setq-default js2-ignored-warnings '("msg.extra.trailing.comma")))

js2-refactor supports some useful refactoring options and builds on top of js2-mode.

  (use-package js2-refactor
    :ensure t
    (js2r-add-keybindings-with-prefix "C-c C-m")
    (add-hook 'js2-mode-hook 'js2-refactor-mode))

RJSX mode makes JSX work well.

  (use-package rjsx-mode
    :ensure t)

Prettier-js autoformats JS code - much like `gofmt` - and we hook it into JS2 and RJSX modes.

  (use-package prettier-js
    :ensure t
    (setq prettier-js-args '(
                          "--trailing-comma" "es5"
                          "--single-quote" "true"
                          "--print-width" "100"
    (add-hook 'js2-mode-hook 'prettier-js-mode)
    (add-hook 'rjsx-mode-hook 'prettier-js-mode))

js-doc makes it easy to add jsdoc comments via Ctrl+c i.

  (use-package js-doc
    :ensure t
    :bind (:map js2-mode-map
           ("C-c i" . js-doc-insert-function-doc)
           ("@" . js-doc-insert-tag))
    (setq js-doc-mail-address "[email protected]"
         js-doc-author (format "Jamie Collinson <%s>" js-doc-mail-address)
         js-doc-url "jamiecollinson.com"
         js-doc-license "MIT License"))

Sometimes it's useful to use the local eslint provided by a project's node_modules directory. We call this function from a flycheck hook to enable it automatically.

  (defun jc/use-eslint-from-node-modules ()
    "Set local eslint if available."
    (let* ((root (locate-dominating-file
                  (or (buffer-file-name) default-directory)
           (eslint (and root
                        (expand-file-name "node_modules/eslint/bin/eslint.js"
      (when (and eslint (file-executable-p eslint))
        (setq-local flycheck-javascript-eslint-executable eslint))))

Web mode

Web mode handles html/css/js.

  (use-package web-mode
    :ensure t
    :mode ("\\.html\\'")
    (setq web-mode-markup-indent-offset 2)
    (setq web-mode-engines-alist
          '(("django" . "focus/.*\\.html\\'")
            ("ctemplate" . "realtimecrm/.*\\.html\\'"))))

Web Beautify

Web beautify prettifies html / css / js using js-beautify - install with npm install -g js-beautify.

  (use-package web-beautify
    :ensure t
    :bind (:map web-mode-map
           ("C-c b" . web-beautify-html)
           :map js2-mode-map
           ("C-c b" . web-beautify-js)))


Markdown support isn't built into Emacs, add it with markdown-mode.

  (use-package markdown-mode
    :ensure t
    :commands (markdown-mode gfm-mode)
    :mode (("README\\.md\\'" . gfm-mode)
           ("\\.md\\'" . markdown-mode)
           ("\\.markdown\\'" . markdown-mode))
    :init (setq markdown-command "multimarkdown"))


Go-mode provides basic language support, we call gofmt on each save to keep code tidy, use eldoc to display documentation and add guru / doctor for IDE functionality.

  (use-package go-mode
    :ensure t
    (add-hook 'before-save-hook 'gofmt-before-save)

    (use-package go-eldoc
      :ensure t
      (add-hook 'go-mode-hook 'go-eldoc-setup))

    (use-package godoctor
      :ensure t)

    (use-package go-guru
      :ensure t))

Go guru needs a scope to look at, this function sets it to the current package.

  (defun jc/go-guru-set-current-package-as-main ()
    "GoGuru requires the scope to be set to a go package which
     contains a main, this function will make the current package the
     active go guru scope, assuming it contains a main"
    (let* ((filename (buffer-file-name))
           (gopath-src-path (concat (file-name-as-directory (go-guess-gopath)) "src"))
           (relative-package-path (directory-file-name (file-name-directory (file-relative-name filename gopath-src-path)))))
      (setq go-guru-scope relative-package-path)))


Install haskell mode.

  (use-package haskell-mode
    :ensure t)

Code formatting is easier with hindent.

  (use-package hindent
    :ensure t)

Completion is via ghc-mod / company. Install the former separately with cabal install ghc-mod.

  (use-package ghc
    :ensure t
    (add-hook 'haskell-mode-hook (lambda () (ghc-init))))

  (use-package company-ghc
    :ensure t
    (add-to-list 'company-backends 'company-ghc))


Emacs handles python quite well, but we can improve things with anaconda mode.

  (use-package anaconda-mode
    :ensure t
    (add-hook 'python-mode-hook 'anaconda-mode)
    (add-hook 'python-mode-hook 'anaconda-eldoc-mode))

Sometimes I use kivy.

  (use-package kivy-mode
    :ensure t
    :mode ("\\.kv\\'" . kivy-mode))


Elixir highlighting is not built into emacs at present. Elixir-mode gives all the usual niceties, and alchemist improves interaction with tools like iex, mix and elixir-format.

  (use-package elixir-mode
    :ensure t

    (use-package alchemist
      :ensure t))


Cucumber (gherkin) is a syntax for specifying behaviour driven development tests.

  (use-package feature-mode
    :ensure t)

Rebol / Red

Red is an updated open source implementation of Rebol.

  (use-package rebol)


  (use-package idris-mode
    :ensure t)


Proof general must be installed separately via:

  git clone https://github.com/ProofGeneral/PG ~/.emacs.d/lisp/PG
  make -C ~/.emacs.d/lisp/PG

Open .v files with Proof General's Coq mode

  (require 'proof-site "~/.emacs.d/lisp/PG/generic/proof-site")
  (use-package company-coq
    :ensure t
    (add-hook 'coq-mode-hook 'company-coq-mode))


Elm is a delightful language for reliable webapps. It compiles to JS. First install elm with npm install -g elm elm-oracle elm-format.

  (use-package elm-mode
    :ensure t
    (setq elm-format-on-save t)
    (add-to-list 'company-backends 'company-elm))


Emacs has a great built in C/C++ mode, but we can improve on it with irony-mode for code completion via libclang.

  (use-package irony
    :ensure t
    :hook (c-mode . irony-mode))

Add company mode support.

  (use-package company-irony
    :ensure t
    (add-to-list 'company-backends 'company-irony))

Add flycheck support.

  (use-package flycheck-irony
    :ensure t
    :hook (flycheck-mode . flycheck-irony-setup))


Dotnet core runs on linux / macos. Let's get syntax highlighting.

  (use-package csharp-mode
    :ensure t)

Omnisharp gives completion / refactoring support, and hooks into company-mode.

  (use-package omnisharp
    :ensure t
    :hook ((csharp-mode . omnisharp-mode)
           ;; TODO: 'before-save runs globally - make this buffer local?
           (before-save . omnisharp-code-format-entire-file))
    (add-to-list 'company-backends 'company-omnisharp))


Since we have dotnet core why not?

  (use-package fsharp-mode
    :ensure t)


General settings.

I should comment on these more...

  (setq org-startup-indented 'f)
  (setq org-directory "~/org")
  (setq org-special-ctrl-a/e 't)
  (setq org-default-notes-file (concat org-directory "/notes.org"))
  (define-key global-map "\C-cc" 'org-capture)
  (setq org-mobile-directory "~/Dropbox/Apps/MobileOrg")
  (setq org-src-fontify-natively 't)
  (setq org-src-tab-acts-natively t)
  (setq org-src-window-setup 'current-window)


Improve the display of bullet points.

  (use-package org-bullets
    :ensure t
    (setq org-bullets-bullet-list '("∙"))
    (add-hook 'org-mode-hook 'org-bullets-mode))

Customize appearance.

      ((variable-tuple (cond
                        ((x-list-fonts "Source Sans Pro") '(:font "Source Sans Pro"))
                        ((x-list-fonts "Lucida Grande")   '(:font "Lucida Grande"))
                        ((x-list-fonts "Verdana")         '(:font "Verdana"))
                        ((x-family-fonts "Sans Serif")    '(:family "Sans Serif"))
                        (nil (warn "Cannot find a Sans Serif Font.  Install Source Sans Pro."))))
       (base-font-color     (face-foreground 'default nil 'default))
       (headline           `(:inherit default :weight normal :foreground ,base-font-color)))

    (custom-theme-set-faces 'user
                            `(org-level-8 ((t (,@headline ,@variable-tuple))))
                            `(org-level-7 ((t (,@headline ,@variable-tuple))))
                            `(org-level-6 ((t (,@headline ,@variable-tuple))))
                            `(org-level-5 ((t (,@headline ,@variable-tuple))))
                            `(org-level-4 ((t (,@headline ,@variable-tuple))))
                            `(org-level-3 ((t (,@headline ,@variable-tuple :height 1.33))))
                            `(org-level-2 ((t (,@headline ,@variable-tuple :height 1.33))))
                            `(org-level-1 ((t (,@headline ,@variable-tuple :height 1.33))))
                            `(org-document-title ((t (,@headline ,@variable-tuple :height 1.33 :underline nil))))))


Add bootstrap styled export.

  (use-package ox-twbs
    :ensure t)



writegood-mode highlights bad word choices and has functions for calculating readability.

  (use-package writegood-mode
    :ensure t
    :bind ("C-c g" . writegood-mode)
    (add-to-list 'writegood-weasel-words "actionable"))

Stack Overflow

SX is a full stack overflow client within Emacs.

  (use-package sx
    :ensure t
    (bind-keys :prefix "C-c s"
               :prefix-map my-sx-map
               :prefix-docstring "Global keymap for SX."
               ("q" . sx-tab-all-questions)
               ("i" . sx-inbox)
               ("o" . sx-open-link)
               ("u" . sx-tab-unanswered-my-tags)
               ("a" . sx-ask)
               ("s" . sx-search)))

Web browsing

w3m is a terminal based browser. Emacs now has eww built in, but I prefer w3m. Install it separately, e.g. with brew install w3m.

There's an emacs package to interface with it.

  (use-package w3m
    :ensure t)


notmuch is a fast mail client. Install it externally, e.g. with brew install notmuch and then use it within emacs.

  (use-package notmuch
    :ensure t)

Rest client

Sometimes I need to explore REST services. Why not Emacs?

  (use-package restclient
    :ensure t)


I use slack for work.

  (use-package slack
    :ensure t
    :commands (slack-start))


It's always useful to look things up.

  (use-package google-this
    :ensure t)

  1. I hesitate to say this is the emacs way, it's just what I felt necessary.