Pavel Panchekha

By

Share under CC-BY-SA.

Emacs Initialization Script

I use Org's Babel system for this configuration file. My .emacs.d/init.el file contains only:

(package-initialize)
(require 'ob-tangle)
(org-babel-load-file "~/.emacs.d/emacs.org")

Packages

I install packages mostly from MELPA.

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

Here are the packages I use; this table is used by org-mode to install the packages.

Package Use
better-defaults Hide menus and fix some basic annoyances
monokai-theme A colorful theme which I really like
evil Vim key-bindings
evil-leader Set SPC as a leader key
helm A generic menu-driven Emacs plugin
projectile A light-weight project tool
paradox Better package management tools
magit A git mode
auto-complete Completions and suggestions
org An organization tool
haskell-mode Editing haskell
quack Some additional scheme utils
geiser A Scheme REPL
markdown-mode Editing markdown
typopunct Inserting proper punctuation automatically
(dolist (package (mapcar #'intern (mapcar #'first (rest packages))))
  (unless (package-installed-p package)
    (package-install package))
  (require package))

I generally manage these packages through the paradox tool, which I configure to interface with Github:

(setf paradox-github-token my-github-token)
(setf paradox-star-automatically t)
(setf paradox-execute-asynchronously t)

Personal Information

My name and email address helps Emacs format various messages.

(setf user-full-name "Pavel Panchekha")
(setf user-mail-address "me@pavpanchekha.com")

I keep my custom-set variables separate from my true configuration file.

(setf custom-file "~/.emacs.d/custom.el")
(load custom-file)

Since I publish this file on the Internet, I keep my passwords elsewhere:

(org-babel-load-file "~/.emacs.d/passwords.org")

I store some collected data in Dropbox. To avoid one computer overwriting another's data, I include the hostname in the file name. This code extracts the hostname itself.

(setf hostname
      (with-temp-buffer
        (call-process "hostname" nil t)
        (let ((hostname* (buffer-string)))
          (while (string-match "[\r\n\t ]+" hostname*)
            (setq hostname* (replace-match "" t t hostname*)))
          hostname*)))

Evil: key commands à la Vim

Evil is the Vim key-stroke language for Emacs.

(global-evil-leader-mode)
(evil-leader/set-leader "SPC")
(evil-mode 1)

By default Evil uses undo-tree, which represents previous document states as a tree. I, however, prefer the more confusing but simpler cyclic undo that comes with vanilla Emacs.

(global-undo-tree-mode -1)

Visual line mode is what Emacs calls “word wrap”. I use it in all text modes, so I ask Evil to execute commands on visual lines; otherwise these commands are g $ and similar. The commands I and A should act similarly, but they do not yet have associated -visual-line versions.

(define-key evil-motion-state-map "j" #'evil-next-visual-line)
(define-key evil-motion-state-map "k" #'evil-previous-visual-line)
(define-key evil-motion-state-map "$" #'evil-end-of-visual-line)
(define-key evil-motion-state-map "^" #'evil-first-non-blank-of-visual-line)
(define-key evil-motion-state-map "0" #'evil-beginning-of-visual-line)

Evil binds RET, which is often used in other modes. This unbinds it:

(define-key evil-motion-state-map (kbd "RET") nil)
(define-key evil-motion-state-map (kbd " ") nil)

I have a few shortcuts using the SPC leader. They’re mostly bindings to Helm tools, but I plan to grow more one day.

Key Function
SPC helm-M-x
f helm-find-files
b helm-mini
h help-for-help
p helm-projectile
g helm-google-suggest
(apply #'evil-leader/set-key
       (apply #'append (mapcar (lambda (row) (list (first row) (intern (second row)))) (rest bindings))))

Graphical Interface Quirks

I now use the better-defaults package to turn off the scroll bar, tool bar, and menu bar.

Instead of the menu bar, I put the mode line at the top of the document (a trick I took from Bastien Guerry):

(setq-default header-line-format mode-line-format)
(setq-default mode-line-format nil)

I no longer need the Emacs startup screen, so I turn it off. I usually start from the daemon anyway, so I’ll only see the startup screen once.

(setf inhibit-startup-screen t
      inhibit-startup-message t
      inhibit-startup-echo-area-message t)

Instead, I would rather Emacs open up by visiting the ~ directory, in which I store current projects.

(setf initial-buffer-choice "~/")

I’m still mulling this choice over—I’d prefer my Home directory to be a bit cleaner, and I’d prefer opening it without showing hidden files (of which there are too many, and which I’d also prefer to clean out. For now, there’s no escaping it.

The mode-line is made more useful by showing the column number and progress through the file. The column number is especially handy for avoiding long lines and for debugging error messages.

(setf column-number-mode t)
(setf size-indication-mode t)

I hate my computer beeping when I err. I ask Emacs to express its discontent visually.

(setf visible-bell t)

I rarely use the mouse, so tooltips are an annoyance. This code causes them to appear in the echo area instead.

(tooltip-mode -1)
(setf tooltip-use-echo-area t)

For scrolling, I ask Emacs to scroll at most five lines at a time and to keep 5 lines between the cursor and the top/bottom of the page. This helps me keep my place in the document.

(setf scroll-conservatively 5)
(setf scroll-margin 5)

I use a time tracker that records window titles. This is more handy if I display the currently file path in the window title.

(setq frame-title-format
      '((:eval (if (buffer-file-name)
                   (concat "Emacs: " (abbreviate-file-name (buffer-file-name)))
                 "Emacs: %b"))))

Hide hidden files and directories by default in dired.


Turn on Flycheck everywhere

(add-hook 'after-init-hook #'global-flycheck-mode)

Auto-completion

The Auto Complete Mode provides in-line auto-completion. I actually see a lot of competition right now between Auto Complete Mode and Company Mode. Here’s hoping one wins out; I understand Company to be the older mode, but also still under active development.

(global-auto-complete-mode)

I hook up completions to Geiser, the Scheme evaluation mode. This gives good completion in Racket buffers.

(eval-after-load "auto-complete"
  '(add-to-list 'ac-modes '(geiser-repl-mode geiser-mode) t))

Auto Complete Mode automatically enables itself in all buffers, so I don’t need much configuration. I ask it to use fuzzy matching, which accounts for typos.

(setf ac-use-fuzzy t)

Org-mode

Org-mode indents description lists so as to keep a consistent left edge. I don't like this behavior.

(setf org-description-max-indent 0)

I prefer to hide the inline markup used by Org-mode.

(setf org-hide-emphasis-markers t)
(setf org-hide-leading-stars t)

Org-mode needs more information to use alternate LaTeX document classes. I put this information into a separate file so I can load it separately in Makefiles.

(load "~/.emacs.d/export.el")

I use org-journal for journaling.

(setf org-journal-dir "~/Dropbox/")
(setf org-journal-file-format "journal.txt")
(setf org-journal-date-prefix "#+TITLE: ")
(setf org-journal-time-prefix "* ")

Magit Git integration

Magit is an incredible Emacs interface to the Git version-control system. I have a Magit binding in my leader map:

(evil-leader/set-key "m" 'magit-status)

Editing text

I’m writing text documents pretty often now—the life of a scientist involves a lot of papers, notes, meetings, websites. Normally these files use org-mode. I’d love to use Markdown for everything—Org-mode’s syntax is actually pretty ugly—but Markdown has problems of its own. That’s a rant for another day, but suffice it to say that I’m using org-mode for now.

I give Org-mode files a txt extension because this allows editing them on other devices.

(add-to-list 'auto-mode-alist '("\\.txt$" . org-mode))

My BibTeX files contain paper commentaries, marked up in Org mode. BibTeX has this weird feature where everything BibTeX can’t parse it treats as a comment. So, it’s really easy to embed paper comments into the bibliography files.

(add-to-list 'auto-mode-alist '("\\.bib$" . org-mode))

visual-line-mode implements proper line wrapping, which I prefer. For Org mode I also turn on proportional fonts. But traditionally Markdown files are hard-wrapped, and use ASCII fixed-text conventions more. LaTeX files get the same treatment.

(add-hook 'org-mode-hook 'visual-line-mode)
(add-hook 'org-mode-hook 'variable-pitch-mode)

(add-hook 'markdown-mode-hook 'auto-fill-mode)

(add-hook 'latex-mode-hook 'auto-fill-mode)
(add-hook 'latex-mode-hook 'variable-pitch-mode)

I’ve gone back and forth on single- and double-spaced sentences, but for now I’m in the single-spacing camp.

(setf sentence-end-double-space nil)

In text documents I prefer nice, Unicode punctuation. The typopunct package automatically inserts that, including em- and en-dashes, matching quotes, proper apostrophes, and so on.

(typopunct-change-language 'english t)
(add-hook 'org-mode-hook 'typopunct-mode)
(add-hook 'markdown-mode-hook 'typopunct-mode)

In the text modes I use, I turn on spell checking.

(add-hook 'org-mode-hook 'flyspell-mode)
(add-hook 'markdown-mode-hook 'flyspell-mode)
(add-hook 'latex-mode-hook 'flyspell-mode)

To insert other Unicode characters, I use the TeX input mode that ships with Emacs:

(defun TeX-input-method () (set-input-method 'TeX))
(add-hook 'org-mode-hook 'TeX-input-method)
(add-hook 'markdown-mode-hook 'TeX-input-method)
(add-hook 'latex-mode-hook 'TeX-input-method)

Editing directories

Dired is great for exploring a file system and so on.

  (require 'dired-x)

(setf dired-omit-files "^\\.?#\\|^\\.")

  (defun dired-hide-details-home ()
    "Hide details and hidden files,
     if the current buffer is the home directory."
    (when (equal (expand-file-name default-directory) (expand-file-name "~/"))
      (dired-hide-details-mode)
      (dired-omit-mode)))

  (add-hook 'dired-mode-hook 'dired-hide-details-mode)

Spell checking

Fly-spell mode uses ISpell. I want to use the ispell program, to use American English, and to locate my personal dictionary within my .emacs.d directory.

(setf ispell-program-name "/usr/bin/ispell")
(setf ispell-dictionary "american")
(setf ispell-personal-dictionary "~/.emacs.d/dict")

A key binding I really miss from Vim is the spell checking keys zg and z=. Emacs has a great spell-check built-in: Ispell. All we need to do is add a few key-bindings. But first we need a function to bind to, and for zg (save current word to dictionary) one does not exist. So off we go to implement ispell-save-word.

(defun ispell-save-word () (interactive)

First, we need to get the current word. We don't need to explicitly use ispell-following-word, since ispell-get-word does this for us. ispell-get-word returns a list of word, start, end (though its documentation certainly doesn't hint at such), so we call car to extract the word itself.

(let ((word (car (ispell-get-word nil))))

Now we can call ispell-send-string. Its documentation is pretty weak (and that's if I want to be nice), but from reading the code of ispell-command-loop (search for ?i), it seems like we want to send *word\n, where word is the word in question.

(ispell-send-string (concat "*" word "\n"))

Finally, since we modified the dictionary, we want to save it. To be nice, we're going to first mark the dictionary as modified. We only want to force a save, though, if the dictionary was clean before-hand, so we save the old value.

(let ((old-ispell-pdict-modified-p ispell-pdict-modified-p))
  (setq ispell-pdict-modified-p '(t))

And finally, we want force a save if necessary. The "if necessary" part is actually annoyingly complicated…

(when (or (and old-ispell-pdict-modified-p
               (listp old-ispell-pdict-modified-p)
               (car ispell-pdict-modified-p))
          (and ispell-pdict-modified-p
               (not (listp ispell-pdict-modified-p)))))

But once that's out of the way, we can just call ispell-pdict-save with no-query.

(ispell-pdict-save t))))

Finally, we add key-bindings using Evil's evil-normal-state-map.

(define-key evil-normal-state-map "z=" 'ispell-word)
(define-key evil-normal-state-map "zg" 'ispell-save-word)

Projectile

Projectile is a project management suite for Emacs. I enable it everywhere. It only does anything when I’m in a version-controlled directory, so there’s little harm in this.

(projectile-global-mode)

The run Command

I have command called run, which compiles and runs some program or file in a temporary directory. I use it for compiling LaTeX or testing C code.

(defun run-command (file)
  (interactive (list (buffer-file-name)))
  (save-window-excursion
   (shell-command (concat "run " file " &"))))

(defun compile-command (file)
  (interactive (list (buffer-file-name)))
  (save-window-excursion
   (shell-command (concat "run -c " file " &"))))

Then we attach them to [f5] and [C-f5].

(global-set-key (kbd "<f5>") 'run-command)
(global-set-key (kbd "C-<f5>") 'compile-command)

Doc View

I sometimes use doc-view for long PDFs (though rarely now).

For long PDFs, continuous scrolling is best.

(setf doc-view-continuous t)

144 is a decent resolution, since it makes a page of text about as wide as half my screen, and I generally use Emacs with two vertical panes.

(setf doc-view-resolution 144)

Doc-view works much better with Vim-style h/j/k/l movement keys.

(require 'doc-view)
(define-key doc-view-mode-map (kbd "j") 'doc-view-next-line-or-next-page)
(define-key doc-view-mode-map (kbd "k") 'doc-view-previous-line-or-previous-page)
(define-key doc-view-mode-map (kbd "h") 'image-backward-hscroll)
(define-key doc-view-mode-map (kbd "l") 'image-forward-hscroll)

Haskell programming tools

Haskell Mode provides syntax highlighting and similar utilities for programming in Haskell. Multiple methods of indenting Haskell code come with Haskell Mode. They don't differ much, but I prefer haskell-indentation. I used to use haskell-indent but it annoyed me somehow.

(add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)

Scheme programming tools

Several modes come together to make programming in Scheme enjoyable. I usually use the Racket dialect of Scheme, but I've used MIT-Scheme heavily in the past. Sadly, no package seems to support both. For now I use Quack and Geiser, which together make Racket a breeze.

Since I never use Guile, I configure Geiser to always start up in Racket mode.

(setf geiser-active-implementations '(racket))

It is customary in Racket to use a proper Unicode λ instead of the symbol lambda. I hack the abbreviation tools in Emacs to make this happen: I set lambda to be an abbreviation for λ.

(require 'abbrev)
(add-hook 'scheme-mode-hook
  (lambda ()
    (abbrev-mode 1)
    (define-abbrev scheme-mode-abbrev-table "lambda" "λ")))

Perfectly matching parentheses is annoying; electric-pair-mode automatically inserts closing parentheses when I type the open parenthesis. This works great show-paren-mode, which automatically highlights the matching parenthesis (show-paren-mode is provided by better-defaults).

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

Geiser provides auto-completion with M-TAB. I instead set up auto-complete using the auto-complete package.

(add-hook 'geiser-mode-hook 'ac-geiser-setup)
(add-hook 'geiser-repl-mode-hook 'ac-geiser-setup)

Geiser stores history information; I'd prefer it not clutter my home directory.

(setf geiser-repl-history-filename "~/.emacs.d/geiser-history")

Emacs Lisp programming tools

When I write emacs-lisp I am often in the debugger. To turn it on, I use this function:

(defun debug-mode () "Turn on various Emacs debugging features" (interactive)
  (setf debug-on-error t message-log-max 10000))

I'm also often shaving my Emacs configuration (this file). It's helpful to jump to it and reload it quickly.,

(defun reconfigure () (interactive)
  (load-file "~/.emacs.d/init.el"))

(defun edconfigure () (interactive)
  (find-file "~/.emacs.d/emacs.org"))

Coq programming tools

Proof General is, of course, central to using Coq.

(require 'proof)

Inter-Key Timings

One interesting characteristic of a person's typing is their inter-key timings – the time between typing two letters in succession. For example, it usually takes more time to type "cr" than ";l", since one involves moving the left index finger a large distance and the other uses the really natural rolling chord on the right hand. By recording all key character pairs, we can actually track timings for this. And since I do a lot of my work in Emacs, it is easiest to do this as an Emacs extension.

I've written such a thing: keylogger.el. It has an Emacs Lisp extension and an analyzer written in Javascript. I turn it on when Emacs starts:

(load "~/Dropbox/Work/keylogger.el/keylogger.el")
(setf keylogger-filename (concat "~/Dropbox/Data/keys." hostname ".el"))
(keylogger-load)
(keylogger-start)
(keylogger-autosave)

Note that each startup, I load the file, load my previously-saved data, tell it to record new key presses, and to autosave them every fifteen minutes.

Printing Buffers to PDF

I once needed to print an Emacs buffer to PDF. The standard printing commands rely on lpr and assume an actual printer. Instead I use the Emacs printing package to export buffers to Postscript, and then call ps2pdf to produce a PDF from the Postscript.

(require 'printing)

We want to use the function pr-ps-buffer-print from the printing package. We give it a temporary file to print to, and later we'll run ps2pdf on that file.

(defun print-to-pdf () (interactive)
  (let* ((outfile (make-temp-file pr-ps-temp-file))
         (pdffile (concat outfile ".pdf")))
    (pr-ps-buffer-print 1 outfile)
    (shell-command (concat "ps2pdf "
                           (shell-quote-argument outfile)
                           " "
                           (shell-quote-argument pdffile)))
    (find-file pdffile)))

The default print settings are silly for printing to PDF. I prefer syntax highlighting but no headers.

(setf pr-faces-p t)
(setf ps-print-header nil)
(setf ps-print-header-frame)

Helm

Helm is an incredible search interface. It’s hard to describe, but it somehow improves on many of Emacs’s built-in utilities. I turn on Helm in a couple of places (but sadly not too many of them).

(helm-mode 1)

I use Helm’s version of find-file, search, apropos

(global-set-key (kbd "C-x C-f") 'helm-find-files)
(global-set-key (kbd "C-s") 'helm-occur)
(global-set-key (kbd "C-x b") 'helm-mini)
(global-set-key (kbd "C-h a") 'helm-apropos)
(global-set-key (kbd "C-c h g") 'helm-google-suggest)
(global-set-key (kbd "C-c h p") 'helm-projectile)