Literate Dotfiles Files

Table of Contents

1 Introduction

Hello! You have found my dotfile configurations. These are customizations I have arrived at in my search for a useful, personalized working environment. Not all of my environment is recorded here (anything requiring privacy is held elsewhere) but most of it is.

1.1 Getting At The Configurations Contained In This File

So, odds are good that you will take a look-see over this document and either:

  • Immediately recognized how to use it

… or …

  • Have no idea how this is meant to be used

To the latter: this is an org mode document written in a literate programming style. To be usable, it needs to be tangled once opened inside of an Emacs org mode buffer. To do this, sit in front of a buffer containing this file and type C-c C-v t.

The selections of code listed below will then be assembled into usable dotfiles, contained inside of ~/config. Linking the desired dotfiles into the home directory is left up to the reader.

Please note:

  • this documents targets Ubuntu systems.
  • sprinkled throughout are commands that will need to be executed. To use org-mode, you will need to clone and build a git repository, for example.

2 Emacs

I think of Emacs as a platform for text centric applications. A lot of what I'm going to be configuring may not be that useful if all you require is a text editor.

The Ubuntu package we desire is emacs25, which is the latest version with a GTK interface.1 Because we are going to be building org-mode from a git repository, we will also need to install build-essential, and texinfo

apt install emacs25 build-essential texinfo

2.1 Fundamental Configurations

The following configurations affect the whole program, are used to extend the whole program, or provide a platform from which more local customizations will be made.

2.1.1 User Information

Lets start off with something really simple. We can tell Emacs who we are.

(setf user-full-name "Keifer Miller")
(setf user-mail-address "keifer.miller@gmail.com")

And now Emacs can tell the world who we are. Should we choose to email it.

2.1.2 Getting Ready for Package Management

MELPA is a wonderful, extensive emacs package archive. There are others, but this one is my repository of choice.

(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)

I find it useful to make it possible for different versions of emacs to have separate package installs.

(setf package-user-dir (expand-file-name (concat "elpa/" emacs-version) user-emacs-directory))

TODO: Cite what is happening By default, Emacs will activate installed packages after processing the init file. I don't want that to be the case, I only want things to be active as I need them.

(setq package-enable-at-startup nil)

This is all the configuration I do for how packages should be managed. Let's get the system into a useable state:

