Alex’s Emacs Configuration

;; -*- lexical-binding: t -*-



I stole the outline of this from qDot, and then someone else’s init.el, and then bashed things together until they worked right.

Basic Setup


Anything in this section relates to the core setup of emacs. Since I’m not using the weird Ouroboric self-tangling thing qDot was, we’ve already got use-package, org, and cl-lib loaded.

Prefer UTF-8 everywhere:

(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-language-environment "UTF-8")

Set up some simple platform finding variables.

(defvar linux-p (eq system-type 'gnu/linux) "True if using Linux, nil otherwise")
(defvar macosx-p (eq system-type 'darwin) "True if using Mac OS X, nil otherwise")
(defvar mswindows-p (eq system-type 'windows-nt) "True if using windows, nil otherwise")

Don’t need startup screens.

(setq inhibit-splash-screen t)

Make the bell blink, but only on non-Mac platforms. I prefer the Mac OS-level vbell.

(unless macosx-p (setq visible-bell t))

Don’t end sentences with a double space. This is important for fill functions.

(setq sentence-end-double-space nil)

Make sure message log is really, really big in case I screw something up.

(setq message-log-max 5000)

Make sure there’s no dialog on platforms that might try to bring one up.

(when (or mswindows-p macosx-p)
  (defadvice y-or-n-p (around prevent-dialog-yorn activate)
    "Prevent y-or-n-p from activating a dialog"
    (let ((use-dialog-box nil))

  (defadvice yes-or-no-p (around prevent-dialog activate)
    "Prevent yes-or-no-p from activating a dialog"
    (let ((use-dialog-box nil))

Put autosave files (ie #foo#) in one place, not scattered all over the file system.

(defvar alexm/autosave-dir (concat user-emacs-directory "autosaves/"))
(make-directory alexm/autosave-dir t)
(setq auto-save-file-name-transforms
      `((".*" ,alexm/autosave-dir t)))

Kill the fuck out of backup files.

(setq make-backup-files nil)

Scroll by up to 20 lines to get point back on screen.

(setq scroll-conservatively 20)

Make sure page up and page down are symmetric, so M-v undoes C-v perfectly.

(setq scroll-preserve-screen-position 'always)

Ensure files end with lines.

(setq require-final-newline t)

I like seeing keystrokes after a bit.

(setq echo-keystrokes 0.5)

I like seeing garbage collection and up the limit a bunch.

(setq garbage-collection-messages t
      gc-cons-threshold (* 64 1024 1024))

Clean up some bozotic defaults:

 Custom-buffer-done-kill t
 backward-delete-char-untabify-method nil
 case-fold-search t
 calendar-week-start-day 1
 calendar-latitude 56.0
 calendar-longitude 2.0
 completion-show-help nil
 default-frame-scroll-bars nil
 diff-switches "-u"
 enable-recursive-minibuffers t
 indent-tabs-mode nil
 js-indent-level 2
 ispell-program-name "aspell"
 kill-read-only-ok t
 kill-whole-line t
 read-quoted-char-radix 16
 recenter-positions '(bottom middle)
 remote-shell-program "/usr/bin/ssh"
 send-mail-function 'sendmail-send-it
 vertical-scroll-bar nil
 whois-server-name ""
 word-wrap t
 x-select-enable-clipboard t
 yow-file "~/.emacs.d/yow.lines"
(when (fboundp 'set-scroll-bar-mode) (set-scroll-bar-mode nil))



Something to make setting faces easier — this works a lot like custom-set-faces but doesn’t use that machinery. You can call it with customize blobs, though.

(defun alexm/set-faces-by-spec (&rest specs)
  "Maps SPECS through face-spec-set."
  (mapc #'(lambda (f) (apply #'face-spec-set f)) specs))

Rot13 as Message

Do a rot13, but display it in a message instead of modifying the buffer.

(defun alexm/rot13-region (start end)
  "Display the ROT13 encryption of the region between START and END in current buffer."
  (interactive "r")
  (display-message-or-buffer (rot13 (filter-buffer-substring start end))))

Timestamp Utilities

Define a macro because there’s three time-formatting functions coming up.

These are, eventually, bound all the way down there.

(defmacro alexm/defstamper (name format)
  `(defun ,name (arg)
     (interactive "P")
     (let ((stamp (format-time-string ,format nil t)))
       (if arg
           (kill-new stamp)
         (insert stamp)))))

Kill, or with a prefix argument, insert, the current timestamp in modified ISO8601.

(alexm/defstamper alexm/stamp-m8601 "%Y.%m.%d..%H.%M.%S")

Kill, or with a prefix argument, insert, the current datestamp in modified ISO8601.

(alexm/defstamper alexm/stamp-m8601-date "%Y.%m.%d")

Kill, or with a prefix argument, insert, the current datestamp in RFC-2822 format.

(alexm/defstamper alexm/stamp-rfc2822 "%a, %d %b %Y %T %z")
(defun alexm/restore-text-scale nil
  "Return text size to normal"
  (text-scale-increase 0))

Text cleansers

(defun alexm/clean-up-mesos-stacktraces nil
  "Make a Mesos stack-trace readable. Intended to be invoked immediately after pasting the offending trace."
    (let ((end-of-trace (point)))
      (goto-char (search-backward "Traceback (most recent call last):"))
      (while (and (< (point) end-of-trace)
                    (seq "/var/lib/mesos" (* nonl) "sandbox")
                    (? "/.pex/" (| "code" "install") "/")
                    (* (not (any "/"))) "/")
        (replace-match "")))))

Convenience tools

Don’t kill on first Cmd-Q

Only kill emacs if I hit Cmd-Q twice in ten seconds.

(defun alexm/dont-kill-on-first-cmd-q (_)
  "Beep, message the user, and then clear confirm-kill-emacs for 10 seconds."
    (message "Repeat that command within 10 seconds if you're sure.")
    (setq confirm-kill-emacs nil)
     10 nil
     #'(lambda nil
         (setq confirm-kill-emacs #'alexm/dont-kill-on-first-cmd-q)))))
(setq confirm-kill-emacs #'alexm/dont-kill-on-first-cmd-q)
OS X Location hook

Maintain the variables set by osx-location, which see.

Also, start the timer for celestial-mode-line, if it’s not already running.

(defun alexm/osx-location-changed nil
  (setq calendar-latitude osx-location-latitude
        calendar-longitude osx-location-longitude
        (format "%s, %s" osx-location-latitude osx-location-longitude))
  (unless celestial-mode-line--timer

Theme, Display, Font, and Modeline setup

Set the theme.

(load-theme 'wombat t)

Correct highlight face to not have underlining, and to not modify the foreground. Also, make the inactive modeline less ugly.

 '(region ((t (:background "#a0df00" :foreground unspecified))))
 '(highlight ((t (:underline nil
                             :foreground unspecified
                             :background "#455445"))))
 '(mode-line-inactive ((t (:foreground "#999999")))))

Use fonts we either know we have, or can check for. Symbola is used to fill in missing glyphs for odd emoticons that pop up on IRC/IM usually.

(when (member "Symbola" (font-family-list))
  (set-fontset-font "fontset-default" nil
                    (font-spec :size 20 :name "Symbola")))
(when macosx-p
  (set-face-font 'default "Menlo-10"))
(when mswindows-p
  (set-face-font 'default "consolas-10"))
(when linux-p
  (set-face-font 'default "Fixed-11"))

Set up modeline and display variables.

(setq-default display-time-format "%Y%m%dT%H%M"
              '("%e" mode-line-mule-info
                mode-line-modified " " mode-line-buffer-identification " "
                mode-line-position " " mode-line-modes " "
                (vc-mode vc-mode) " " mode-line-misc-info
(column-number-mode t)

Actually show the region we’re selecting when marking.

(transient-mark-mode t)

If a file is reverted outside of emacs, and its buffer has NOT been edited inside emacs, automatically revert it.

(global-auto-revert-mode t)

Transparently open compressed files.

(auto-compression-mode t)

Save a list of recent files visited.

(recentf-mode 1)
(add-to-list 'recentf-exclude "-autoloads\\.el\\'")
(add-to-list 'recentf-exclude "\\.el\\.gz\\'")

Just expect font lock to be on everywhere, and turn up the gaudiness.

(setq font-lock-maximum-decoration t)
(global-font-lock-mode 1)

Back-tab sometimes gets fucky. Unfuck it.

(define-key key-translation-map "\M-[Z" (kbd "<backtab>"))

Set up default window sizes.

(setq initial-frame-alist
      '((tool-bar-lines . 0)
        (menu-bar-lines . 0)
        (width . 80)
        (height . 60))
      default-frame-alist initial-frame-alist)

Package Configuration

This section contains installation and configuration information for all the packages I use.

In order to quickly access configurations, the org nodes are named after the mode the package exposes, as well as having each configuration node tagged with the ’package’ tag.


I use passacre for password management. I prefer that it prompt for confirmation.

(require 'passacre)
(setq passacre-confirm t)


A lot of my goddamn life is on IRC.

circe   package

Here comes my IRC config! Watch out, it’s a DOOZY!

(use-package circe
    :ensure t
    :bind (:map lui-mode-map
                ("M-a" . tracking-next-buffer)
                ("C-u" . lui-kill-to-beginning-of-line))
    :load-path "~/package/circe-discord"
    (require 'circe-chanop)
    (require 'circe-lagmon)
    (require 'circe-rainbow)
    (require 'circe-probe)
    (require 'circe-color-nicks)
    (require 'circe-new-day-notifier)
    (require 'lui-irc-colors)
    (add-hook 'circe-chat-mode-hook #'alexm/circe-chat-mode)
    (add-hook 'circe-server-mode-hook #'alexm/circe-server-mode)
    (add-hook 'circe-server-connected-hook #'alexm/server-connected)
    (add-hook 'circe-channel-mode-hook #'alexm/channel-mode)
    (add-hook 'circe-query-mode-hook #'alexm/query-mode)
     '(circe-my-message-face ((t (:foreground "grey95"))))
     '(circe-fool-face ((t (:foreground "grey20"))))
     '(circe-highlight-nick-face ((t (:foreground "magenta" :weight bold))))
     '(circe-prompt-face ((t (:foreground "#00eebb" :background "unspecified"))))
     '(circe-server-face ((t (:foreground "steelblue" :weight unspecified))))
     '(lui-irc-colors-bg-5-face ((t (:background "sienna4"))))
     '(lui-irc-colors-bg-7-face ((t (:background "orange4"))))
     '(lui-irc-colors-bg-11-face ((t (:background "#00e5e5"))))
     '(lui-irc-colors-bg-12-face ((t (:background "steelblue1"))))
     '(lui-irc-colors-fg-2-face ((t (:foreground "#66ccff"))))
     '(lui-irc-colors-fg-3-face ((t (:foreground "#66ff66"))))
     '(lui-irc-colors-fg-4-face ((t (:foreground "#ff0000"))))
     '(lui-irc-colors-fg-5-face ((t (:foreground "sienna3"))))
     '(lui-irc-colors-fg-7-face ((t (:foreground "orange2"))))
     '(lui-irc-colors-fg-8-face ((t (:foreground "yellow2"))))
     '(lui-irc-colors-fg-9-face ((t (:foreground "#00ff00"))))
     '(lui-irc-colors-fg-11-face ((t (:foreground "LightCyan3"))))
     '(lui-irc-colors-fg-12-face ((t (:foreground "lightblue1"))))
     '(lui-time-stamp-face ((t (:foreground "green" :weight bold)))))
     lui-fill-column 0
     lui-fill-type nil
     lui-highlight-keywords '(("atax1a" circe-highlight-nick-face))
     lui-logging-flush-delay 0
     lui-max-buffer-size 300000
     lui-scroll-behavior 'post-output
     lui-time-stamp-format "%H:%M"
     lui-time-stamp-position 'right-margin
     tracking-frame-behavior nil
     tracking-ignored-buffers nil
     tracking-most-recent-first t
    (fset 'circe-command-J 'circe-command-JOIN)
    (fset 'circe-command-Q 'circe-command-QUERY)
    (fset 'circe-command-WI 'circe-command-WHOIS)
    (add-to-list 'circe-format-not-tracked
    (add-to-list 'lui-pre-output-hook 'lui-irc-colors)
    (defadvice circe-new-day-notification (before ddate activate)
      (setq circe-new-day-notifier-format-message
             "\n" " " (concat "*** " (shell-command-to-string "ddate"))))))

Override the default TIME handler with one that conforms to Erisian norms.

(defun irc-handle-ctcp--ctcp-time (conn _event sender _target _argument)
  "Handle a CTCP TIME request."
   conn (irc-userstring-nick sender) "TIME"
   (replace-regexp-in-string "\n" " " (shell-command-to-string "ddate"))))

Chat modes require margins for the timestamps.

(defun alexm/circe-chat-mode nil
  (setq right-margin-width 5
        lui-logging-directory "~/.circe-logs"
        lui-logging-file-format "{target}@{network}_%Y-%m.txt"
        lui-logging-format "[%Y%m%d_%T] {text}"))

Server, query, and channels need shorter modeline names; certain channels also get special treatment.

(defun alexm/circe-server-mode nil
  (setq mode-name "C-s"))
(defun alexm/query-mode nil
  (setq mode-name "C-q")
  (smartparens-mode -1))
(defun alexm/channel-mode nil
  (setq mode-name "C-C")
  (smartparens-mode -1)
  (when (member-ignore-case circe-chat-target (list "&bitlbee" "#techcrap"))
    (setq circe-reduce-lurker-spam t)))

When connecting to the server, rename the buffer to something reasonable.

(defun alexm/server-connected nil
   (concat circe-nick "@"
           circe-network ":"
           (number-to-string circe-port))

Haven’t gotten around to this…

(defun alexm/start-circe nil
 circe-completion-suffix ", "
 circe-default-nick "Pi"
 circe-default-user "pi"
 circe-fool-list '("wolfgang" "kyhwana" "Shad0w" "Oeskeso" "^Xenofur" "^crabs!" "~kes@" "^arcbot!" "^zetathustra!" "^Brule!" "^hal!" "^buttbot!" "^joepie91!" "^TONKA!" "Bauer")
 circe-format-self-say "<{mynick}> {body}"
 circe-format-server-topic "*** Topic change by {userhost}: {new-topic}\n*** Previously: {old-topic}\n*** Diff: {topic-diff}"
 circe-highlight-nick-type 'occurrence
 circe-new-buffer-behavior 'display
 circe-server-flood-penalty 1
 circe-server-send-unknown-command-p t
 circe-unknown-message-destination 'last-active
 circe-use-cycle-completion t
 lui-track-bar-behavior 'before-switch-to-buffer)

Emacs Customization

browse-kill-ring   package

See and update/select kill ring history.

(use-package browse-kill-ring
    :ensure t
    :commands browse-kill-ring
    :bind (("C-x y" . browse-kill-ring)))

dired   package

Set up dired with extensions, make sure beginning/end commands move inside directory listings instead of buffer.

wdired allows text editing of the dired buffer to do things like changing permissions via string/regexp replacement.

(use-package dired
    :commands dired
    :bind ("C-x d" . dired)
      ;; Additions to dired

      (load "dired-x")
      (load "wdired")
      (setq wdired-allow-to-change-permissions 'advanced)

      (defun alexm/quit-dired (_k)
        "Quit dired and do what I want with it like mutt"
        (interactive "i")
        (dired-do-flagged-delete t)
        (quit-window t))

      ;; dired modifications
      (bind-keys :map dired-mode-map
                 ("$" . dired-do-flagged-delete)
                 ("&" . dired-flag-garbage-files)
                 ("c" . find-file)
                 ("j" . dired-next-line)
                 ("k" . dired-previous-line)
                 ("q" . alexm/quit-dired)
                 ("r" . wdired-change-to-wdired-mode))

      (defun dired-back-to-top ()
        (goto-char (point-min))
        (dired-next-line (if dired-omit-mode 2 4)))

      (define-key dired-mode-map
          [remap beginning-of-buffer] 'dired-back-to-top)

      (defun dired-jump-to-bottom ()
        (goto-char (point-max))
        (dired-next-line -1))

      (define-key dired-mode-map
          [remap end-of-buffer] 'dired-jump-to-bottom)))

csv   package

Load up CSV mode.

(use-package csv-mode
    :ensure t)

dns   package

Load up DNS mode and make it handle .com and .net and .biz files.

(use-package dns-mode
    :mode "\\.\\(com\\|net\\|biz\\)\\'")


It’s REALLY ANNOYING to not get a decent $PATH. This fixes that.

(use-package exec-path-from-shell
    :if macosx-p
    :ensure t

expand-region   package

Hit M-m, expand up to the next largest region based on mode-context sensitive scope.

(use-package expand-region
    :ensure expand-region
    :bind (("M-#" . er/mark-symbol)
           ("M-m" . er/expand-region))
    :commands (er/expand-region er/enable-mode-expansions))

flyspell-mode   package

Spelling correction with wiggly red lines!

(use-package flyspell
    :diminish flyspell-mode
     flyspell-duplicate-distance 0
     flyspell-issue-message-flag nil
     flyspell-issue-welcome-flag nil
     flyspell-use-meta-tab nil))

ido   package

Make selecting files/buffers in minibuffer easier

(use-package ido
    (ido-mode t)
    (ido-everywhere t)
    (setq ido-create-new-buffer 'always
          ido-decorations '("«" "»" " " "…" "⎡" "⎦" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")
          ido-enable-flex-matching t
          ido-ignore-buffers '(":[0-9]" "\\` ")
          ido-use-virtual-buffers t)))

ido-completing-read+   package

magit wants this. give it what it wants.

(use-package ido-completing-read+
    :ensure t)

fish-mode   package

I use, for better or for worse, fish shell.

(use-package fish-mode
    :ensure t)

flx-ido   package

Make fuzzy matching for ido work better.

(use-package flx-ido
    :ensure flx-ido
      (flx-ido-mode 1)
      (setq ido-enable-flex-matching t)
      (setq ido-use-faces nil)))

ibuffer   package

List buffers in a dired-ish way. Try to group based on modes or what kind of project something may be related to.

(use-package ibuffer
    :commands (ibuffer ibuffer-list-buffers ibuffer-other-window)
    (setq ibuffer-default-sorting-mode 'major-mode
          ibuffer-always-show-last-buffer t
          ibuffer-view-ibuffer t
          ibuffer-formats '((mark modified read-only " "
                             (name 32 32 :left :elide) " "
                             (size 9 -1 :right) " "
                             (mode 16 16 :left :elide) " " filename-and-process)
                            (mark " " (name 16 -1) " " filename))))

info+   package

(use-package info+
    :ensure nil)

ledger   package

I should be doing accounting in Ledger-mode.

(defun alexm/ledger-mode nil
  (add-hook 'before-save-hook #'ledger-mode-clean-buffer t t)
  (add-hook 'before-save-hook #'delete-trailing-whitespace t))

(use-package ledger-mode
    :init (setq ledger-clear-whole-transactions t)
    :mode "\\.ledger\\'"
    (add-hook 'ledger-mode-hook #'alexm/ledger-mode)
       ((t (:background "#233223" :inherit nil))))))

lorem-ipsum   package

(use-package lorem-ipsum
    :ensure t
    :bind (("M-s l" . lorem-ipsum-insert-sentences)
           ("M-s L" . lorem-ipsum-insert-paragraphs)))

multiple-cursors   package

Work with multiple cursors simultaneously.

(use-package multiple-cursors
    :commands (mc/mark-next-like-this
    :init (use-package phi-search :ensure t)
    :bind (("C->" . mc/mark-next-like-this)
           ("C-<" . mc/mark-previous-like-this)
           ("C-*" . mc/mark-all-like-this)
           ("C-&" . mc/mark-more-like-this-extended)
           ("C-S-SPC" . mc/mark-pop))
    :ensure t)

paradox   package

Paradox makes the package list pretty and adds some stats to the listings.

(use-package paradox
    :ensure t
    :commands (paradox-list-packages)
    :config (setq paradox-github-token t))

rect-mark   package

Make rectangular region marking easier.

(use-package rect-mark
    :ensure nil
    :bind (("C-x r C-SPC" . rm-set-mark)
           ("C-x r C-x" . rm-exchange-point-and-mark)
           ("C-x r C-k" . rm-kill-region)
           ("C-x r M-w" . rm-kill-ring-save)))

savehist   package

Save minibuffer history, so oft-used functions bubble to the top.

(use-package savehist
    (savehist-mode 1)
    (setq savehist-file (concat user-emacs-directory "savehist")
     savehist-save-minibuffer-history 1
     savehist-additional-variables '(search-ring regexp-search-ring))))

saveplace   package

Make sure I always come back to the same place in a file after closing/opening.

saveplace tends to screw with buffers that have automatically folded layouts, like org-mode. It’ll open trees with none of the parents open, which causes weird problems. So org-mode is ignored.

(use-package saveplace
  (save-place-mode t)
  ;; saveplace and org-mode do not play well together, reset the regexp to include
  ;; org and org_archive files
  (setq-default save-place-ignore-files-regexp "\\(?:COMMIT_EDITMSG\\|hg-editor-[[:alnum:]]+\\.txt\\|svn-commit\\.tmp\\|bzr_log\\.[[:alnum:]]+\\|.*\\.org\\|.*\\.org_archive\\)$"))

scala   package

Let’s play with Scala!

(use-package scala-mode
    :ensure t)

tramp   package

Tramp should default to the sshx mode.

(use-package tramp
    :commands tramp
    (setq tramp-default-method "sshx"))

undo-tree   package

Allow undo to branch, and be visualized as a graph.

(use-package undo-tree
    :ensure undo-tree
    :diminish undo-tree-mode
    (global-undo-tree-mode 1))

uniquify   package

Make buffer names unique, handy when opening files with similar names

(use-package uniquify
    (setq uniquify-buffer-name-style 'post-forward-angle-brackets
          uniquify-after-kill-buffer-p t
          uniquify-ignore-buffers-re "^\\*")))

vc-fossil   package

(use-package vc-fossil
    :ensure t
    :commands (vc-fossil-registered)
    :config (add-to-list 'vc-handled-backends 'Fossil))


message-mode   package

Add Cc and Bcc headers to the message buffer

(use-package message
    :commands message-mode
    :no-require t
      (add-to-list 'mm-text-html-renderer-alist
                   '(elinks mm-inline-render-with-file nil
                     "elinks" "-dump-charset" "utf8" "-dump" file))
      (setq mail-envelope-from 'header
            mail-specify-envelope-from t
            message-default-mail-headers "Cc: \nBcc: \n"
            message-kill-buffer-on-exit t
            message-send-mail-function 'message-send-mail-with-sendmail
            message-sendmail-envelope-from 'header
            message-make-forward-subject-function 'message-forward-subject-fwd
            mm-text-html-renderer 'elinks)
      (add-hook 'message-mode-hook 'turn-on-flyspell 'append)))

notmuch-mode   package

Define spam/unspam twitchers.

(use-package notmuch
    :commands notmuch-hello
    :bind (("C-c m" . notmuch-hello))
      (unless (or (file-exists-p "~/Mail/store/.notmuch")
                  (file-exists-p "~/Maildir/.notmuch"))
        (setq notmuch-command "notmuch-spigot"))
      (if (car (file-attributes
                (concat (notmuch-database-path) "/[Gmail]/.Sent Mail")))
          (setq notmuch-fcc-dirs "\"[Gmail]/.Sent Mail\" +sent -new -unread"))
      (setq notmuch-search-oldest-first t
            notmuch-hello-hide-tags '(".bf_spam" ".bf_ham")
            notmuch-hello-thousands-separator "."
            notmuch-saved-search-sort-function 'notmuch-sort-saved-searches
            notmuch-archive-tags '("-inbox" "-unread"))
      (setq notmuch-search-line-faces
            '(("unread" . notmuch-search-unread-face)
              ("flagged" . notmuch-search-flagged-face)
              ("pagerduty" :foreground "green" :background "red")
              ("concur" :foreground "green" :background "red")
              ("alerts" :background "grey30")
              ("cron" :background "grey30")
              ("review" :background "#2B2900")
              ("ticket" :background "#260026")
              ("dogfood" :background "#012000")
              ("lists/transtaskforce" :background "#090033")


org-mode   package

Without org-mode to remind me that I’m supposed to be doing something, I’d probably just look at porn all day.

Unfortunately, I also forget to look at org-mode a lot.

A good portion of this setup is taken from Bernt Hansen’s org-mode config. It’s by far the most complete org-mode configuration I’ve ever seen.

Define a new-day function for work.

(defun alexm/org-new-day nil
  (goto-char (point-max))
  (unless (looking-at-p "^$")
  (insert "* ")
  (alexm/stamp-m8601-date nil)
  (org-insert-subheading (list 1)))

The package is already loaded by virtue of init.el, but do some configuration of it anyway.

(use-package org
    :commands (org-agenda)
    :bind (("C-c l" . org-store-link)
           ("C-c a" . org-agenda)
           ("C-M-r" . org-capture)
           :map org-mode-map
           ("C-x @ N" . alexm/org-new-day))
    :mode (("\\.org_archive\\'"  . org-mode)
           ("\\.org\\'"  . org-mode)))

Try to enable Tempo if it’s available.

(when (version<= "9.2" org-version)
  (load "org-tempo"))

Install Twitter Bootstrap exporter.

(use-package ox-twbs :ensure t)
org-mode configuration
  • Variables

    Add markdown export backend, habits module. Set habit graph over to the right.

    (load "ox-publish")
    (add-to-list 'org-export-backends 'md)
    (add-to-list 'org-modules 'org-habit)
    (add-to-list 'org-modules 'org-notmuch)
    (setq org-habit-graph-column 60)

    Look for org files in my fossil checkout.

    (add-to-list 'org-agenda-files "~/package/jerkcity/pi")

    Timestamps take notes by default.

    (setq org-log-done 'note)

    Keep drawer for logs too.

    (setq org-drawers '("PROPERTIES" "LOGBOOK"))

    Save clock data and state changes and notes in the LOGBOOK drawer.

    (setq org-log-into-drawer t)

    Show notes in a task first.

    (setq org-reverse-note-order nil)

    How much to indent in from the node level.

    (setq org-indent-indentation-per-level 2)

    Use IDO for target completion.

    (setq org-completion-use-ido t)

    Disable priorities.

    (setq org-enable-priority-commands nil)

    Don’t use super/subscript globally, makes exports weird due to underscores. If they need to be used, set them on a per file level

    (setq org-use-sub-superscripts nil)

    Use speed commands (single key commands that can be used when cursor is at beginning of a line for a node).

    (setq org-use-speed-commands t)

    I like links being active ret.

    (setq org-return-follows-link t)

    Make lists cycle whether they’re nodes or plain.

    (setq org-cycle-include-plain-lists t)

    Fontify org-src blocks like their language mode.

    (setq org-src-fontify-natively t)

    Turn on sticky agendas so we don’t have to regenerate them.

    (setq org-agenda-sticky nil)

    If there’s a region, do whatever it is I’m trying to do to ALL headlines in region.

    (setq org-loop-over-headlines-in-active-region t)

    Changes the effect of C-a/C-e when used on org node lines. Does things like making C-a go to point after stars. I agree with qDot. It’s really annoying, so turn it off.

    (setq org-special-ctrl-a/e nil)

    Do special stuff when cutting in a headline.

    (setq org-special-ctrl-k t)

    When yanking subtrees, promote/demote levels based on the node being yanked into, if any.

    (setq org-yank-adjusted-subtrees t)

    Weeks start on Monday.

    (setq org-agenda-start-on-weekday 1)

    Start agenda showing the next week by default.

    (setq org-agenda-span 7)

    Multiple pass pdf generation.

    (setq org-latex-to-pdf-process '("xelatex -interaction nonstopmode %f"
                                     "xelatex -interaction nonstopmode %f"))

    I HATE INVISIBLE EDITS. So show me where it’s happening and then make sure it doesn’t happen.

    (setq org-catch-invisible-edits 'show-and-error)

    No blank lines before headings

    (setq org-blank-before-new-entry '((heading)
                                       (plain-list-item . auto)))

    Tune the agenda view.

    (setq org-agenda-skip-scheduled-if-done nil
          org-agenda-skip-deadline-if-done t)

    Set export options for LaTeX and disable other annoying export shit.

    (setq org-export-latex-packages-alist
          '(("utf8" "inputenc")
            ("osf,sc" "mathpazo")
            ("" "amsmath"))
          org-html-postamble nil
          org-twbs-postamble nil
          org-export-with-LaTeX-fragments t
          org-export-with-tags nil
          org-export-with-author nil
          org-export-with-smart-quotes t
          org-export-with-section-numbers nil
          org-export-with-email nil
          org-export-with-date nil)

    Keep it from turning on annoying modes at startup.

    (setq org-startup-truncated nil)

    Deadlines should show up 3 days before, by default.

    (setq org-deadline-warning-days 3)
  • Publishing

    Experiment: publish personal web sites via org-publish, with Twitter Bootstrap theme.

    (defun alexm/replace-org-project (x)
      (add-to-list 'org-publish-project-alist x
                   t '(lambda (a b) (equal (car a) (car b)))))
    (let ((site-root "~/package/jerkcity/pi/sites")
          (document-root "~/public_html"))
         :base-directory ,site-root
         :base-extension "\\(?:cs\\|j\\)s\\|\\(?:png\\|jpe?g\\)"
         :publishing-directory ,document-root
         :recursive t
         :publishing-function org-publish-attachment))
      (defun* alexm/org-add-project
          (basename &rest options
                    &key (publishing-function 'org-html-publish-to-html)
           :base-directory ,(concat site-root "/" basename)
           :base-extension "org"
           :publishing-directory ,(concat document-root "/" basename)
           :auto-preamble nil
           :creator-info nil
           :html-doctype "html5"
           :html-html5-fancy t
           :html-postamble nil
           :publishing-function ,publishing-function
           :recursive t
           :section-numbers nil
           :sub-superscript nil
           :todo-keywords nil
           :with-latex t
           :with-properties t
           :with-toc nil
       :headline-levels 1
       :author (list "Pi Irrational")
       :html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">"
       :html-head-extra "<meta name=\"viewport\" value=\"width=device-width\">"
       :with-author t
      (alexm/org-add-project ""
                             :headline-levels 1
                             :publishing-function 'org-twbs-publish-to-html
                             :auto-sitemap t
                             :author '("Alex Maestas")
                             :html-head-include-scripts nil
                             :html-head "<link href=\"/bootstrap.min.css\" rel=\"stylesheet\">"
                             :with-author t)
      (alexm/org-add-project ""
                             :headline-levels 1
                             :author '("Vivisector Crew")
                             :auto-sitemap nil
                             :html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
                             :with-author nil)
      (alexm/org-add-project ""
                             :author '("Lauren Smith")
                             :headline-levels 1
                             :auto-sitemap nil
                             :with-author t))
  • Hooks

    Flyspell mode for spell checking everywhere.

    (add-hook 'org-mode-hook 'turn-on-flyspell)

    Always indent text using outline. Also delete trailing whitespace on save.

    (defun alexm/org-mode-hook nil
      (org-indent-mode t)
      (add-hook 'before-save-hook 'delete-trailing-whitespace t t))
    (add-hook 'org-mode-hook #'alexm/org-mode-hook)
  • Speed key bindings

    Using speedkeys, s will narrow to the subtree, but you have to call widen explicitly. Set capital S to widen.

    (setq org-speed-commands-user '(("S" . widen)))
  • Faces

    Sasha Chua’s org done faces

    (setq org-fontify-done-headline t)
     '(org-done ((t (:foreground "PaleGreen"
                                 :weight normal :strike-through t))))
       ((((class color) (min-colors 16) (background dark))
         (:foreground "LightSalmon" :strike-through t)))))
    ;; Set org babel backgrounds so we get nice blocks
    (set-face-background 'org-block-begin-line "#333")
    (set-face-background 'org-block-end-line "#333")
  • Refile settings

    Don’t allow refiling into anything that’s set to DONE.

    (defun alexm/verify-refile-target ()
      "Exclude todo keywords with a done state from refile targets"
      (not (member (nth 2 (org-heading-components)) org-done-keywords)))
    (setq org-refile-target-verify-function 'alexm/verify-refile-target)
  • Org Babel

    Set up languages that babel will handle.

       (emacs-lisp . t)
       (shell t)
       (org t)))


rainbow-delimiters   package

(use-package rainbow-delimiters
    :ensure rainbow-delimiters
    :commands (rainbow-delimiters-mode rainbow-delimiters-mode-enable)
     '(rainbow-delimiters-depth-1-face ((t (:foreground "green" :weight extra-bold))))
     '(rainbow-delimiters-depth-2-face ((t (:foreground "forestgreen" :weight bold))))
     '(rainbow-delimiters-depth-3-face ((t (:foreground "lightseagreen" :weight bold))))
     '(rainbow-delimiters-depth-4-face ((t (:foreground "lightskyblue" :weight bold))))
     '(rainbow-delimiters-depth-5-face ((t (:foreground "cyan" :weight bold))))
     '(rainbow-delimiters-depth-6-face ((t (:foreground "steelblue" :weight bold))))
     '(rainbow-delimiters-depth-7-face ((t (:foreground "orchid" :weight bold))))
     '(rainbow-delimiters-depth-8-face ((t (:foreground "purple" :weight bold))))
     '(rainbow-delimiters-depth-9-face ((t (:foreground "hotpink" :weight bold))))
     '(rainbow-delimiters-unmatched-face ((t (:background "red" :foreground "green" :weight bold))))))

smartparens   package

Smarter paren matching without going the paredit route.

Turning off deferred loading because this is useful almost everywhere.

(use-package smartparens
    :ensure smartparens
    :diminish smartparens-mode
    :defer nil
    :bind (("<s-right>"   . sp-forward-slurp-sexp)
           ("<s-left>"    . sp-forward-barf-sexp)
           ("<s-M-right>" . sp-backward-slurp-sexp)
           ("<s-M-left>"  . sp-backward-barf-sexp))
      (smartparens-global-mode t)
      (show-smartparens-global-mode 1)
      (setq sp-highlight-pair-overlay nil)
      (load "smartparens-config")))

cc-mode   package

Settings for C/C++ modes.

(defun alexm/cc-mode-hook ()
  (c-add-style "alexm/cc-code-style"
                 (arglist-close . c/lineup-arglist)
                 (arglist-intro . c/lineup-arglist-intro-after-paren)
                 (c-basic-offset . 4)
                 (knr-argdecl . 5)
                 (label . 0)
                 (statement-case-open . +)
                 (substatement-open . 0)))
  (c-set-style "alexm/cc-code-style")
  (c-set-offset 'innamespace 0)
  (bind-keys :map c-mode-map
             ("C-m" . newline-and-indent))
  (bind-keys :map c++-mode-map
             ("C-m" . newline-and-indent))
  (subword-mode 1))

(add-hook 'c-mode-common-hook 'alexm/cc-mode-hook)

;; function decides whether .h file is C or C++ header, sets C++ by
;; default because there's more chance of there being a .h without a
;; .cc than a .h without a .c (ie. for C++ template files)
(defun alexm/c-c++-header ()
  "sets either c-mode or c++-mode, whichever is appropriate for
  (let ((c-file (concat (substring (buffer-file-name) 0 -1) "c")))
    (if (file-exists-p c-file)
(add-to-list 'auto-mode-alist '("\\.h\\'" . alexm/c-c++-header))

compilation   package

Compilation mode.

(use-package compile
    :commands (compile)
    (setq compilation-disable-input nil
          compilation-auto-jump-to-first-error nil
          compilation-scroll-output 'first-error
          mode-compile-always-save-buffer-p t))

edebug-x   package

(use-package edebug-x
    :ensure edebug-x
    :commands (edebug-x-modify-breakpoint-wrapper

emacs-lisp-mode   package

Preconfigure eldoc-mode.

(use-package eldoc
    :commands (eldoc-mode)
    :diminish eldoc-mode)

Coalesce a bunch of individual hooks:

(defun alexm/remove-elc-on-save nil
  "If you're saving an elisp file, likely the .elc is no longer valid."
  (if (file-exists-p (concat buffer-file-name "c"))
      (delete-file (concat buffer-file-name "c"))))
(defun alexm/emacs-lisp-mode nil
  (add-to-list 'flycheck-disabled-checkers 'emacs-lisp-checkdoc)
  (add-hook 'emacs-lisp-mode-hook 'alexm/remove-elc-on-save nil t)
  (eldoc-mode 1))

eldoc mode shows function calls in the minibuffer. \(0.275\) seconds is somewhere in the middle of the average length of a blink.

(setq eldoc-idle-delay 0.275)

Default lisp indentation looks weird.

(setq lisp-indent-function 'common-lisp-indent-function)
(add-hook 'emacs-lisp-mode-hook #'alexm/emacs-lisp-mode)
(add-hook 'lisp-interaction-mode-hook #'eldoc-mode)

(define-key emacs-lisp-mode-map (kbd "C-c v") 'eval-buffer)
(define-key lisp-mode-shared-map (kbd "RET") 'reindent-then-newline-and-indent)

;; Enable jumping to elisp via help mode

(define-key 'help-command (kbd "C-l") 'find-library)
(define-key 'help-command (kbd "C-f") 'find-function)
(define-key 'help-command (kbd "C-k") 'find-function-on-key)
(define-key 'help-command (kbd "C-v") 'find-variable)

flycheck   package

Using flycheck instead of flymake

(use-package flycheck
    :ensure flycheck
    :commands flycheck-mode
    (bind-key "M-n" #'flycheck-next-error flycheck-mode-map)
    (bind-key "M-p" #'flycheck-previous-error flycheck-mode-map)
    (bind-key "C-c ! !" #'flycheck-list-errors flycheck-mode-map)
    (setq flycheck-checker-error-threshold 4000))

fuel   package

fu.el is the factor interaction mode.

(use-package fuel
    :ensure t
    :no-require t
    :commands (run-factor))

gdb   package

(setq gdb-non-stop-setting nil
      gdb-many-windows t
      gdb-show-main t
      gud-chdir-before-run nil
      gud-tooltip-mode t)

git-gutter   package

(use-package git-gutter+
    :ensure git-gutter+
    :diminish git-gutter+-mode
    :commands (git-gutter+-mode)
    (setq git-gutter+-hide-gutter nil))

magit   package

git management in emacs.

(use-package magit
    :ensure magit
    :bind (("M-g s" . magit-status))
    :commands (magit magit-status)
    ;; omfg shut up magit I am fine with auto reverting
    (setq magit-last-seen-setup-instructions "1.4.0")
      (setq magit-completing-read-function

      (add-hook 'magit-log-edit-mode-hook 'turn-on-flyspell 'append)
      (setq magit-auto-revert-mode nil)
      ;; Set up diffing faces, and always full screen magit
      (eval-after-load 'magit
          (set-face-foreground 'magit-diff-added "green1")
          (set-face-foreground 'magit-diff-removed "red1")
          (set-face-background 'magit-diff-added "#004400")
          (set-face-background 'magit-diff-removed "#440000")
          (set-face-background 'magit-section-highlight "#1f2727")
          ;; full screen magit-status

          (defadvice magit-status (around magit-fullscreen activate)
            (window-configuration-to-register :magit-fullscreen)
          (defun magit-quit-session ()
            "Restores the previous window configuration and kills the magit buffer"
            (jump-to-register :magit-fullscreen))

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

perl-mode   package

I am, for better or for worse, a Perl hacker.

(use-package cperl-mode
    :ensure t
    :init (defalias 'perl-mode 'cperl-mode)
     cperl-close-paren-offset -4
     cperl-continued-statement-offset 4
     cperl-indent-level 4
     cperl-indent-parens-as-block t
     cperl-tab-always-indent t

prog-mode   package

Set up defaults for all programming modes.

Always indent 4.

(setq-default c-basic-offset 4)

Spaces, not tabs. Everywhere.

(setq-default indent-tabs-mode nil)

Set up fill column and whitespace-mode settings when starting programming mode.

(defun alexm/programming-mode-hook ()
  (setq whitespace-style '(face lines-tail)
        show-trailing-whitespace t)
  (add-hook 'before-save-hook 'delete-trailing-whitespace t t)
  (set-fill-column 80)
  (unless org-export-current-backend (whitespace-mode)))

(add-hook 'prog-mode-hook 'alexm/programming-mode-hook)

Always check spelling in comments and documentation.

(add-hook 'prog-mode-hook 'flyspell-prog-mode)

python-mode   package

Bring in the mode.

(use-package python
  (setq python-fill-docstring-style 'pep-257-nn))

Sort Python imports.

(defun isort nil
  "Sort python imports"
   (point-min) (point-max)
   "isort -"
   nil t nil t))

smerge-mode   package

Adds commands for dealing with conflicted merge files (i.e. >>>>>>> and <<<<<<< files)

(use-package smerge-mode
    :commands (smerge-mode))

(defun sm-try-smerge ()
    (goto-char (point-min))
    (when (re-search-forward "^<<<<<<< " nil t)
      (smerge-mode 1))))

(add-hook 'find-file-hook 'sm-try-smerge t)


htmlize   package

Used for HTMLizing buffers, but mostly for code block export in org-mode.

(use-package htmlize
    :ensure htmlize)

LaTeX   package

Set some LaTeX settings.

(use-package tex
    :if (executable-find "latex")
    :ensure auctex
    :commands (LaTeX-mode)
    (setq LaTeX-default-verb-delimiter ?=
          LaTeX-verbatim-environments '("verbatim" "verbatim*" "lstlisting")
          TeX-newline-function 'newline-and-indent))

markdown-mode   package

Markdown. Used mostly for blogging and README files.

(use-package markdown-mode
    :mode (("\\.markdown\\'" . markdown-mode)
           ("\\.md\\'" . markdown-mode))
    :ensure markdown-mode)

yaml-mode   package


(use-package yaml-mode
    :mode (("\\.yaml\\'" . yaml-mode)
           ("\\.yml\\'" . yaml-mode))
    :ensure yaml-mode)


ansi-color   package

Turn on ansi in shells

(use-package ansi-color
    :ensure ansi-color
    :commands shell
    (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on))


easy-pg   package

gpg file auto query/loading

(use-package epa-file
    :defer t
      (setq epa-file-cache-passphrase-for-symmetric-encryption t)))

proced   package

(use-package proced
    :commands (proced proced-toggle-auto-update)
      (setq proced-auto-update-interval 2)

      (defun alexm/proced-settings ()
        (proced-toggle-auto-update t))

      (add-hook 'proced-mode-hook 'alexm/proced-settings)))

debian-changelog-mode   package

(use-package debian-changelog-mode
    :ensure nil
    (setq debian-changelog-date-utc-flag t))

midnight-mode   package

(use-package midnight
    :ensure t
    :init (setq midnight-period (* 6 60 60)
                midnight-delay (random 60))
    (add-to-list 'clean-buffer-list-kill-never-regexps "@[^:]+:[1-9][0-9]*$")
    (add-to-list 'clean-buffer-list-kill-never-regexps "^[#&]"))

osx-location   package

Enabling this gets us better results from celestial-mode-line, which see.

(use-package osx-location
    :if macosx-p
    :ensure t
    :after (celestial-mode-line solar)
    (add-hook 'osx-location-changed-hook #'alexm/osx-location-changed)

solar   package


(use-package solar)

celestial-mode-line   package

Get the modeline to display moon phase and sunset.

(use-package celestial-mode-line
    :if macosx-p
    :ensure t
    (add-to-list 'global-mode-string 'celestial-mode-line-string t))


(bind-key "C-c C-d" 'delete-region)
(bind-key "C-c d"   'delete-region)
(bind-key "C-x C-d" 'ido-dired)
(bind-key "C-c e"   'eval-and-replace)
(bind-key "C-x C-k" 'kill-region)
(bind-key "C-x C-b" 'ibuffer-other-window)
(bind-key "C-M-g"   'goto-line)
(bind-key "M-o"     'other-window)
(bind-key "C-w"     'backward-kill-word) ;; make this like shell.
(bind-key "C-x ^"   'what-cursor-position)
(bind-key "C-x +"   'enlarge-window)
(bind-key "C-x -"   'shrink-window)
(bind-key "C-x ="   'balance-windows)
(bind-key "C-x i"   #'alexm/start-or-switch-to-circe)
(bind-key "M-s ?"   #'alexm/rot13-region)
(bind-key "M-s i"   #'isort python-mode-map)
(bind-key "C-x @ n" #'alexm/stamp-m8601)
(bind-key "C-x @ d" #'alexm/stamp-m8601-date)
(bind-key "C-x @ r" #'alexm/stamp-rfc2822)
(bind-key "s-="     #'text-scale-increase)
(bind-key "s--"     #'text-scale-decrease)
(bind-key "s-0"     #'alexm/restore-text-scale)
(bind-key "C-x M"   #'alexm/clean-up-mesos-stacktraces)

Toggle Map


(define-prefix-command 'alexm/toggle-map)
;; The manual recommends C-c for user keys, but C-x t is
;; always free, whereas C-c t is used by some modes.
(define-key ctl-x-map "t" 'alexm/toggle-map)
(define-key alexm/toggle-map "d" 'toggle-debug-on-error)
(define-key alexm/toggle-map "e" 'toggle-debug-on-error)
(define-key alexm/toggle-map "f" 'auto-fill-mode)
(define-key alexm/toggle-map "#" 'linum-mode)
(define-key alexm/toggle-map "l" 'toggle-truncate-lines)
(define-key alexm/toggle-map "q" 'toggle-debug-on-quit)
(define-key alexm/toggle-map "t" 'tags-reset-tags-tables)
(autoload 'tags-reset-tags-tables "etags" nil t)
(define-key alexm/toggle-map "v" 'visual-line-mode)
;;; Generalized version of `read-only-mode'.
(define-key alexm/toggle-map "r" 'dired-toggle-read-only)
(autoload 'dired-toggle-read-only "dired" nil t)

(defun narrow-or-widen-dwim (p)
  "If the buffer is narrowed, it widens. Otherwise, it narrows intelligently.
Intelligently means: region, subtree, or defun, whichever applies

With prefix P, don't widen, just narrow even if buffer is already
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
         (narrow-to-region (region-beginning) (region-end)))
        ((derived-mode-p 'org-mode) (org-narrow-to-subtree))
        (t (narrow-to-defun))))

(define-key alexm/toggle-map "n" 'narrow-or-widen-dwim)