Skip to content

Instantly share code, notes, and snippets.

@russelldb
Forked from seancribbs/init.el
Created August 22, 2017 11:10
Show Gist options
  • Select an option

  • Save russelldb/0674c536470a897a191d895be003817a to your computer and use it in GitHub Desktop.

Select an option

Save russelldb/0674c536470a897a191d895be003817a to your computer and use it in GitHub Desktop.

Revisions

  1. @seancribbs seancribbs revised this gist Mar 3, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion seancribbs.org
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@

    (global-set-key (kbd "C-S-k") 'delete-region)
    (global-set-key (kbd "C-s") 'isearch-forward-regexp)
    (global-set-key (kbd "") 'isearch-backward-regexp)
    (global-set-key (kbd "C-r") 'isearch-backward-regexp)
    (global-set-key (kbd "M-%") 'query-replace-regexp)
    (global-set-key (kbd "C-M-s") 'isearch-forward)
    (global-set-key (kbd "C-M-r") 'isearch-backward)
  2. @seancribbs seancribbs created this gist Mar 3, 2016.
    3 changes: 3 additions & 0 deletions init.el
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    ;; Use org-babel to load config
    (require 'org)
    (org-babel-load-file (expand-file-name "seancribbs.org" user-emacs-directory))
    881 changes: 881 additions & 0 deletions seancribbs.org
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,881 @@
    #+TITLE: Sean Cribbs' Emacs 24 Configuration
    #+AUTHOR: Sean Cribbs
    #+EMAIL: [email protected]
    #+OPTIONS: toc:3 num:nil
    #+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://thomasf.github.io/solarized-css/solarized-light.min.css" />
    * Introduction
    Inspired by [[http://www.aaronbedra.com/emacs.d/][Aaron Bedra's emacs configuration]], I have converted mine
    to an org-mode file as well. This should improve load speed over my
    bespoke number-oriented-multi-file config, as well as improve
    documentation of my settings. You might notice a few things lifted
    directly from Aaron's config.
    * Startup
    I want to do a few things early in the startup process, like
    cleanup some of Emacs' less savory defaults, so these come first.
    I'm also trying to wean myself off of emacs-starter-kit, so things
    that it does early in the startup process that I want to co-opt
    will go in this section.
    ** Environment
    There are plenty of things installed outside of the default =PATH=.
    This allows me to establish additional PATH information. At the
    moment, the only things that added are /usr/local/bin for homebrew
    on OS X.

    Sadly, there's no built-in variable pointing to the user's home
    directory, so I pull that out based on the environment variable
    =HOME=, or failing that, the parent directory of the Emacs
    configuration.

    I also keep some non-ELPA things in my emacs directory.
    #+begin_src emacs-lisp
    (setenv "PATH" (concat "/usr/local/bin:/opt/local/bin:/usr/bin:/bin" (getenv "PATH")))

    (defconst user-home-directory
    (or (getenv "HOME")
    (expand-file-name ".." user-emacs-directory))
    "The user's home directory.")

    (add-to-list 'load-path (expand-file-name "site-lisp" user-emacs-directory))
    #+end_src
    ** Common Lisp for Emacs
    Emacs lisp is really only a subset of common lisp, and I need to
    have some of the additional functionality to make the
    configuration and its dependencies work properly, which we get by
    requiring Common Lisp for Emacs.
    #+begin_src emacs-lisp
    (require 'cl)
    #+end_src

    ** Key Bindings
    Miscellaneous keybindings that don't belong anywhere else. I use
    Option as =super= and Command as =meta= on OS/X.

    #+begin_src emacs-lisp
    (setq mac-option-modifier 'super)
    (setq mac-command-modifier 'meta)

    (global-set-key (kbd "C-S-k") 'delete-region)
    (global-set-key (kbd "C-s") 'isearch-forward-regexp)
    (global-set-key (kbd "") 'isearch-backward-regexp)
    (global-set-key (kbd "M-%") 'query-replace-regexp)
    (global-set-key (kbd "C-M-s") 'isearch-forward)
    (global-set-key (kbd "C-M-r") 'isearch-backward)
    (global-set-key (kbd "C-M-%") 'query-replace)

    (setq imenu-auto-rescan t)
    (global-set-key (kbd "C-x TAB") 'imenu)

    (put 'upcase-region 'disabled nil)
    #+end_src
    ** Yes and No
    Nobody likes to have to type out the full yes or no when Emacs
    asks. Which it does often. Make it one character.

    #+begin_src emacs-lisp
    (defalias 'yes-or-no-p 'y-or-n-p)
    #+end_src

    ** Backup Files
    I hate backup files just as much as the next person. This is why
    we have version control systems, people.
    #+begin_src emacs-lisp
    (setq make-backup-files nil)
    (setq backup-directory-alist `((".*" . ,temporary-file-directory)))
    (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)))
    #+end_src
    ** Marking text
    There are some behaviors in Emacs that aren't intuitive related to
    marking text. Specifically, typing or yanking into the selected
    region should replace it (=delete-selection-mode=), and when the
    buffer is changed, the region is de-selected
    (=transient-mark-mode=).
    #+begin_src emacs-lisp
    (delete-selection-mode t)
    (transient-mark-mode t)
    #+end_src
    * Server
    I use =emacsclient= obsessively, especially via my shell alias =e=,
    which is mapped to =emacsclient -n=. In order for this to work, you
    have to start the "server".
    #+BEGIN_SRC emacs-lisp
    (require 'server)
    (server-start)
    #+END_SRC
    * Packages
    Since Emacs 24, Emacs includes the Emacs Lisp Package Archive
    (ELPA) by default. This provides a nice way to install additional
    packages. Since the default package archive doesn't include
    everything necessary, the marmalade, and melpa repositories are
    also added. This also prefetches the package list if we don't have
    a cached copy yet.

    #+BEGIN_SRC emacs-lisp
    (require '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" magit graphviz-dot-mode lua-mode elixir-mode elixir-yasnippets flymake-elixir)))

    (when (not package-archive-contents)
    (package-refresh-contents))
    #+END_SRC
    ** Define packages
    This is the list of packages used in this configuration. I start
    with major modes and enhancements first, add flymake, and then
    utilities and themes.

    #+begin_src emacs-lisp
    (defvar seancribbs/packages
    '(
    clojure-mode
    elixir-mode
    elixir-yasnippets
    graphviz-dot-mode
    haskell-mode
    inf-ruby
    js2-mode
    lua-mode
    markdown-mode
    mmm-mode
    php-mode
    protobuf-mode
    python-mode
    rspec-mode
    ruby-end
    scala-mode
    wc-mode
    web-mode
    yaml-mode

    flymake
    flymake-easy
    flymake-elixir
    flymake-lua
    flymake-ruby
    flymake-haskell-multi

    org-present

    ag
    auto-complete
    dash-at-point
    expand-region
    highlight
    hlinum
    ido-ubiquitous
    magit
    minimap
    neotree
    paredit
    smex
    htmlize

    ir-black-theme
    solarized-theme
    twilight-theme
    underwater-theme
    )
    )
    #+end_src
    ** Install default packages
    When Emacs boots, check to make sure all of the packages defined
    in =seancribbs/packages= are installed. If not, have ELPA take
    care of it.

    #+begin_src emacs-lisp
    (dolist (p seancribbs/packages)
    (when (not (package-installed-p p))
    (package-install p)))
    #+end_src

    * Visual tweaks
    ** Window chrome
    Most people don't use =menu-bar-mode=, but some things provided by
    my add-ons don't have key combos bound to the menu items they
    create, so I enable it. Unfortunately it doesn't help things in
    console mode, so I only enable it in graphical modes.

    The default frame title leaves a bit to be desired, so both
    Aaron's and ESK's config include the next tweak.

    I don't want to hear audible bells or see the splash screen, so
    those are disabled.
    #+begin_src emacs-lisp
    (when window-system
    (menu-bar-mode 1)
    (setq frame-title-format '(buffer-file-name "%f" ("%b"))))

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

    (setq visible-bell t
    inhibit-splash-screen t
    inhibit-startup-message t
    initial-scratch-message nil)
    #+end_src
    ** Font
    I've used DejaVu Sans Mono for years. Thanks, Aaron, for making this
    easier for me to set! It's also nice to be able to quickly tweak
    the text size.

    #+begin_src emacs-lisp
    (when window-system
    (when (functionp 'set-fontset-font)
    (set-fontset-font "fontset-default"
    'unicode
    (font-spec :family "DejaVu Sans Mono"
    :width 'normal
    :size 12.4
    :weight 'normal))))

    (global-set-key (kbd "C-+") 'text-scale-increase)
    (global-set-key (kbd "C--") 'text-scale-decrease)
    #+end_src
    ** Theme
    I use the =solarized-light= theme most of the time, so I figure it
    should startup in that theme.
    #+begin_src emacs-lisp
    (load-theme 'solarized-light t)
    #+end_src
    ** Window Resizing
    Following this are some experimental keys that I've been
    trying so I can easily grow or shrink a window split. I'm not
    particularly happy with them yet.

    #+begin_src emacs-lisp
    (global-set-key (kbd "s-<right>") 'enlarge-window-horizontally)
    (global-set-key (kbd "s-<left>") 'shrink-window-horizontally)
    (global-set-key (kbd "s-<up>") 'enlarge-window)
    (global-set-key (kbd "s-<down>") 'shrink-window)
    #+end_src
    ** Buffer management
    Switching buffers should be easy and fast, and killing them too.
    And sometimes, you just have to declare buffer-bankruptcy.

    #+begin_src emacs-lisp
    (global-set-key (kbd "M-]") 'next-buffer)
    (global-set-key (kbd "M-[") 'previous-buffer)

    (defun kill-current-buffer ()
    "Kills the current buffer"
    (interactive)
    (kill-buffer (buffer-name)))
    (global-set-key (kbd "C-x C-k") 'kill-current-buffer)

    (defun nuke-all-buffers ()
    "Kill all buffers, leaving *scratch* only"
    (interactive)
    (mapcar (lambda (x) (kill-buffer x))
    (buffer-list))
    (delete-other-windows))
    (global-set-key (kbd "C-x C-S-k") 'nuke-all-buffers)

    (global-set-key (kbd "C-c r") 'revert-buffer)
    #+end_src
    ** Whitespace
    I like to see where the unnecessary whitespace is in all
    programming modes, and have a quick key to clean it up. There
    shall be no tabs in my files, only spaces. I'd also like to
    quickly reindent an entire buffer according to the modes' electric
    indentation. The last three functions were copied from ESK.

    #+begin_src emacs-lisp
    (require 'whitespace)

    (unless (member 'whitespace-mode prog-mode-hook)
    (add-hook 'prog-mode-hook 'whitespace-mode))
    (global-set-key (kbd "C-c w") 'whitespace-cleanup)
    (set-default 'indicate-empty-lines t)
    (set-default 'indent-tabs-mode nil)
    (setq whitespace-style '(face trailing lines-tail tabs)
    whitespace-line-column 80)

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

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

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

    (global-set-key (kbd "C-c n") 'seancribbs/cleanup-buffer)
    #+end_src

    ** Modeline
    The Emacs modeline contains helpful status information. I turn on
    column and line numbers globally.

    #+begin_src emacs-lisp
    (line-number-mode 1)
    (column-number-mode 1)
    #+end_src
    ** Highlights
    I took these customizations from ESK. First, it's always nice to
    quickly see what line you're on, and then when you put in
    watchwords, those should show up highlighted. I'd also like to see
    matching parens so I can be sure my code is structured correctly.
    #+begin_src emacs-lisp
    (defun seancribbs/turn-on-hl-line-mode ()
    (when (> (display-color-cells) 8)
    (hl-line-mode t)))

    (defun seancribbs/add-watchwords ()
    (font-lock-add-keywords
    nil '(("\\<\\(FIX\\(ME\\)?\\|TODO\\|HACK\\|REFACTOR\\|NOCOMMIT\\)"
    1 font-lock-warning-face t))))

    (add-hook 'prog-mode-hook 'seancribbs/turn-on-hl-line-mode)
    (add-hook 'prog-mode-hook 'seancribbs/add-watchwords)

    (show-paren-mode t)
    #+end_src

    * Major modes
    ** Programming Modes
    These customizations I like to use in all "programming modes",
    i.e. modes derived from =prog-mode=. The main change here is that
    I find =comment-dwim= to not "do what I mean" in most cases, so I use
    this function that used to be part of ESK or some dependency of
    it. Instead of inserting a comment at the end-of-line, it will
    toggle commenting out the current line. Unfortunately the key I'm
    used to is usually occupied by =dabbrev-expand=, so I assign that
    to something else.

    #+begin_src emacs-lisp
    (defun comment-or-uncomment-region-or-line ()
    "Comments or uncomments the region or the current line if there's no active region."
    (interactive)
    (let (beg end)
    (if (region-active-p)
    (setq beg (region-beginning) end (region-end))
    (setq beg (line-beginning-position) end (line-end-position)))
    (comment-or-uncomment-region beg end)))

    (global-set-key (kbd "M-/") 'comment-or-uncomment-region-or-line)
    (global-set-key (kbd "M-\\") 'dabbrev-expand)
    #+end_src
    ** Flymake
    Flymake is super-useful for finding dumb errors in my source files
    by running compilation in the background. This adds a key to
    easily jump to the next error in the current buffer.

    #+begin_src emacs-lisp
    (defun seancribbs/flymake-keys ()
    "Adds keys for navigating between errors found by Flymake."
    (local-set-key (kbd "C-c C-n") 'flymake-goto-next-error)
    (local-set-key (kbd "C-c C-p") 'flymake-goto-prev-error))

    (add-hook 'flymake-mode-hook 'seancribbs/flymake-keys)
    #+end_src

    ** Erlang
    I write a lot of Erlang. Unlike most people, I don't like the all
    the quirks that come with =edts= and other "Emacs IDE for Erlang"
    packages, so I load the mode from the latest OTP I have installed.
    I also add Quviq QuickCheck and Wrangler.
    *** Find Erlang Mode
    There's a few curiosities here. I use multiple Erlang versions
    and found =kerl= too hacky to maintain, so I wrote a few short
    shell functions to build, install, and switch between versions of
    OTP I have in =$HOME/erlang=. This means I need to pull
    =erlang-mode= from the latest "tools" application in OTP.

    #+begin_src emacs-lisp
    (defconst seancribbs/erlang/root
    "/usr/local/Cellar/erlang"
    "The root directory where various versions of Erlang are installed")

    (defvar seancribbs/erlang/latest
    "18.2.1"
    "The latest version of Erlang installed.")

    (defvar seancribbs/erlang/latest/tools-version
    "2.8.2"
    "The version of the 'tools' application in the latest Erlang.")

    (defun seancribbs/erlang/latest/root ()
    "Computes the root directory of the latest Erlang installed."
    (expand-file-name seancribbs/erlang/latest seancribbs/erlang/root))

    (defun seancribbs/erlang/latest/bin ()
    "Computes the latest Erlang's executable directory"
    (expand-file-name "bin" (seancribbs/erlang/latest/root)))

    (defun seancribbs/erlang/latest/lib ()
    "Computes the latest Erlang's library directory"
    (expand-file-name "erlang" (expand-file-name "lib" (seancribbs/erlang/latest/root))))

    (defun seancribbs/erlang/latest/emacs ()
    "Computes the location of the OTP emacs mode."
    (cl-reduce 'expand-file-name
    (list "emacs"
    (format "tools-%s" seancribbs/erlang/latest/tools-version)
    "lib"
    (seancribbs/erlang/latest/lib))
    :from-end t))
    #+end_src

    *** Load Erlang Mode
    Now that we have that boilerplate out of the way, we can add the
    mode. First we add the tools/emacs directory to the load path,
    set the Erlang root, add its binaries to the executable path and
    require the mode.

    Somehow Erlang mode is not derived from =prog-mode=, so my usual
    additions don't apply, so I need to add them to make it
    consistent.
    #+begin_src emacs-lisp
    (add-to-list 'load-path (seancribbs/erlang/latest/emacs))
    (add-to-list 'exec-path (seancribbs/erlang/latest/bin))
    (setq erlang-root-dir (seancribbs/erlang/latest/lib))
    (require 'erlang-start)

    (add-hook 'erlang-mode-hook 'seancribbs/add-watchwords)
    (add-hook 'erlang-mode-hook 'seancribbs/turn-on-hl-line-mode)
    (add-hook 'erlang-mode-hook 'whitespace-mode)
    #+end_src

    *** Additional Files
    The OTP emacs mode doesn't come with some of my commonly used
    files that are Erlang code or terms.

    #+begin_src emacs-lisp
    (add-to-list 'auto-mode-alist '("rebar.config" . erlang-mode)) ;; rebar
    (add-to-list 'auto-mode-alist '("rebar.config.script" . erlang-mode)) ;; rebar
    (add-to-list 'auto-mode-alist '("app.config" . erlang-mode)) ;; embedded node/riak
    ;;(add-to-list 'auto-mode-alist '(".riak_test.config" . erlang-mode))
    (add-to-list 'auto-mode-alist '("\\.erlang$" . erlang-mode)) ;; User customizations file
    #+end_src

    *** Flymake
    Flymake is my savior for =erlang-mode= and requires only a little
    bit of configuration. For rebar3-based projects, we need to look
    in the =_build/*= directories for dependencies, not just in
    =deps/= (not working yet).

    #+begin_src emacs-lisp
    (require 'erlang-flymake)
    (setq erlang-flymake-command (expand-file-name "erlc" (seancribbs/erlang/latest/bin)))

    (defun rebar3/erlang-flymake-get-include-dirs ()
    (append
    (erlang-flymake-get-include-dirs)
    (file-expand-wildcards (concat (erlang-flymake-get-app-dir) "_build/*/lib")))
    )

    (setq erlang-flymake-get-include-dirs-function 'rebar3/erlang-flymake-get-include-dirs)

    (defun rebar3/erlang-flymake-get-code-path-dirs ()
    (append
    (erlang-flymake-get-code-path-dirs)
    (file-expand-wildcards (concat (erlang-flymake-get-app-dir) "_build/*/lib/*/ebin"))))

    (setq erlang-flymake-get-code-path-dirs-function 'rebar3/erlang-flymake-get-code-path-dirs)
    #+end_src

    *** Erlang QuickCheck (Quviq)
    QuickCheck is the best testing tool, and comes with a bunch of
    helpful templates and shortcut keys for building out
    property-based tests.

    NB: I have disabled this since I no longer have a license.

    #+begin_src emacs-lisp
    ;;(defvar seancribbs/erlang/eqc-version
    ;; "1.34.2"
    ;; "The latest version of EQC I have installed.")

    ;;(defun seancribbs/erlang/eqc/root ()
    ;; "Computes the location of the latest EQC app."
    ;; (cl-reduce 'expand-file-name
    ;; (list (format "eqc-%s" seancribbs/erlang/eqc-version)
    ;; seancribbs/erlang/eqc-version
    ;; "eqc"
    ;; seancribbs/erlang/root)
    ;; :from-end t))

    ;;(add-to-list 'load-path (expand-file-name "emacs" (seancribbs/erlang/eqc/root)))
    ;;(autoload 'eqc-erlang-mode-hook "eqc-ext" "EQC Mode" t)
    ;;(add-hook 'erlang-mode-hook 'eqc-erlang-mode-hook)
    ;;(setq eqc-max-menu-length 30)
    ;;(setq eqc-root-dir (seancribbs/erlang/eqc/root))
    #+end_src
    *** Wrangler
    Wrangler is an Erlang refactoring tool that I use less often than
    other things, but can be super helpful in renaming functions,
    modules, and extracting common functionality.

    #+begin_src emacs-lisp
    (add-to-list 'load-path (expand-file-name "dev/wrangler/elisp" user-home-directory))
    (require 'vc)
    (require 'wrangler)

    (setq wrangler-search-paths '())

    (defconst seancribbs/erlang/project-subdirs
    '("src" "test" "deps" "apps"))

    (defun seancribbs/erlang/expand-project-path (project-root subdir)
    "Expands a subdirectory"
    (let ((full-path (expand-file-name subdir project-root)))
    (when (file-exists-p full-path)
    (list full-path))))

    (defconst seancribbs/erlang/project-root-files-regexp
    (regexp-opt '(".git" "rebar.config")))

    (defun seancribbs/erlang/project-root-filter (name)
    (when (not (file-regular-p name))
    (and (not (string-match-p "/\\(deps\\|apps\\)" name))
    (directory-files name nil seancribbs/erlang/project-root-files-regexp)
    )))

    (defun seancribbs/erlang/project-root ()
    "Finds the root of a project, based on presence of Git or rebar
    artifacts."
    (locate-dominating-file buffer-file-name 'seancribbs/erlang/project-root-filter))

    (defun seancribbs/erlang/wrangler-set-paths ()
    "Sets the wrangler search paths based on the location of the
    current file."
    (interactive)
    (let* ((project-root (expand-file-name (seancribbs/erlang/project-root)))
    (subdir-finder (lambda (subdir) (seancribbs/erlang/expand-project-path project-root subdir))))
    (setq wrangler-search-paths
    (apply 'append (mapcar subdir-finder seancribbs/erlang/project-subdirs)))
    (minibuffer-message "Set wrangler paths to %S" wrangler-search-paths)))

    (eval-after-load "erlang"
    '(define-key erlang-mode-map (kbd "C-c C-w !") 'seancribbs/erlang/wrangler-set-paths))
    #+end_src

    *** Customizations
    Erlang binaries are a pain to type, so I add a function and
    keybinding that inserts one for me. I'm still getting this one in
    my fingers.

    #+begin_src emacs-lisp
    (defun erlang-insert-binary ()
    "Inserts a binary string into an Erlang buffer and places the
    point between the quotes."
    (interactive)
    (insert "<<\"\">>")
    (backward-char 3)
    )
    (eval-after-load "erlang" '(define-key erlang-mode-map (kbd "C-c b") 'erlang-insert-binary))
    #+end_src

    ** Lua
    Lua is a pretty interesting embeddable scripting language. I'm
    currently using it inside =nginx= and =luajit= from the shell.

    For some reason =lua-mode= defaults to 3-space indent, but all my
    coworkers use 4.

    #+begin_src emacs-lisp
    (require 'lua-mode)
    (setq lua-default-application "luajit")
    (setq lua-indent-level 4)
    #+end_src

    ** Scala
    Scala is used by one of the major projects I am working on.

    #+begin_src emacs-lisp
    (add-to-list 'auto-mode-alist '(".scala$" . scala-mode))
    (add-to-list 'auto-mode-alist '(".sbt$" . scala-mode))
    #+end_src

    ** Python
    Python's PEP8 tool is really picky about line-length, so this
    changes =fill-paragraph= to flow to narrower widths. I also hate
    the default of 8-space indentation. 4 is more humane.

    #+begin_src emacs-lisp
    (add-hook 'python-mode-hook
    (lambda () (set (make-local-variable 'fill-column) 75)
    (set (make-local-variable 'tab-width) 4)))
    #+end_src

    ** Ruby
    The default auto-mode list for Ruby is insufficient. I also want
    to edit ERB files using MMM's ERB mode. One also shouldn't edit
    Rubinius compiler output.

    #+begin_src emacs-lisp
    (require 'ruby-mode)
    (require 'mmm-erb)

    (add-to-list 'auto-mode-alist '("Guardfile$" . ruby-mode))
    (add-to-list 'auto-mode-alist '("Assetfile$" . ruby-mode))
    (add-to-list 'auto-mode-alist '(".html.erb" . html-erb-mode))

    (add-to-list 'completion-ignored-extensions ".rbc")
    (add-to-list 'completion-ignored-extensions ".rbo")
    #+end_src
    ** Haskell
    I'm learning Haskell. =haskell-mode= makes you choose an
    indentation strategy, so I'm using =haskell-indentation-mode= right
    now.
    #+begin_src emacs-lisp
    (add-hook 'haskell-mode-hook 'haskell-indentation-mode)
    #+end_src
    ** JavaScript
    We should edit JSON files in JavaScript mode.
    #+begin_src emacs-lisp
    (add-to-list 'auto-mode-alist '("\\.json$" . js-mode))
    #+end_src
    ** Emacs Lisp
    ElDoc and paredit make editing Emacs Lisp a lot easier.
    #+begin_src emacs-lisp
    (add-hook 'emacs-lisp-mode-hook 'eldoc-mode)
    (add-hook 'emacs-lisp-mode-hook 'paredit-mode)
    (define-key read-expression-map (kbd "TAB") 'lisp-complete-symbol)
    (define-key lisp-mode-shared-map (kbd "RET") 'reindent-then-newline-and-indent)
    (define-key emacs-lisp-mode-map (kbd "C-c v") 'eval-buffer)
    #+end_src
    ** Clojure
    I'm starting to use a little Clojure with riemann, but paredit is
    off by default.
    #+begin_src emacs-list
    (add-hook 'clojure-mode-hook (lambda () (paredit-mode t)))
    #+end_src
    ** Org
    I co-opted a lot of these =org-mode= customizations from Aaron.

    =org-present= is for doing presentations direct from =org-mode=. I
    added =hide-mode-line= so that you don't get the modeline noise
    while presenting. It is not available as a package but you can
    download it: [[http://webonastick.com/emacs-lisp/hide-mode-line.el]]

    #+begin_src emacs-lisp
    (require 'ob)

    (org-babel-do-load-languages
    'org-babel-load-languages
    '((sh . t)
    (dot . t)
    (ruby . t)
    (js . t)
    (C . t)))

    (add-to-list 'org-src-lang-modes (quote ("dot". graphviz-dot)))

    (setq org-src-fontify-natively t)

    (require 'org-present)
    (require 'hide-mode-line)

    (define-key org-present-mode-keymap (kbd "q") 'org-present-quit)

    (defun seancribbs/org-present-hook ()
    "Entry hook for org-present mode"
    (window-configuration-to-register :org-present-register)
    (delete-other-windows)
    (org-present-big)
    (org-display-inline-images)
    (hide-mode-line-in (current-buffer)))

    (add-hook 'org-present-mode-hook 'seancribbs/org-present-hook)

    (defun seancribbs/org-present-quit-hook ()
    "Entry hook for org-present mode"
    (org-present-small)
    (org-remove-inline-images)
    (show-mode-line-in (current-buffer))
    (redraw-display)
    (when (get-register :org-present-register)
    (jump-to-register :org-present-register)))

    (add-hook 'org-present-mode-quit-hook 'seancribbs/org-present-quit-hook)

    #+end_src
    ** Markdown
    Most of my Markdown editing uses Github-flavored, so I use
    =gfm-mode= instead of the regular =markdown-mode=.

    #+begin_src emacs-lisp
    (add-to-list 'auto-mode-alist '(".md$" . gfm-mode))
    #+end_src
    ** Text
    I like my text modes to auto-wrap paragraphs.

    I did a project for a little while where I tried to write 750
    words a day, to improve my writing skills. I didn't get very far,
    but I added =wc-mode= and a quick keychord to launch it.

    #+begin_src emacs-lisp
    (add-hook 'text-mode-hook 'turn-on-auto-fill)

    (require 'wc-mode)

    (defun open-daily-writing ()
    "Open today's writing file"
    (interactive)
    (let ((filename (format-time-string "%Y-%m-%d.txt")))
    (find-file (concat user-home-directory "/notes/writing/"
    filename))
    (with-current-buffer filename
    (wc-mode t)
    (wc-set-word-goal 750))
    )
    (delete-other-windows))

    (global-set-key (kbd "C-x C-S-W") 'open-daily-writing)
    #+end_src

    ** Graphviz
    Graphviz dot is great for quickly specifying graphs.

    #+begin_src emacs-lisp
    ;; NB: (require 'graphviz-dot-mode) doesn't work because the file
    ;; doesn't have a (provide), but it does have an autoload.
    (setq graphviz-dot-dot-program "/usr/local/bin/dot"
    graphviz-dot-indent-width 4)
    #+end_src
    ** LaTeX
    I use LaTeX for papers and sometimes presentations in Beamer.

    Fontifying sub/superscripts can be incredibly annoying, especially
    when your file contains source code that might have underscores, so
    I turn off =tex-fontify-script=.

    #+begin_src emacs-lisp
    (require 'tex-mode)

    (defvar texlive-bin
    "/usr/local/texlive/2014/bin/x86_64-darwin"
    "The location of the TeXlive distribution binaries.")

    (setq latex-run-command (concat (expand-file-name "pdflatex" texlive-bin) " -shell-escape")
    tex-bibtex-command (expand-file-name "bibtex" texlive-bin)
    tex-fontify-script nil)
    #+end_src

    * Utilities
    ** Uniquify
    =uniquify= is a built-in library that renames buffers according to
    relative paths instead of adding numbers to the names like
    =foo.txt<2>=.

    #+begin_src emacs-lisp
    (require 'uniquify)
    (setq uniquify-buffer-name-style 'forward)
    #+end_src
    ** Ido
    Ido mode provides a nice way to navigate the filesystem. These
    tweaks come from ESK.
    #+begin_src emacs-lisp
    (ido-mode t)
    (ido-ubiquitous-mode)
    (setq ido-enable-prefix nil
    ido-enable-flex-matching t
    ido-auto-merge-work-directories-length nil
    ido-create-new-buffer 'always
    ido-use-filename-at-point 'guess
    ido-use-virtual-buffers t
    ido-handle-duplicate-virtual-buffers 2
    ido-max-prospects 10)

    (global-set-key (kbd "C-x M-f") 'ido-find-file-other-window)
    #+end_src
    ** ffap
    Find file at point is useful for jumping between files based on
    the word pointed at, e.g. Erlang modules in the current directory.

    #+begin_src emacs-lisp
    (require 'ffap)
    #+end_src

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

    #+begin_src emacs-lisp
    (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)
    #+end_src

    ** Magit
    Magit is the best VCS tool I've ever used. It makes all sorts of
    things in git easier.

    I add an advice around launching Magit that saves and restores the
    previous window configuration when exiting. This lets you
    "fullscreen" changes and other VCS windows, then quickly return to
    your previously opened buffers and windows.

    I also set the diff switches to use unified diffs, which ESK also
    does.

    #+begin_src emacs-lisp
    (setq magit-last-seen-setup-instructions "1.4.0")

    (require 'magit)
    ;; TODO is this needed if we have the PATH set correctly?
    (setq magit-git-executable "/usr/local/bin/git")
    (global-set-key (kbd "C-c g") 'magit-status)

    (defadvice magit-status (around magit-fullscreen activate)
    (window-configuration-to-register :magit-fullscreen)
    ad-do-it
    (delete-other-windows))

    (defun magit-quit-session ()
    "Restores the previous window configuration and kills the magit buffer"
    (interactive)
    (kill-buffer)
    (when (get-register :magit-fullscreen)
    (jump-to-register :magit-fullscreen)))

    (define-key magit-status-mode-map (kbd "q") 'magit-quit-session)

    (setq diff-switches "-u")
    #+end_src

    ** Ag
    =ag= (aka =the_silver_searcher=) is a great command-line tool for
    finding things in programming source files.

    #+begin_src emacs-lisp
    (require 'ag)
    (global-set-key (kbd "C-x C-g") 'ag-project) ;; Bind C-x C-g to ag-project
    #+end_src

    ** Dash
    Dash is a Mac OS/X documentation browser and has a nice way to
    launch it from Emacs.

    #+begin_src emacs-lisp
    (require 'dash-at-point)
    (global-set-key (kbd "C-c d") 'dash-at-point)
    #+end_src
    ** Neotree
    Neotree is the only "project browser sidebar" thing I've ever been
    able to tolerate. It does a pretty good job if you turn off the
    icons and base its colors on the theme.

    #+begin_src emacs-lisp
    (setq neo-theme 'ascii)
    (custom-set-faces
    '(neo-banner-face ((t . (:inherit shadow))) t)
    '(neo-header-face ((t . (:inherit shadow))) t)
    '(neo-root-dir-face ((t . (:inherit link-visited :underline nil))) t)
    '(neo-dir-link-face ((t . (:inherit dired-directory))) t)
    '(neo-file-link-face ((t . (:inherit default))) t)
    '(neo-button-face ((t . (:inherit dired-directory))) t)
    '(neo-expand-btn-face ((t . (:inherit button))) t))
    #+end_src