(require 'cl)

(package-initialize)

(unless (and (package-installed-p 'use-package)
           (package-installed-p 'delight))
  (progn
    (package-refresh-contents)
    (map nil 'package-install '(use-package delight))))

(require 'use-package)

That will set things up for managing package installation with use-package. Org-mode is a large enough project, however, that I like to checkout their git repository and manage the package myself. This has kept me from getting burned by new bugs or major changes in the past.

First, clone the repository and build it:

mkdir -p ~/repos/
if ! [ -e ~/repos/org-mode/ ]; then git -C ~/repos clone git://orgmode.org/org-mode.git; fi
pushd ~/repos/org-mode/
make
popd

Then, we need to load it in emacs:

(add-to-list 'load-path (expand-file-name "~/repos/org-mode/lisp"))
(add-to-list 'load-path (expand-file-name "~/repos/org-mode/contrib/lisp"))
(add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\|txt\\)$" . org-mode))
(require 'org)

2.1.3 Slimming Down The User Interface

When I first started using Emacs, I did it inside of a terminal.

I used it with the same workflow I use for vi. Open a file. Edit it. Close Emacs. Run a compiler or restart a daemon. Repeat. I was dropping in to Emacs from the shell, so running it a terminal made sense. Nowadays I'm more apt to drop into a shell from inside Emacs's graphical client. But I still prefer the slimmer terminal style interface.

It feels cleaner to me. So lets get rid of the omnipresent widgets from the windowed client. We'll do this by adding settings to the default-frame-alist, which Emacs draws from when creating a new frame. There are other (maybe more idiomatic) ways to set these values (see tool-bar-mode and menu-bar-mode) which work by setting the value for the current frame. But when using Emacs' daemon functionality, there won't be a current frame when this code is evaluated. Setting the default frame values gets around this. For a list of possible default frame parameters, see the manual.

(add-to-list 'default-frame-alist '(vertical-scroll-bars . nil))
(add-to-list 'default-frame-alist '(tool-bar-lines . 0))

Dialog boxes are also present in the graphical client. I find them to be pretty jarring intrusions into the otherwise keyboard centered world I expect of Emacs. Luckily, disabling them is a single variable away.

(setf use-dialog-box nil)

The menu bar makes an appearance in both the terminal client and the windowed client. I found it clunky to use from inside of a terminal, so I never got into the habit of using it. It is more intuitive in the GUI (it is just a menu bar after all), but that lack of a habit carries over there too.

(menu-bar-mode -1)

Similarly, I've never found a reason to allow the splash screen to display on a freshly launched Emacs session. I'd much rather drop into the *scratch* buffer, which is what Emacs chooses to display when the splash is disabled.

(setf inhibit-splash-screen t)

Delight mode provides a simple way to control how modes appear in the ModeLine. It will be used in various places in this file, mainly to prevent modes from showing up in the mode line entirely. I do this if the mode is self evident when enabled, always enabled, and doesn't provide a meaningful menu when clicked on.

There will be scenarios where lots of modes are on at once. Without this the Mode Line will get really cluttered really fast.

(require 'delight)

Finally, my most basic instinct in life is to hit 'y' when I want to accept a prompt. Lets swap out the 'yes or no' prompt with one that is more concise.

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

2.1.4 Setting a Font

I use Adobe's Source Code Pro font through out most of my desktop. I find that the various weights of this font have different "feels", but all of them work well for me. At present I am using the Black weight because it does a good job of staying readable at small sizes.

(add-to-list 'default-frame-alist '(font . "Source Code Pro Black-9"))

2.1.5 TODO Backups

By default, emacs will save backup files filename~ in the same directory as the file they stem from. This can lead to clutter fast, so we'll contain them in ~/config/.emacs.d/backups

2.1.6 Completion and Selection Interface

Helm is a completion framework. Completion happens on a window basis instead of the minibuffer, and TAB allows access to selection of actions instead of completion. Helm works by throwing up everything available and then you narrow down the range with search criteria.

Out of the box, helm provides helm enabled versions of many commands. You can bind keys to just the ones you want, or you can enable them all.

Since helm is enabled globally, it isn't that useful for it to show in the ModeLine. All it does is bloat up the place.

By default, helm's window will have a lot of dead space once you've searched enough to have a reasonable number of candidates. It is helpful to have helm slim down its window in such cases.

(use-package helm
  :diminish helm-mode
  :ensure helm
  :config (progn
        (require 'helm-config)
        (helm-mode 1)
        (helm-autoresize-mode 1)))

2.2 General Editing

The following configurations are focused on editing text, but aren't predicated on specific contexts when doing so. Plain text, configuration files, or programming, it is all equally valid.

2.2.1 Improving Tone

Write Good mode aims to improve prose by highlighting weasel worlds, passive voice, and duplicate words.

(use-package writegood-mode
  :ensure writegood-mode
  :diminish writegood-mode
  :init (add-hook 'text-mode-hook 'writegood-mode))

2.2.2 Spell Checking

The Flyspell package highlights misspellings as soon as they are finished (i.e. whitespace is typed) or as soon as the point moves into them. It leverages the Ispell functionally already present in Emacs.

By default, flyspell will only highlight words that your pointer has interacted with. I'd rather have it highlight everything when it starts in the buffer. The flyspell-buffer command will move the point through the entire buffer, checking everything. It then returns the point to where it was before the check.

Flyspell isn't one of the facets of Emacs that Helm wraps by default, but the helm-flyspell package fills the gap.

Now that a Helm driven interface for Flyspell is present, I want to leverage it when correcting the word under the point. Lets bind over the default C-c $ binding

(use-package flyspell
  :ensure flyspell
  :commands flyspell-mode
  :config (progn
            (setenv "DICTIONARY" "en_US")
            (setf ispell-program-name "aspell")
            (add-hook 'flyspell-mode-hook 'flyspell-buffer)
            (use-package helm-flyspell
          :ensure helm-flyspell
          :bind* ("C-c $" . helm-flyspell-correct))))

2.2.3 Auto Completion

Company mode is an auto-complete system with a separated frontend / backend design.

Company works well in both plain text and programming contexts, so I use it everywhere I can. My spelling is terrible and every little bit helps.

Since company is enabled globally, it isn't that useful for it to show up in the mode line. Especially since it is pretty obvious when it is enabled.

By default, company waits half a second before it automatically starts to complete. I find that to be a little too long.

(use-package company
  :ensure company
  :diminish company-mode
  :init (add-hook 'after-init-hook 'global-company-mode)
  :config (setf company-idle-delay 0.25))

2.2.4 Snippets

Yasnippet is a text expansion system for emacs similar to the behavior found in Textmate. The snippets that ship with yasnippet are focused on programming, but there is nothing about yasnippet itself that makes it programming specific. Possible uses for snippets in everyday life:

  • Citing papers
  • Recording notes
  • Capturing bookmarks
  • Writing recipes

Yasnippet separates the mode from the snippets. For it to be useful, you might find that you'll need to include some snippet repositories.

First, clone some snippet repositories. yasnippet-snippets and yasmate are likely canidates:

mkdir -p ~/repos/
if ! [ -e ~/repos/yasnippet-snippets/ ]; then git -C ~/repos clone git://github.com/AndreaCrotti/yasnippet-snippets; fi

Then add them to your list of snippet directories.

(use-package yasnippet
  :ensure t
  :init (progn
            (yas-global-mode 1)
            (setf yas-snippet-dirs (expand-file-name "~/repos/yasnippet-snippets"))))

2.2.5 Whitespace

I like how simple the implementation of Visible Whitespace Mode is, but I am going to go with Whitespace Mode to grab the additional features it offers.

(global-whitespace-mode 1)

The whitespace-style variable controls whitespace visualization. The values lines and line-tails control visualization of long lines, which isn't really whitespace. Unfortunately, lines is a default value.

Lets set the style to the default value (face, tabs, spaces, trailing, lines, space-before-tab, newline, indentation, empty, space-after-tab, space-mark, tab-mark, and newline-mark) minus lines.

(setf whitespace-style '(face tabs spaces trailing space-before-tab newline indentation empty space-after-tab space-mark tab-mark newline-mark))

The symbols that get displayed in place of white space don't make a lot of sense if you've got a full featured font capable of handling symbols like ΒΆ. Lets take advantage of those fonts.

The variable whitespace-display-mappings controls the display of whitespace characters.

(setf whitespace-display-mappings '((space-mark 32
                                                [183]
                                                [46])
                                    (space-mark 160
                                                [164]
                                                [95])
                                    (newline-mark 10
                                                  [182 10])
                                    (tab-mark 9
                                              [187 9]
                                              [92 9])))

2.3 Programming

Here is what many would consider to be the meat and potatoes of Emacs: programming. Emacs has a pantheon of modes that transform its idioms to better match the programming languages you'll be using on a daily basis.

2.3.1 Haskell

Haskell Mode is the defacto standard mode for editing Haskell in Emacs. Somewhat surprisingly (or not), Emacs does not ship with a mode for Haskell out of the box. Happily the mode is available on MELPA.

(use-package haskell-mode
  :ensure haskell-mode
  :diminish haskell-mode
  :init (progn (add-hook 'haskell-mode-hook 'haskell-indentation-mode)
               (add-hook 'haskell-mode-hook 'intero-mode)
               (use-package intero
                 :ensure intero
                 :diminish intero)))

Because Haskell is whitespace sensistive, there is good reason to want to use Haskell Mode. Or, rather, the one of the minor indention mode that ships with it:

  • haskell-simple-indent-mode: use TAB to align indention with prior line.
  • haskell-indent-mode: use TAB to cycle through possible / legal indention points.
  • haskell-indentation-mode: like haskell-indent, but rebinds RETURN and DEL for cleaner behavior.

haskell-indentation-mode gets the most bang for the buck.

2.3.1.1 Intero

Intero is a "complete interactive development program for Haskell." it hooks into haskell-mode and stack to provide a company backend, and additional type checking features.

2.4 Communication

2.4.1 Engine Mode

Engine Mode allows one to take the url used to query on a search engine, and use it to generate a function that will search on inputed text (or the text at point / in region). It also makes it simple to bind these functions to keys.

(use-package engine-mode
  :ensure engine-mode
  :config (progn
        (engine-mode 1)
        (defengine duckduckgo "https://duckduckgo.com/html/?q=%s"
          :keybinding "d")))

It can map these search engines to key bindings under the C-x / map.

2.4.2 Internet Relay Chat

ERC is one of the two main Internet Relay Chat clients shipped with Emacs. The other is rcirc. I'm going to regularly be using it to connect to Freenode, and the irc gateway for a slack group.

(require 'erc)

I want to be able to auto join my frequented rooms when I connect to the server. However, I've migrated my irc usage through ZNC, and this problem is better solved in that space. The following clears out ERC's autojoin features.

(erc-autojoin-mode nil)
(setf erc-autojoin-channels-alist nil)

The Slack gateway does a lot of mode setting when people come and go from their interface. It can be hard to keep track of the conversation amongst the mode change spam. The erc-hide-list variable provides a way to opt out of seeing these messages.

(setf erc-hide-list '("MODE"))

ERC ships with a module that handles integrating flyspell into itself, but does not enable it my default.

(erc-spelling-mode 0)

2.4.3 Email

  (setf gnus-select-method
            '(nnimap "gmail"
                     (nnimap-address "imap.gmail.com")
                     (nnimap-server-port "imaps")
                     (nnimap-stream ssl)))

  (setf stmpmail-service 587)
  (setf gnus-ignored-newsgroups "^to\\.\\|^[0-9. ]+\\( \\|$\\)\\|^[\"]\"[#'()]")

(setf gnus-secondary-select-methods '((nntp "news.eternal-september.org")))

2.4.4 Feed Reading

Elfeed is a feed reader that supports both RSS and ATOM, which is a prerequisite if I'm going to be using it.

(use-package elfeed
  :ensure elfeed
  :config (setf elfeed-feeds
            '("http://cyclingspokane.blogspot.com/feeds/posts/default"
              "http://surlybikes.com/site/rss" "http://ridingthecatskills.com/feed/"
              "http://rss.earwolf.com/hello-from-the-magic-tavern"
              "http://feeds.feedburner.com/dancarlin/history?format=xml"
              "http://feeds.feedburner.com/dancarlin/commonsense?format=xml")))

Adding feeds to read is as simple as sticking them inside the elfeed-feeds list.

2.5 Media

2.5.1 TODO EMMS

(use-package emms
  :ensure t
  :config (progn (emms-standard)
                 (emms-default-players)))

2.6 Project Management

Lets define a project as a bunch of related files and folders contained inside of a parent directory. It might be a web page. Or a journal. The following configurations are focused on making life easy when you need to work within projects.

2.6.1 Git

Magit is a feature rich interface for working with git repositories inside of emacs. It does a surprisingly good job of being user friendly while mirroring the flags of the git command line utility inside of its interface. Not only is it a good way to work with git, it is a good way to learn how to work with git inside of a command line.

It isn't bundled with Emacs, but is one of Emac's most popular projects. Grab it from MELPA.

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

I depend on Magit for all of my Git interactions inside of Emacs. So I've bound it to C-g

2.6.2 Project Switching

Projectile is a framework for working with projects within emacs.

(use-package projectile
  :ensure projectile
  :bind ("C-c p p" . helm-projectile-switch-project)
  :config (progn
        (use-package helm-projectile
          :ensure helm-projectile
          :config (helm-projectile-on))
        (projectile-global-mode)))

Helm and Projectile play together really nicely, which is convenient since they are both focused on quick selection. Projectile isn't in the scope of the default Helm package, but the helm-projectile package in MELPA covers the gap.

Most of my usage inside of emacs takes place inside of projects, so turning projectile on everywhere makes since.

The first thing I tend to do when launching Emacs is switching to a project. Having a global binding to do that is handy.

2.7 Org Mode

Org Mode provides many different features and is rather fiddly to describe. Roughly speaking, it comprises a markup language, and tools for data capture, literate coding, document publishing, time tracking, and task management. It is powerful and easy to got lost in.

The most obvious use for Org is creating outlines and tracking tasks.

I'm using to write this file. I use it alot. It is a big part of why I use Emacs. And I've got several global key bindings to speed up my workflow.

(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)
(global-set-key "\C-cb" 'org-iswitchb)
(global-set-key "\C-cc" 'org-capture)
(global-set-key "\C-co" (lambda ()
                          (interactive)
                          (find-file "~/repos/org-files/index.org")))

The org-indent-mode helps org files keep from being visually cluttered.

(setf org-startup-indented t)

My main .org file is ~/config/git/org/index.org and this is where I want to capture org notes to by default. I want to be able to refile headlines and use the agenda on any file in ~/config/git/org. When I refile I want to be able to progress a fair ways into my tree, which is reflected by (:maxlevel. 5) in my refile target. If that didn't make any sense, now would be a good time to browse over to the org-mode homepage.

(setf org-directory (expand-file-name "~/repos/org-files"))
(setf org-agenda-files (list org-directory
                          (concat org-directory "/potential-projects")
                          (concat org-directory "/organizer")))
(setf org-default-notes-file (concat org-directory "/capture.org"))
(setf org-refile-targets '((org-agenda-files . (:maxlevel . 9))))

At some point in the future, I would like to subdivide my capture templates into the categories outlined by the POIC system:

  • Record
  • Discovery
  • Task
  • Citation

As it stands, however, I have Todos and Appointments (which would go under Task in the above). Note that using an empty string for the file location causes org to use the org-default-notes-file.

(setf org-capture-templates
   `(("t" "Todo" entry (file+headline ,org-default-notes-file "Tasks")
         "* TODO %?\n%i\n")
        ("a" "Appointment" entry (file+headline ,org-default-notes-file "Appointments")
         "* TODO %? %^G\nSCHEDULED: %^T\n %i\n")))

Babel is a literate programming component of Org. It provides a way to work with blocks of code inside of org files. These blocks are able to refer to each other, and blocks of different languages can interact. A full list of babel languages can be found on worg.

These are the ones I use:

(org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t)
                                                        (lisp . t)
                                                        (ditaa . t)
                                                        (shell . t)
                                                        (ruby . t)))

I want code blocks in my files to look as I would expect them to in their own major mode.

(setf org-src-tab-acts-natively t)
(setf org-src-fontify-natively t)

The org-src-window-setup variable controls what the behavior will be when org opens up a source block in a new buffer.

(setf org-src-window-setup 'reorganize-frame)

Org's default behavior when evaluating code blocks is to ask you to confirm first. This is a safe and sane choice, but it gets a little repetitious when working with lots of blocks.

(setf org-confirm-babel-evaluate nil)

My personal website is driven by my org mode repository, so I need a sane way to publish it. This used to be accomplished using a setup based on the one described in Org Mode - Organize Your Life In Plain Text!

<div id="sidebar">
  <div id="header">
    <div id="navigation">
      <div class="navigation-block">
        <h2>Blog</h2>
        <ul id="blog-navigation">
          <li><a href="/">Index</a></li>
        </ul>
      </div>
      <div class="navigation-block">
        <h2>Projects</h2>
        <ul id="projects-navigation">
          <li><a href="/common-place/README.html">Common Place</a></li>
          <li><a href="/dotfiles/dotfiles.html">Dotfiles</a></li>
        </ul>
      </div>
    </div>
  </div>
</div>
(require 'ox-publish)
(setf org-html-head-include-default-style nil)

(setf org-publish-project-alist
   '(("org-notes"
   :base-directory "~/repos/org-files"
   :publishing-directory "/ssh:nginxsite@keifer.link:keifer.link/"
   :exclude "private"
   :recursive t
   :publishing-function org-html-publish-to-html
   :headline-levels 5
   :html-postamble nil
   :html-preamble 
   "<div id=\"sidebar\">
             <div id=\"header\">
              <div id=\"navigation\">
        <div class=\"navigation-block\">
                 <h2>Blog</h2>
                 <ul id=\"blog-navigation\">
                  <li><a href=\"/\">Index</a></li>
                 </ul>
        </div>
        <div class=\"navigation-block\">
                 <h2>Projects</h2>
        <ul id=\"projects-navigation\">
                  <li><a href=\"/common-place/README.html\">Common Place</a></li>
                  <li><a href=\"/dotfiles/dotfiles.html\">Dotfiles</a></li>
        </ul>
        </div>
              </div>
             </div>
        </div>"
   :html-head "<link href=\"http://keifer.link/css/stylesheet.css\" rel=\"stylesheet\"></link>"
   :html-head-include-default-style t
   )
     ("org-static"
   :base-directory "~/repos/org-files"
   :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
   :publishing-directory "/ssh:nginxsite@keifer.link:keifer.link/"
   :exclude "private"
   :recursive t
   :publishing-function org-publish-attachment)
     ("org" :components ("org-notes" "org-static"))))
(defun publish-org nil
  "Publish Org Notes"
  (org-publish-project "org" t))

Overall, I was pretty happy with how org exports to html. I just disagree with the idea that unruled tables are more readable:

(setf org-html-table-default-attributes '(:border "1"
                                          :cellspacing "0"
                                          :cellpadding "3"
                                          :rules "all"
                                          :frame "all"))

Footnotes:

1
The GTK build of emacs suffers from a bug which kills the daemon when X11 exits. If you wish to persist your emacs session after exiting X11, the emacs25-lucid package may be of interest.