Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1977 lines (1794 sloc) 68.4 KB

Michael Fogleman’s Emacs configuration

Introduction

Quotations

On Emacs

Emacs outshines all other editing software in approximately the same way that the noonday sun does the stars. It is not just bigger and brighter; it simply makes everything else vanish.

– Neal Stephenson, ”In the Beginning was the Command Line

On 2 Apr 1992 in the journal Nature the discovery was reported that a giant ancient fungus had been living under the forests of Michigan for at least 1,500 years, the oldest and largest living thing on Earth. Software could get to be like that, I suppose, and Emacs, incorporating, like the fungal thallus, all the the filamentous strands of Emacs Lisp that now already thinly web the Earth, is surely a front runner. But do not be distracted by such lives. Even the life of Emacs, like the life of that fungus, is an ephemerality; to grok life one must transcend not only thermospace but cyberspace.

Will Mengarini

On Literate Programming

Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.

The practitioner of literate programming can be regarded as an essayist, whose main concern is with exposition and excellence of style. Such an author, with thesaurus in hand, chooses the names of variables carefully and explains what each variable means. He or she strives for a program that is comprehensible because its concepts have been introduced in an order that is best for human understanding, using a mixture of formal and informal methods that reinforce each other.

– Donald Knuth

In my experience, software created with literate programming has turned out to be significantly better than software developed in more traditional ways…

Jon Bentley probably hit the nail on the head when he once was asked why literate programming hasn’t taken the whole world by storm. He observed that a small percentage of the world’s population is good at programming, and a small percentage is good at writing; apparently I am asking everybody to be in both subsets.

Yet to me, literate programming is certainly the most important thing that came out of the TeX project. Not only has it enabled me to write and maintain programs faster and more reliably than ever before, and been one of my greatest sources of joy since the 1980s—it has actually been indispensable at times.

Donald Knuth

Settings

Personal information

(setq user-full-name "Michael Fogleman"
      user-mail-address "michaelwfogleman@gmail.com")

Enable package support

I set up packages, Melpa, and use-package bright and early so that I can make use of use-package’s bind-key macro.

When I first copy this set-up into a new machine, I still have to require package, add MELPA, initialize package, and grab use-package, solarized-theme, and a couple of others (including my tid-mode) from the package archives and the internet. This could be improved, but it’s not so bad.

(require 'package)
(add-to-list 'package-archives
             '("melpa" . "http://melpa.org/packages/") t)
(setq load-prefer-newer t)
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))
(require 'use-package)

Validate

(use-package validate
  :ensure t)

Paradox

(use-package async
  :ensure t)

(use-package paradox
  :ensure t
  :config
  (setq paradox-execute-asynchronously t))

Diminish

(use-package diminish
  :ensure t
  :init
  (defmacro rename-modeline (package-name mode new-name)
    `(eval-after-load ,package-name
       '(defadvice ,mode (after rename-modeline activate)
          (setq mode-name ,new-name))))
  (diminish 'isearch-mode))

Theme

I still have to do a load-theme -> solarized-dark upon restarting.

(use-package solarized-theme
  :ensure t)

Turn off unnecessary graphical features

Tool Bar

(if (fboundp 'menu-bar-mode) (menu-bar-mode -1))
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))

Startup Messages

(setq inhibit-startup-message t
      initial-scratch-message ""
      inhibit-startup-echo-area-message t)

Mode Line

Sebastian Wiesner inspired me to slim down my mode line.

I change the default mode-line-format variable, but comment out any variables that I eliminated, so that I can add them in later if I deem them useful.

I add in the date, time, and battery information in formats that I like.

Finally, I diminish some built-in minor modes.

(setq-default mode-line-format
              '("%e" ; print error message about full memory.
                mode-line-front-space
                ; mode-line-mule-info
                ; mode-line-client
                ; mode-line-modified
                ; mode-line-remote
                ; mode-line-frame-identification
                mode-line-buffer-identification
                "   "
                ; mode-line-position
                ; (vc-mode vc-mode)
                ; "  "
                mode-line-modes
                "   "
                ; mode-line-misc-info
                display-time-string
                "   "
                battery-mode-line-string
                mode-line-end-spaces))

(display-time-mode 1)
(setq display-time-format "%a %m/%d%t%R")
(display-battery-mode 1)
(setq battery-mode-line-format "%p%%") ; Default: "[%b%p%%]"

(diminish 'isearch-mode)

Window handling

To handle windows intelligently, I use the built-in windmove functionality. I also add some special functionality for Org where windmove is active in locations where Org Mode does not have special functions.

(windmove-default-keybindings)
(add-hook 'org-shiftup-final-hook 'windmove-up)
(add-hook 'org-shiftleft-final-hook 'windmove-left)
(add-hook 'org-shiftdown-final-hook 'windmove-down)
(add-hook 'org-shiftright-final-hook 'windmove-right)

Backups

(setq backup-directory-alist
      `(("." . ,(expand-file-name
                 (concat user-emacs-directory "backups")))))

Change prompts

Make yes or no prompts be y or n prompts.

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

Other

Apropos

Let apropos commands perform more extensive searches than default. This also comes from Better Defaults.

(setq apropos-do-all t)

Buffer / File Warnings

Remove the warning if a buffer or file does not exist, so you can create them.

(setq confirm-nonexistent-file-or-buffer nil)

;; via https://iqbalansari.github.io/blog/2014/12/07/automatically-create-parent-directories-on-visiting-a-new-file-in-emacs/

(defun create-non-existent-directory ()
  "Check whether a given file's parent directories exist; if they do not, offer to create them."
  (let ((parent-directory (file-name-directory buffer-file-name)))
    (when (and (not (file-exists-p parent-directory))
               (y-or-n-p (format "Directory `%s' does not exist! Create it?" parent-directory)))
      (make-directory parent-directory t))))

(add-to-list 'find-file-not-found-functions #'create-non-existent-directory)

Ediff

The default Ediff behavior is confusing and not desirable. This fixes it.

(setq ediff-window-setup-function 'ediff-setup-windows-plain
      ediff-split-window-function 'split-window-horizontally)

Enable

Some features and settings are disabled by default; this is sane behavior for new users, but it is expected that we will disable them eventually.

(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'erase-buffer 'disabled nil)
(put 'set-goal-column 'disabled nil)

Casing

The following advice makes the upcase/downcase/capitalize-word functions more usable. Thanks, Oleh!

(defadvice upcase-word (before upcase-word-advice activate)
  (unless (looking-back "\\b")
    (backward-word)))

(defadvice downcase-word (before downcase-word-advice activate)
  (unless (looking-back "\\b")
    (backward-word)))

(defadvice capitalize-word (before capitalize-word-advice activate)
  (unless (looking-back "\\b")
    (backward-word)))

Private Files

(load "~/.emacs.d/secrets.el" t)

Prettify Symbols

(global-prettify-symbols-mode +1)

Font

(set-default-font "Source Code Pro" nil t)
(set-face-attribute 'default nil :height 175)

Working with the Mark

From Artur’s article, ”Faster Pop to Mark Command.”

(defadvice pop-to-mark-command (around ensure-new-position activate)
  (let ((p (point)))
    (dotimes (i 10)
      (when (= p (point)) ad-do-it))))

(setq set-mark-command-repeat-pop t)

Encoding

(prefer-coding-system 'utf-8)
(setq coding-system-for-read 'utf-8)
(setq coding-system-for-write 'utf-8)

Key Bindings

Although keybindings are also located elsewhere, this section will aim to provide bindings that are not specific to any mode, package, or function.

System-specific

(when (eq system-type 'darwin)
  (setq mac-command-modifier 'meta
        mac-option-modifier 'super
        mac-control-modifier 'control
        ns-function-modifier 'hyper))

From Better Defaults

(bind-key "M-/" #'hippie-expand)

Lines

Enable line indenting automatically. If needed, you can disable on a mode-by-mode basis.

(bind-keys ("RET" . newline-and-indent)
           ("C-j" . newline-and-indent))

Make C-n insert new lines if the point is at the end of the buffer.

(setq next-line-add-newlines t)

Movement

These keybindings for movement come from What the .emacs.d?.

(defun super-next-line ()
  (interactive)
  (ignore-errors (next-line 5)))

(defun super-previous-line ()
  (interactive)
  (ignore-errors (previous-line 5)))

(defun super-backward-char ()
  (interactive)
  (ignore-errors (backward-char 5)))

(defun super-forward-char ()
  (interactive)
  (ignore-errors (forward-char 5)))

(bind-keys ("C-S-n" . super-next-line)
           ("C-S-p" . super-previous-line)
           ("C-S-b" . super-backward-char)
           ("C-S-f" . super-forward-char))

Meta Binds

Since you don’t need three ways to do numeric prefixes, you can make use of meta-binds instead:

(bind-keys ("M-1" . delete-other-windows)
           ("M-O" . mode-line-other-buffer))

Copying and Killing

ejmr’s snippets post recommends giving this advice to kill-ring-save and kill-ring, which, if no region is selected, makes C-w and M-w kill or copy the current line.

Currently, I just advise kill-region (C-w), as M-w is taken over by easy-kill.

(defadvice kill-region (before slick-cut activate compile)
  "When called interactively with no active region, kill a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (list (line-beginning-position)
           (line-beginning-position 2)))))

backward-kill-line

This binding comes from Emacs Redux. Note that we don’t need a new function, just an anonymous function.

(bind-key "C-<backspace>" (lambda ()
                            (interactive)
                            (kill-line 0)
                            (indent-according-to-mode)))

Sentence and Paragraph Commands

By default, sentence-end-double-space is set to t. That convention may be programatically convenient, but that’s not how I write. I want to be able to write normal sentences, but still be able to fill normally. Let to the rescue!

(defadvice forward-sentence (around real-forward)
  "Consider a sentence to have one space at the end."
  (let ((sentence-end-double-space nil))
    ad-do-it))

(defadvice backward-sentence (around real-backward)
  "Consider a sentence to have one space at the end."
  (let ((sentence-end-double-space nil))
    ad-do-it))

(defadvice kill-sentence (around real-kill)
  "Consider a sentence to have one space at the end."
  (let ((sentence-end-double-space nil))
    ad-do-it))

(ad-activate 'forward-sentence)
(ad-activate 'backward-sentence)
(ad-activate 'kill-sentence)

A slightly less tricky matter is the default binding of backward- and forward-paragraph, which are at the inconvenient M-{ and M-}. This makes a bit more sense, no?

(bind-keys ("M-A" . backward-paragraph)
           ("M-E" . forward-paragraph)
           ("M-K" . kill-paragraph))

Toggle Map

Augmented by a post on Irreal. Some keys on the toggle map are elsewhere in this config.

(define-prefix-command 'toggle-map)
(bind-key "C-x t" 'toggle-map)
(bind-keys :map toggle-map
           ("d" . toggle-debug-on-error)
           ("l" . linum-mode)
           ("o" . org-mode)
           ("t" . text-mode)
           ("w" . whitespace-mode))

Launcher Map

(defun scratch ()
  (interactive)
  (switch-to-buffer-other-window (get-buffer-create "*scratch*")))

(bind-keys :prefix-map launcher-map
           :prefix "C-x l"
           ("A" . ansi-term) ;; save "a" for open-agenda
           ("c" . calc)
           ("C" . calendar)
           ("d" . ediff-buffers)
           ("e" . eshell)
           ("E" . eww)
           ("h" . man)
           ("l" . paradox-list-packages)
           ("u" . paradox-upgrade-packages)
           ("p l" . paradox-list-packages)
           ("p u" . paradox-upgrade-packages)
           ("P" . proced)
           ("s" . scratch)
           ("@" . (lambda () (interactive) (find-file "~/Dropbox/passwords.org.gpg"))))

Macros

Think about macros! Play with macros!

(setq kmacro-ring-max 30)

(bind-keys :prefix-map macro-map
           :prefix "C-c m"
           ("b" . kmacro-bind-to-key)
           ("k" . kmacro-end-or-call-macro-repeat)
           ("n" . kmacro-cycle-ring-next)
           ("p" . kmacro-cycle-ring-previous)
           ("a" . kmacro-add-counter)
           ("i" . kmacro-insert-counter)
           ("r" . apply-macro-to-region-lines)
           ("s" . kmacro-set-counter)
           ("N" . kmacro-name-last-macro)
           ("I" . insert-kbd-macro))

System

All of my packages for interacting with my laptop.

OS

OS X

Mac Related

(defun is-mac-p
    ()
  (eq system-type 'darwin))

(if (is-mac-p) (setq osx t)
  (setq osx nil))

Face Attributes

(when (is-mac-p)
  (set-face-attribute 'default nil :height 165))

Reveal In Finder

(use-package reveal-in-finder
  :if osx
  :ensure t)

Shell

(use-package shell
  :bind ("<f1>" . shell)
  :init
  (dirtrack-mode)
  (setq explicit-shell-file-name (cond ((eq system-type 'darwin) "/bin/bash")
                                       ((eq system-type 'gnu/linux) "/usr/bin/bash")))
  (when (eq system-type 'darwin)
    (use-package exec-path-from-shell
      :ensure t
      :init
      (exec-path-from-shell-initialize)))
  :config
  (bind-keys :map shell-mode-map
             ("<s-up>" . comint-previous-input)
             ("<s-down>" . comint-next-input)))

(add-hook 'after-save-hook
          'executable-make-buffer-file-executable-if-script-p)

Dired

(use-package dired
  :bind ("<f2>" . dired)
  :init
  :config
  (put 'dired-find-alternate-file 'disabled nil)
  (setq dired-dwim-target t
        dired-recursive-deletes 'always
        dired-recursive-copies 'always
        dired-isearch-filenames t
        dired-listing-switches "-alh")
  (use-package dired+
    :ensure t) ;; also automatically calls dired-x, enabling dired-jump, C-x C-j
  (use-package dired-details
    :disabled t
    :init
    (dired-details-install))
  (use-package dired-filter
    :ensure t)
  (use-package dired-subtree
    :ensure t
    :init
    (bind-keys :map dired-mode-map
               :prefix "C-,"
               :prefix-map dired-subtree-map
               :prefix-docstring "Dired subtree map."
               ("C-i" . dired-subtree-insert)
               ("C-/" . dired-subtree-apply-filter)
               ("C-k" . dired-subtree-remove)
               ("C-n" . dired-subtree-next-sibling)
               ("C-p" . dired-subtree-previous-sibling)
               ("C-u" . dired-subtree-up)
               ("C-d" . dired-subtree-down)
               ("C-a" . dired-subtree-beginning)
               ("C-e" . dired-subtree-end)
               ("m" . dired-subtree-mark-subtree)
               ("u" . dired-subtree-unmark-subtree)
               ("C-o C-f" . dired-subtree-only-this-file)
               ("C-o C-d" . dired-subtree-only-this-directory)))
  (bind-keys :map dired-mode-map
             ("<return>" . dired-find-alternate-file)
             ("^" . (lambda () (interactive) (find-alternate-file "..")))
             ("'" . wdired-change-to-wdired-mode)
             ("s-/" . dired-filter-mode)))

Some of these suggestions are adapted from Xah Lee’s article on Dired. dired-find-alternate-file, which is bound to a, is disabled by default. <return> was previously dired-advertised-find-file, and ^ was previously dired-up-directory. Relatedly, I re-bind ‘q’ to my kill-this-buffer function below.

Dired-details lets me show or hide the details with ) and (, respectively. If, for some reason, it becomes hard to remember this, dired-details+ makes the parentheses interchangeable.

Ag

(use-package ag
  :ensure t
  :init
  (use-package wgrep
    :ensure t)
  (use-package wgrep-ag
    :ensure t)
  :config
  (bind-keys :map ag-mode-map
             ("q" . kill-this-buffer))
  (setq ag-highlight-search t))

Emacs

These are helper packages that make Emacs even more awesome.

Hydra

(use-package hydra
  :ensure t
  :init
  (defhydra hydra-zoom ()
    "zoom"
    ("+" text-scale-increase "in")
    ("=" text-scale-increase "in")
    ("-" text-scale-decrease "out")
    ("_" text-scale-decrease "out")
    ("0" (text-scale-adjust 0) "reset")
    ("q" nil "quit" :color blue))
  (bind-keys ("C-x C-0" . hydra-zoom/body)
             ("C-x C-=" . hydra-zoom/body)
             ("C-x C--" . hydra-zoom/body)
             ("C-x C-+" . hydra-zoom/body))
  (setq hydra-lv nil))

Windows

Golden Ratio

(use-package golden-ratio
  :ensure t
  :diminish golden-ratio-mode
  :init
  (golden-ratio-mode 1)
  (setq golden-ratio-auto-scale t))

Winner Mode

(use-package winner
  :init (winner-mode))

Quit Bottom Window

Swiped from Lunaryorn’s post about display-buffer-alist.

(defun quit-bottom-side-windows ()
  "Quit side windows of the current frame."
  (interactive)
  (dolist (window (window-at-side-list))
    (quit-window nil window)))

(bind-key "C-c q" #'quit-bottom-side-windows)

God

(use-package god-mode
  :ensure t
  :init
  (defun update-cursor ()
    (setq cursor-type (if (or god-local-mode buffer-read-only)
                          'bar
                        'box)))
  (add-hook 'god-mode-enabled-hook 'update-cursor)
  (add-hook 'god-mode-disabled-hook 'update-cursor)
  :config
  (bind-keys :map launcher-map
             ("g" . god-local-mode))
  (bind-keys :map god-local-mode-map
             ("z" . repeat)
             ("." . repeat)
             ("i" . god-local-mode))
  (add-to-list 'god-exempt-major-modes 'org-agenda-mode))

Ivy and Swiper

(use-package swiper
  :ensure t
  :diminish ivy-mode
  :bind (("C-s" . swiper)
         ("C-r" . swiper)
         ("C-c C-r" . ivy-resume))
  :init
  (ivy-mode 1)
  (setq ivy-display-style 'fancy
        ivy-height 4
        ivy-use-virtual-buffers t))

IDO

I prefer Ivy, but I keep IDO around for Smex and Ido-Menu. Ido-vertical-mode makes IDO bearable.

(setq ido-enable-flex-matching t
      ido-everywhere t
      ido-use-faces t ;; disable ido faces to see flx highlights.
      ido-create-new-buffer 'always
      ;; suppress  "reference to free variable problems"
      ido-cur-item nil
      ido-context-switch-command nil
      ido-cur-list nil
      ido-default-item nil)
(use-package ido-vertical-mode
  :ensure t
  :init
  (ido-vertical-mode)
  (setq ido-vertical-define-keys 'C-n-and-C-p-only))
(use-package flx-ido
  :ensure t
  :init
  (setq flx-ido-threshold 1000)
  (flx-ido-mode 1))
(use-package idomenu
  :ensure t
  :bind ("M-I" . idomenu))

Smex

Smex (Smart M-X) implements IDO functionality for the M-X window.

(use-package smex
  :ensure t
  :bind (("C-x C-m" . smex)
         ("C-x M-m" . smex-major-mode-commands)
         ("M-x" . smex-major-mode-commands)
         ("C-c C-c M-x" . execute-extended-command))
  :init
  (unbind-key "<menu>")
  (smex-initialize))

Company Mode

(use-package company
  :ensure t
  :diminish company-mode
  :bind ("C-." . company-complete)
  :init
  (global-company-mode 1)
  :config
  (bind-keys :map company-active-map
             ("C-n" . company-select-next)
             ("C-p" . company-select-previous)
             ("C-d" . company-show-doc-buffer)
             ("<tab>" . company-complete)))

Avy

(use-package ace-window
  :ensure t
  :bind (("C-x o" . ace-window)
         ("M-2" . ace-window))
  :init
  (setq aw-background nil)
  (setq aw-keys '(?a ?o ?e ?u ?i ?d ?h ?t ?n ?s)))

(use-package avy
  :ensure t
  :bind ("M-SPC" . avy-goto-char)
  :config
  (setq avy-background t))

(use-package avy-zap
  :ensure t)

(bind-keys :prefix-map avy-map
           :prefix "C-c j"
           ("c" . avy-goto-char)
           ("l" . avy-goto-line)
           ("w" . avy-goto-word-or-subword-1)
           ("W" . ace-window)
           ("z" . avy-zap-to-char)
           ("Z" . avy-zap-up-to-char))

(use-package ace-link
  :ensure t
  :init
  (ace-link-setup-default))

(bind-key "C-x SPC" 'cycle-spacing)

Expand Region

Configured like Magnars in Emacs Rocks, Episode 09.

Configuration

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

(pending-delete-mode t)

Extension

(use-package change-inner
  :ensure t
  :bind (("M-i" . change-inner)
         ("M-o" . change-outer)))

Multiple Cursors

You’ve got to admit, Emacs Rocks. Thanks to Magnars, Sacha, and Artur.

(use-package multiple-cursors
  :ensure t
  :bind 
  (("C->" . mc/mark-next-like-this)
   ("C-<" . mc/mark-previous-like-this)
   ("C-M->" . mc/unmark-next-like-this)
   ("C-M-<" . mc/unmark-previous-like-this)
   ("C-*" . mc/mark-all-like-this))
  :init
  (bind-keys :prefix-map mc-map
             :prefix "C-x m"
             ("C-a" . mc/edit-beginnings-of-lines)
             ("C-e" . mc/edit-ends-of-lines)
             ("C-m" mc/mark-all-dwim)
             ("a" . mc/mark-all-like-this)
             ("d" . mc/mark-all-symbols-like-this-in-defun)
             ("h" . mc-hide-unmatched-lines-mode)
             ("i" . mc/insert-numbers)
             ("l" . mc/edit-lines)
             ("r" . mc/reverse-regions)
             ("s" . mc/sort-regions)))

Deletion

Hungry Delete Mode

Via Endless Parentheses.

(use-package hungry-delete
  :ensure t
  :diminish hungry-delete-mode
  :init
  (global-hungry-delete-mode))

easy-kill

(use-package easy-kill
  :ensure t
  :bind ("M-w" . easy-kill))

Kill Ring

The word “kill” might be antiquated, idiosyncratic jargon, but it’s great that Emacs keeps track of what’s been killed. The package “Browse Kill Ring” is crucial to making that functionality visible and usable.

(use-package browse-kill-ring
  :ensure t
  :bind ("C-x C-y" . browse-kill-ring)
  :config
  (setq browse-kill-ring-quit-action 'kill-and-delete-window))

(setq save-interprogram-paste-before-kill t)

Files

Recent Files

Recent files is a minor mode that keeps track of which files you’re using, and provides it in some handy places.

I also rebind the find-file-read-only with ivy-recentf.

(use-package recentf
  :bind ("C-x C-r" . counsel-recentf)
  :init
  (recentf-mode t)
  (setq recentf-max-saved-items 100))

Automatic Saving

This snippet automatically saves buffers in an intelligent way. It was originally mentioned in a post by Bozhidar Batsov; the version below is adapted from his Prelude distribution and his post on focus hooks in Emacs 24.4.

(defun auto-save-command ()
  (let* ((basic (and buffer-file-name
                     (buffer-modified-p (current-buffer))
                     (file-writable-p buffer-file-name)
                     (not org-src-mode)))
         (proj (and (projectile-project-p)
                    basic)))
    (if proj
        (projectile-save-project-buffers)
      (when basic
        (save-buffer)))))

(defmacro advise-commands (advice-name commands class &rest body)
  "Apply advice named ADVICE-NAME to multiple COMMANDS.
The body of the advice is in BODY."
  `(progn
     ,@(mapcar (lambda (command)
                 `(defadvice ,command (,class ,(intern (concat (symbol-name command) "-" advice-name)) activate)
                    ,@body))
               commands)))

(advise-commands "auto-save"
                 (ido-switch-buffer ace-window magit-status windmove-up windmove-down windmove-left windmove-right mode-line-other-buffer)
                 before
                 (auto-save-command))

(add-hook 'mouse-leave-buffer-hook 'auto-save-command)
(add-hook 'focus-out-hook 'auto-save-command)

(unbind-key "C-x C-s")

Auto Revert Mode

Revert buffers automatically when underlying files are changed externally.

(global-auto-revert-mode t)

Save Place

This comes from Magnars.

(use-package saveplace
  :init
  (setq-default save-place t)
  (setq save-place-file (expand-file-name ".places" user-emacs-directory)))

Key Chord mode

(use-package key-chord
  :ensure t
  :init
  (progn 
    (setq key-chord-two-keys-delay .015
          key-chord-one-key-delay .020)
    (key-chord-mode 1)
    (key-chord-define-global "cg" 'undo)
    (key-chord-define-global "yp" 'other-window)
    (key-chord-define-global ";0" 'delete-window)
    (key-chord-define-global ";1" 'delete-other-windows)
    (key-chord-define-global ";2" 'split-window-below)
    (key-chord-define-global ";3"  'split-window-right)
    (key-chord-define-global ",." 'beginning-of-buffer)
    (key-chord-define-global ".p" 'end-of-buffer)
    (key-chord-define-global "jw" 'avy-goto-word-or-subword-1)
    (key-chord-define-global "jc" 'avy-goto-char)
    (key-chord-define-global "jl" 'avy-goto-line)
    ;; (key-chord-define-global "jb" 'ace-jump-buffer)
    ;; (key-chord-define-global "jo" 'ace-jump-buffer-other-window)
    (key-chord-define-global "'l" 'ido-switch-buffer)
    (key-chord-define-global "'-" 'smex)
    (key-chord-define-global ",r" 'find-file)
    (key-chord-define-global ".c" 'ido-dired)
    (key-chord-define-global "0r" ")")
    (key-chord-define-global "1'" "!")
    (key-chord-define-global "2," "@")
    (key-chord-define-global "3." "#")
    (key-chord-define-global "4p" "$")
    (key-chord-define-global "5y" "%")
    (key-chord-define-global "6y" "^")
    (key-chord-define-global "7f" "&")
    (key-chord-define-global "8g" "*")
    (key-chord-define-global "9c" "(")
    (key-chord-define-global "-l" "_")
    (key-chord-define emacs-lisp-mode-map "7f" "&optional ")))

Regexes

(use-package visual-regexp
  :ensure t
  :bind (("M-5" . vr/replace)
         ("M-%" . vr/query-replace)))

(use-package re-builder
  :init
  (setq reb-re-syntax 'string))

Smart Scan

See Mickey’s explanation and the readme.

Related functions from Wilfred’s config.

(use-package smartscan
  :ensure t
  :init
  (global-smartscan-mode t)

  (defun highlight-symbol-first ()
    "Jump to the first location of symbol at point."
    (interactive)
    (push-mark)
    (eval
     `(progn
        (goto-char (point-min))
        (search-forward-regexp
         (rx symbol-start ,(thing-at-point 'symbol) symbol-end)
         nil t)
        (beginning-of-thing 'symbol))))

  (defun highlight-symbol-last ()
    "Jump to the last location of symbol at point."
    (interactive)
    (push-mark)
    (eval
     `(progn
        (goto-char (point-max))
        (search-backward-regexp
         (rx symbol-start ,(thing-at-point 'symbol) symbol-end)
         nil t))))

  (bind-keys ("M-P" . highlight-symbol-first)
             ("M-N" . highlight-symbol-last)))

Edit List

(use-package edit-list
  :ensure t)

Beacon

(use-package beacon
  :ensure t
  :diminish beacon-mode
  :init
  (beacon-mode 1)
  (setq beacon-push-mark 35)
  (setq beacon-color "#666600"))

Discoverability

(use-package which-key
  :ensure t
  :diminish which-key-mode
  :init
  (which-key-mode))

(use-package help-fns+
  :ensure t
  :bind ("C-h M-k" . describe-keymap)) ; For autoloading.

(use-package discover-my-major
  :ensure t
  :bind ("C-h C-m" . discover-my-major))

Goto-chg

Adapted from the article Move Through Edit Points. This works like the mark, except it cycles through edit points. It takes you through your undo history without actually undoing anything.

“C-u 0 C-c ,” will give a description of changes made.

(use-package goto-chg
  :ensure t
  :bind (("C-c ," . goto-last-change)
         ("C-c ." . goto-last-change-reverse)))

Browsing

External Browsers

(setq browse-url-browser-function 'browse-url-generic
      browse-url-generic-program (cond ((eq system-type 'darwin) "open") 
                                       ((eq system-type 'gnu/linux) "firefox")))

(bind-key "C-c B" 'browse-url-at-point)

Engine Mode

(use-package engine-mode
  :ensure t
  :disabled t
  :init
  (engine-mode t)
  (setq engine/browser-function 'eww-browse-url)
  (engine/set-keymap-prefix (kbd "C-c e"))
  :config
  (defengine amazon
    "http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=%s"
    :keybinding "a")

  (defengine duckduckgo
    "https://duckduckgo.com/html/?q=%s"
    :keybinding "d")

  (defengine github
    "https://github.com/search?ref=simplesearch&q=%s"
    :keybinding "g")

  (defengine google-images
    "http://www.google.com/images?hl=en&source=hp&biw=1440&bih=795&gbv=2&aq=f&aqi=&aql=&oq=&q=%s"
    :keybinding "i")

  (defengine google-maps
    "http://maps.google.com/maps?q=%s"
    :keybinding "m"
    :docstring "Mappin' it up.")

  (defengine stack-overflow
    "https://stackoverflow.com/search?q=%s")

  (defengine twitter
    "https://twitter.com/search?q=%s")

  (defengine wikipedia
    "http://www.wikipedia.org/search-redirect.php?language=en&go=Go&search=%s"
    :keybinding "w"
    :docstring "Searchin' the wikis.")

  (defengine wiktionary
    "https://www.wikipedia.org/search-redirect.php?family=wiktionary&language=en&go=Go&search=%s")

  (defengine wolfram-alpha
    "http://www.wolframalpha.com/input/?i=%s")

  (defengine youtube
    "http://www.youtube.com/results?aq=f&oq=&search_query=%s"
    :keybinding "y"))

EWW!

I’ve enjoyed using Conkeror on my Arch machine. This package brings one neat feature of Conkeror to eww.

(use-package eww-lnum
  :ensure t
  :init
  (eval-after-load "eww"
    '(progn (define-key eww-mode-map "f" 'eww-lnum-follow)
            (define-key eww-mode-map "F" 'eww-lnum-universal))))

Development

Here are language-specific (largely Lisps) or development-related packages.

Clojure

Clojure Mode

(use-package clojure-mode
  :ensure t
  :init
  (add-to-list 'auto-mode-alist '("\\.edn$" . clojure-mode))
  (add-to-list 'auto-mode-alist '("\\.cljx\\'" . clojure-mode))
  (add-to-list 'auto-mode-alist '("\\.cljs$" . clojure-mode))
  :config
  (rename-modeline "clojure-mode" clojure-mode "λ")
  (use-package align-cljlet
    :ensure t
    :bind ("C-! a a" . align-cljlet)))

Clojure Refactor

(use-package clj-refactor
  :ensure t
  :init
  (add-hook 'clojure-mode-hook (lambda () (clj-refactor-mode 1)))
  :config
  (cljr-add-keybindings-with-prefix "C-!"))

CIDER

The function “cider-interactive-eval” comes from A CIDER Excursion.

(use-package cider
  :ensure t
  :config
  (setq nrepl-hide-special-buffers t
        nrepl-popup-stacktraces-in-repl t
        nrepl-history-file "~/.emacs.d/nrepl-history"
        cider-mode-line " CIDER"
        cider-repl-display-in-current-window t
        cider-auto-select-error-buffer nil
        cider-repl-pop-to-buffer-on-connect nil
        cider-show-error-buffer nil)
  (defun cider-use-repl-tools ()
    (interactive)
    (cider-interactive-eval
     "(use 'clojure.repl)"))

  (bind-keys :map cider-repl-mode-map
             ("M-r" . cider-refresh)
             ("M-R" . cider-use-repl-tools))

  ;; this snippet comes from schmir https://github.com/schmir/.emacs.d/blob/master/lisp/setup-clojure.el
  (defadvice cider-load-buffer (after switch-namespace activate compile)
    "switch to namespace"
    (cider-repl-set-ns (cider-current-ns))
    (cider-switch-to-repl-buffer))

  ;; fix cond indenting
  (put 'cond 'clojure-backtracking-indent '(2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4)))

Clojure Cookbook

I’ve been reading the Clojure Cookbook in Emacs with AsciiDoc mode.

There are a lot of short chapters, so I whipped up this Elisp to switch between them.

(defun increment-clojure-cookbook ()
  "When reading the Clojure cookbook, find the next section, and close the buffer."
  (interactive)
  (let* ((cur (buffer-name))
         (split-cur (split-string cur "[-_]"))
         (chap (car split-cur))
         (rec (car (cdr split-cur)))
         (rec-num (string-to-number rec))
         (next-rec-num (1+ rec-num))
         (next-rec-s (number-to-string next-rec-num))
         (next-rec (if (< next-rec-num 10)
                       (concat "0" next-rec-s)
                     next-rec-s))
         (target (file-name-completion (concat chap "-" next-rec) "")))
    (progn 
      (if (equal target nil)
          (dired (file-name-directory (buffer-file-name)))
        (find-file target))
      (kill-buffer cur))))
(use-package adoc-mode
  :ensure t
  :bind (("M-+" . increment-clojure-cookbook))
  :init
  (add-to-list 'auto-mode-alist '("\\.asciidoc\\'" . adoc-mode))
  (add-hook 'adoc-mode-hook 'cider-mode))

Emacs Lisp

Elisp-Slime-Nav

(use-package elisp-slime-nav
  :ensure t
  :diminish elisp-slime-nav-mode
  :init
  (dolist (hook '(emacs-lisp-mode-hook ielm-mode-hook))
    (add-hook hook 'elisp-slime-nav-mode)))

Eldoc

When in emacs-lisp-mode, display the argument list for the current function. I liked this functionality in SLIME; glad Emacs has it too. Thanks for the tip and code, Sacha.

(autoload 'turn-on-eldoc-mode "eldoc" nil t)
(diminish 'eldoc-mode)
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)
(add-hook 'cider-mode-hook 'cider-turn-on-eldoc-mode)

Golang

(use-package go-mode
  :ensure t
  :init
  (defun my-go-mode-hook ()
    ;; Call Gofmt before saving
    (add-hook 'before-save-hook 'gofmt-before-save)
    ;; Customize compile command to run go build
    (if (not (string-match "go" compile-command))
        (set (make-local-variable 'compile-command)
             "go build -v && go test -v && go vet"))
    ;; Godef jump key binding
    (local-set-key (kbd "M-.") 'godef-jump))
  (bind-keys :map launcher-map
             ("f" . gofmt))
  (use-package go-eldoc
    :ensure t
    :config
    (go-eldoc-setup))
  (use-package company-go
    :disabled t
    :ensure t
    :config

    (add-hook 'go-mode-hook
              (lambda () (set (make-local-variable 'company-backends) '(company-go)))))
  :config
  (add-hook 'go-mode-hook 'my-go-mode-hook)
  (add-hook 'go-mode-hook 'subword-mode)

  (bind-keys :map launcher-map
             ("f" . gofmt)))

Elixir

(use-package elixir-mode
  :ensure t)

(use-package alchemist
  :ensure t)

Restclient

See Magnars’ tutorial on Emacs Rocks.

(use-package restclient
  :ensure t)

Flycheck

Flycheck presents a handsome and usable interface for checkdoc, amongst other things.

(use-package flycheck
  :ensure t
  :diminish flycheck-mode
  :init
  (use-package flycheck-clojure
    :ensure t)
  (global-flycheck-mode)
  (setq flycheck-indication-mode 'right-fringe)
  :config
  (flycheck-clojure-setup))

Git

I understand that some beardy-folks are worried that the ubiquity of Github will cause people to equate it with Git, and forget that you can use Git without Github. I don’t worry about that- I worry about forgetting how to use Git itself (or the CLI, at least). Magit has spoiled me!

This code from Magnars opens magit-status in one frame, and then restores the old window configuration when you quit.

(use-package magit
  :ensure t
  :bind (("C-x g" . magit-status)
         ("C-c g" . magit-status))
  :init
  (use-package git-timemachine
    :ensure t
    :bind (("C-x v t" . git-timemachine)))
  (use-package git-link
    :ensure t
    :bind (("C-x v L" . git-link))
    :init
    (setq git-link-open-in-browser t))
  :config
  (setq magit-use-overlays nil
        magit-completing-read-function 'ivy-completing-read
        magit-push-always-verify nil)
  (diminish 'magit-backup-mode)

  (defun visit-pull-request-url ()
    "Visit the current branch's PR on Github."
    (interactive)
    (browse-url
     (format "https://github.com/%s/pull/new/%s"
             (replace-regexp-in-string
              "\\`.+github\\.com:\\(.+\\)\\.git\\'" "\\1"
              (magit-get "remote"
                         (magit-get-remote)
                         "url"))
             (cdr (magit-get-remote-branch)))))

  (bind-key "v" 'visit-pull-request-url magit-mode-map)

  (bind-keys :map magit-status-mode-map
             ("TAB" . magit-section-toggle)
             ("<C-tab>" . magit-section-cycle))
  (bind-keys :map magit-branch-section-map
             ("RET" . magit-checkout)))

smartparens

(use-package smartparens
  :ensure t
  :diminish smartparens-mode
  :bind
  (("C-M-f" . sp-forward-sexp)
   ("C-M-b" . sp-backward-sexp)
   ("C-M-d" . sp-down-sexp)
   ("C-M-a" . sp-backward-down-sexp)
   ("C-S-a" . sp-beginning-of-sexp)
   ("C-S-d" . sp-end-of-sexp)
   ("C-M-e" . sp-up-sexp)
   ("C-M-u" . sp-backward-up-sexp)
   ("C-M-t" . sp-transpose-sexp)
   ("C-M-n" . sp-next-sexp)
   ("C-M-p" . sp-previous-sexp)
   ("C-M-k" . sp-kill-sexp)
   ("C-M-w" . sp-copy-sexp)
   ("M-<delete>" . sp-unwrap-sexp)
   ("M-S-<backspace>" . sp-backward-unwrap-sexp)
   ("C-<right>" . sp-forward-slurp-sexp)
   ("C-<left>" . sp-forward-barf-sexp)
   ("C-M-<left>" . sp-backward-slurp-sexp)
   ("C-M-<right>" . sp-backward-barf-sexp)
   ("M-D" . sp-splice-sexp)
   ("C-M-<delete>" . sp-splice-sexp-killing-forward)
   ("C-M-<backspace>" . sp-splice-sexp-killing-backward)
   ("C-M-S-<backspace>" . sp-splice-sexp-killing-around)
   ("C-]" . sp-select-next-thing-exchange)
   ("C-<left_bracket>" . sp-select-previous-thing)
   ("C-M-]" . sp-select-next-thing)
   ("M-F" . sp-forward-symbol)
   ("M-B" . sp-backward-symbol)
   ("H-t" . sp-prefix-tag-object)
   ("H-p" . sp-prefix-pair-object)
   ("H-s c" . sp-convolute-sexp)
   ("H-s a" . sp-absorb-sexp)
   ("H-s e" . sp-emit-sexp)
   ("H-s p" . sp-add-to-previous-sexp)
   ("H-s n" . sp-add-to-next-sexp)
   ("H-s j" . sp-join-sexp)
   ("H-s s" . sp-split-sexp)
   ("M-9" . sp-backward-sexp)
   ("M-0" . sp-forward-sexp))
  :init
  (smartparens-global-mode t)
  (show-smartparens-global-mode t)
  (use-package smartparens-config)
  (bind-key "s" 'smartparens-mode toggle-map)
  (when (eq system-type 'darwin)
    (bind-keys ("<s-right>" . sp-forward-slurp-sexp)
               ("<s-left>" . sp-forward-barf-sexp)))
  (sp-with-modes '(markdown-mode gfm-mode)
    (sp-local-pair "*" "*"))
  (sp-with-modes '(org-mode)
    (sp-local-pair "=" "=")
    (sp-local-pair "*" "*")
    (sp-local-pair "/" "/")
    (sp-local-pair "_" "_")
    (sp-local-pair "+" "+")
    (sp-local-pair "<" ">")
    (sp-local-pair "[" "]"))
  (use-package rainbow-delimiters
    :ensure t
    :init
    (add-hook 'prog-mode-hook 'rainbow-delimiters-mode)))

Projectile

(use-package projectile
  :ensure t
  :bind ("M-p" . projectile-find-file)
  :diminish projectile-mode
  :init
  (projectile-global-mode)
  (setq projectile-enable-caching t
        projectile-completion-system 'ivy)
  (use-package ibuffer-projectile
    :ensure t
    :bind ("C-x C-b" . ibuffer)
    :init
    (add-hook 'ibuffer-hook
              (lambda ()
                (ibuffer-projectile-set-filter-groups)
                (unless (eq ibuffer-sorting-mode 'alphabetic)
                  (ibuffer-do-sort-by-alphabetic))))
    (bind-keys :map ibuffer-mode-map
               ("c" . clean-buffer-list)
               ("n" . ibuffer-forward-filter-group)
               ("p" . ibuffer-backward-filter-group))))

linum-relative

When I toggle line-mode, I want to use relative line-numbers, à la mi amigo Ben. As he points out, the symbol linum-relative-current-symbol makes linum-relative use the absolute line number for the current line.

(use-package linum-relative
  :ensure t
  :init
  (setq linum-format 'linum-relative)
  :config
  (setq linum-relative-current-symbol ""))

comment-dwim-2

(use-package comment-dwim-2
  :ensure t
  :bind ("M-;" . comment-dwim-2))

aggressive-indent

(use-package aggressive-indent
  :ensure t
  :diminish aggressive-indent-mode
  :init
  (global-aggressive-indent-mode 1)
  (add-to-list 'aggressive-indent-excluded-modes 'html-mode)
  (unbind-key "C-c C-q" aggressive-indent-mode-map))

Words and Numbers

“GNU Office Suite Pro Edition,” coming to a cubicle near you!

Org Mode

Quotations

Org-mode does outlining, note-taking, hyperlinks, spreadsheets, TODO lists, project planning, GTD, HTML and LaTeX authoring, all with plain text files in Emacs.

Carsten Dominik

If I hated everything about Emacs, I would still use it for org-mode.

Avdi on Twitter

…for all intents and purposes, Org-mode is Taskpaper!

Carsten Dominik

Configuration

I use the stock package of org-mode as the default major mode. I use the org-habits module.

(use-package org
  :init
  (setq default-major-mode 'org-mode
        org-directory "~/org/"
        org-log-done t
        org-startup-indented t
        org-agenda-inhibit-startup nil
        org-startup-truncated nil
        org-startup-with-inline-images t
        org-completion-use-ido t
        org-agenda-start-on-weekday nil
        org-refile-targets (quote ((nil :maxlevel . 9)
                                   (org-agenda-files :maxlevel . 9)))
        org-refile-use-outline-path t
        org-default-notes-file (concat org-directory "notes.org")
        org-goto-max-level 10
        org-imenu-depth 5
        org-goto-interface 'outline-path-completion
        org-outline-path-complete-in-steps nil
        org-use-speed-commands t
        org-src-fontify-natively t
        org-lowest-priority 68
        org-default-priority 68
        org-ellipsis ""
        org-agenda-files (quote ("~/org/tech.org"
                                 "~/org/cml.org"
                                 "~/org/awakening.org"
                                 "~/org/responsibility.org"
                                 "~/org/work.org"
                                 "~/org/inji.org"
                                 "~/org/money.org"
                                 "~/org/readwrite.org"
                                 "~/org/personal.org"
                                 "~/org/people.org"
                                 "~/org/health.org"
                                 "~/org/todo.org"
                                 "~/org/notes.org"))
        org-tag-alist '(("@work" . ?b)
                        ("@home" . ?h)
                        ("@reading" . ?r)
                        ("@writing" . ?w)
                        ("@errands" . ?e)
                        ("@email" . ?e)
                        ("@coding" . ?c)
                        ("@phone" . ?p)
                        ("@computer" . ?l)
                        ("lowenergy" . ?0)
                        ("highenergy" . ?1))
        org-capture-templates
        '(("c" "Conversation" entry (file+datetree "~/org/conversations.org")
           "* %?\n")
          ("g" "Gratitude Journal" entry (file+datetree "~/org/gratitude.org")
           "* I am grateful for: \n** %?")
          ("n" "Note" entry (file "~/org/notes.org")
           "* %?\n")
          ("m" "Meditation Log" entry (file+datetree "~/org/awakening.org")
           "* %?\n")
	    ("j" "Journal" entry (file+datetree "~/org/journal.org.gpg")
           "* %?")
	    ("r" "Review" entry (file+datetree "~/org/reviews.org")
	     "* %?")
	    ("t" "TODO" entry (file "~/org/todo.org")
           "* TODO %?\n"))
        org-file-apps
        '((auto-mode . emacs)
          ("\\.mm\\'" . default)
          ("\\.x?html?\\'" . "firefox %s")
          ("\\.pdf\\'" . "evince %s"))
        org-todo-keywords
        '((sequence "TODO(t)" "STARTED(s)" "WAITING(w@/!)" "SOMEDAY(.)" "MAYBE(m)" "|" "DONE(x!)" "CANCELLED(c@)")
          (sequence "LEARN" "RESEARCH" "TRY" "TEACH" "|" "COMPLETE")
          (sequence "QUESTION" "|" "ANSWERED")))

  (unbind-key "C-c [")
  (unbind-key "C-c ]")
  (add-to-list 'org-structure-template-alist '("g" "# -*- mode:org; epa-file-encrypt-to: (\"michaelwfogleman@gmail.com\") -*-"))
  (add-to-list 'org-global-properties
               '("Effort_ALL". "0:05 0:15 0:30 1:00 2:00 3:00 4:00"))

  ;; Org Modules
  (require 'org-install)
  (setq org-modules
        '(org-habit org-w3m org-bbdb org-bibtex org-docview org-gnus org-info org-irc org-mhe org-rmail)
        org-habit-graph-column 105)

  (add-hook 'org-agenda-finalize-hook (lambda () (delete-other-windows)))
  (use-package org-bullets
    :ensure t
    :init
    (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
  :config
  (org-load-modules-maybe t)
  (diminish 'org-indent-mode))

(defun make-org-scratch ()
  (interactive)
  (find-file "~/Dropbox/org/scratch.org"))

(bind-keys :map launcher-map
           ("S" . make-org-scratch))

(defun org-open-archive ()
  (interactive)
  (let* ((cur (buffer-file-name))
         (target (concat cur "_archive")))
    (find-file target)))

(defun org-buffer-todo ()
  (interactive)
  "Creates a todo-list for the current buffer. Equivalent to the sequence: org-agenda, < (restrict to current buffer), t (todo-list)."
  (progn
    (org-agenda-set-restriction-lock 'file)
    (org-todo-list)))

(defun org-buffer-agenda ()
  (interactive)
  "Creates an agenda for the current buffer. Equivalent to the sequence: org-agenda, < (restrict to current buffer), a (agenda-list)."
  (progn
    (org-agenda-set-restriction-lock 'file)
    (org-agenda-list)))

(defun org-buffer-day-agenda ()
  (interactive)
  "Creates an agenda for the current buffer. Equivalent to the sequence: org-agenda, < (restrict to current buffer), a (agenda-list), d (org-agenda-day-view)."
  (progn
    (org-agenda-set-restriction-lock 'file)
    (org-agenda-list)
    (org-agenda-day-view))) ;; Maybe I should try writing a Emacs Lisp macro for this kind of thing!

(bind-keys ("C-c A" . org-buffer-agenda)
           ("C-c t" . org-buffer-todo)
           ("C-c d" . org-buffer-day-agenda)
           ("C-c L" . org-timeline)
           ("C-c o" . org-open-archive))

(bind-key "y" 'org-agenda-todo-yesterday org-agenda-mode-map)

(add-hook 'org-mode-hook
          (lambda ()
            (push '("TODO"  . ?▲) prettify-symbols-alist)
            (push '("DONE"  . ?✓) prettify-symbols-alist)
            (push '("CANCELLED"  . ?✘) prettify-symbols-alist)
            (push '("QUESTION"  . ??) prettify-symbols-alist)))

My settings for capture were some of my first Elisp :) I did need, and still need, the help of the Org-Mode manual, of course.

I use org-struct in mu4e. See above.

Bindings

(bind-keys ("C-c l" . org-store-link)
           ("C-c c" . org-capture)
           ("C-c a" . org-agenda)
           ("C-c b" . org-iswitchb)
           ("C-c >" . org-time-stamp-inactive)
           ("C-c M-k" . org-cut-subtree)
           ("<down>" . org-insert-todo-heading))

(setq org-speed-commands-user
      '(("N" org-narrow-to-subtree)
        ("$" org-archive-subtree)
        ("A" org-archive-subtree)
        ("W" widen)
        ("d" org-down-element)
        ("k" org-cut-subtree)
        ("s" org-sort)
        ("x" smex-major-mode-commands)
        ("X" org-todo-done)
        ("y" org-todo-yesterday)))

TiddlyWiki

I edit TiddlyWiki5 .tid files in Emacs using my tid-mode major mode. I create and bind functions to open the TiddlyWiki in Dired and the browser.

(use-package tid-mode
  :load-path "site-lisp/tid-mode/"
  :init
  (defun open-wiki ()
    "Opens my TiddlyWiki directory."
    (interactive)
    (dired "~/Dropbox/wiki/tiddlers/"))
  (defun browse-wiki ()
    "Opens my TiddlyWiki in my browser."
    (interactive)
    (browse-url "127.0.0.1:8080/"))
  (bind-keys ("C-c w" . open-wiki)
             ("C-c W" . browse-wiki)))

Markdown

(use-package markdown-mode
  :ensure t)

Calc

(use-package calc
  :config
  (setq calc-display-trail ()))

Numbers

(use-package number
  :ensure t
  :bind
  (("C-c C-+" . number/add)
   ("C-c C--" . number/sub)
   ("C-c C-*" . number/multiply)
   ("C-c C-/" . number/divide)))

Flyspell

(use-package flyspell
  :bind (("C-`" . ispell-word)
         ("C-~" . ispell-buffer))
  :init
  (dolist (hook '(text-mode-hook org-mode-hook))
    (add-hook hook (lambda () (flyspell-mode 1))))
  :config
  (setq ispell-program-name "aspell"
        ispell-list-command "--list"))

Pandoc

(use-package pandoc-mode
  :ensure t
  :init
  (if (eq window-system 'mac)
      (add-to-list 'exec-path "/usr/local/texlive/2016basic/bin/universal-darwin")))

Functions

Emacs Configuration File

This function and the corresponding keybinding allows me to rapidly access my configuration. They are adapted from Bozhidar Batsov’s post on Emacs Redux.

I use mwf-init-file rather than user-init-file, because I edit the config file in a Git repo.

(defun find-init-file ()
  "Edit my init file in another window."
  (interactive)
  (let ((mwf-init-file "~/src/config/home/.emacs.d/michael.org"))
    (find-file mwf-init-file)))

(bind-key "C-c I" 'find-init-file)

Relatedly, I often want to reload my init-file. This will actually use the system-wide user-init-file variable.

(defun reload-init-file ()
  "Reload my init file."
  (interactive)
  (load-file user-init-file))

(bind-key "C-c M-l" 'reload-init-file)

Keep In Touch

I use mi amigo Ben’s Keep In Touch program. This re-implements some of the command line utility’s functionality in Elisp.

(setq keepintouch-datafile "~/Dropbox/keepintouch.data")

(defun keptintouch (arg)
  "Request a contact in a keepintouch.data file, and update their last
  contacted date (either today, or, if a prefix is supplied, a user-supplied date.)"
  (interactive "P")
  (let ((contact (read-string "Who did you contact? "))
        (date (if (equal arg nil)
                  (format-time-string "%Y/%m/%d")
                (read-string "When did you contact them? (year/month/date): "))))
    (save-excursion
      (find-file keepintouch-datafile)
      (goto-char (point-min))
      (search-forward contact)
      (forward-line -1)
      (beginning-of-line)
      (kill-line)
      (insert date)
      (save-buffer)
      (switch-to-buffer (other-buffer))
      (kill-buffer (other-buffer)))
    (message "%s was contacted." contact)))

(defun keptintouch-backlog ()
  "Create a buffer with Keep In Touch backlog."
  (interactive)
  (let ((buf "*Keep In Touch Backlog*")
        (src "~/src/keepintouch/clj/keepintouch")
        (jar "-jar target/uberjar/keepintouch-0.1.0-SNAPSHOT-standalone.jar")
        (cur default-directory)) 
    (cd src)
    (shell-command
     (concat "java " jar " " keepintouch-datafile " schedule backlog") buf)
    (cd cur)
    (switch-to-buffer buf)))

(bind-keys ("C-c k" . keptintouch)
           ("C-c K" . keptintouch-backlog))

Buffer Management

Open Org Agenda

This function opens the agenda in full screen.

(defun open-agenda ()
  "Opens the org-agenda."
  (interactive)
  (let ((agenda "*Org Agenda*"))
    (if (equal (get-buffer agenda) nil)
        (org-agenda-list)
      (unless (equal (buffer-name (current-buffer)) agenda)
        (switch-to-buffer agenda))
      (org-agenda-redo t)
      (beginning-of-buffer))))

(bind-key "<f5>" 'open-agenda)
(bind-key "a" 'open-agenda launcher-map)

Kill This Buffer

(defun kill-this-buffer ()
  (interactive)
  (kill-buffer (current-buffer)))

(bind-key "C-x C-k" 'kill-this-buffer)

By default, pressing ‘q’ in either Dired or package-menu runs quit-window, which quits the window and buries its buffer. I’d prefer the buffer to close.

(bind-keys :map dired-mode-map
           ("q" . kill-this-buffer))

(bind-keys :map package-menu-mode-map
           ("q" . kill-this-buffer))

Kill All Other Buffers

(defun kill-other-buffers ()
   "Kill all other buffers."
   (interactive)
   (mapc 'kill-buffer (delq (current-buffer) (buffer-list))))

Minibuffer

This code comes from EmacsWiki.

(defun switch-to-minibuffer ()
  "Switch to minibuffer window."
  (interactive)
  (if (active-minibuffer-window)
      (select-window (active-minibuffer-window))
    (error "Minibuffer is not active")))

(bind-key "M-m" 'switch-to-minibuffer)

Edit as Root

This tip comes from an emacs-fu blog post.

(defun find-file-as-root ()
  "Like `ido-find-file, but automatically edit the file with
root-privileges (using tramp/sudo), if the file is not writable by
user."
  (interactive)
  (let ((file (ido-read-file-name "Edit as root: ")))
    (unless (file-writable-p file)
      (setq file (concat "/sudo:root@localhost:" file)))
    (find-file file)))

(bind-key "C-x F" 'find-file-as-root)

Unfill Paragraph

This function greedily borrowed from Sacha.

(defun unfill-paragraph (&optional region)
  "Takes a multi-line paragraph and makes it into a single line of text."
  (interactive (progn
                 (barf-if-buffer-read-only)
                 (list t)))
  (let ((fill-column (point-max)))
    (fill-paragraph nil region)))

(bind-key "M-Q" 'unfill-paragraph)

Org Go To Heading

Speed commands are really useful, but I often want to make use of them when I’m not at the beginning of a header. This command brings you back to the beginning of an item’s header, so that you can do speed commands.

(defun org-go-speed ()
  "Goes to the beginning of an element's header, so that you can execute speed commands."
  (interactive)
  (when (equal major-mode 'org-mode)
    (if (org-at-heading-p)
        (org-beginning-of-line)
      (org-up-element))))

(bind-key "C-c s" 'org-go-speed)

Hide Mode Line

I wonder if Will Mengarini would approve of Bastien’s post… I know I need all the space I can get on this laptop!

(defvar-local hidden-mode-line-mode nil)

(define-minor-mode hidden-mode-line-mode
  "Minor mode to hide the mode-line in the current buffer."
  :init-value nil
  :global t
  :variable hidden-mode-line-mode
  :group 'editing-basics
  (if hidden-mode-line-mode
      (setq hide-mode-line mode-line-format
            mode-line-format nil)
    (setq mode-line-format hide-mode-line
          hide-mode-line nil))
  (force-mode-line-update)
  ;; Apparently force-mode-line-update is not always enough to
  ;; redisplay the mode-line
  (redraw-display)
  (when (and (called-interactively-p 'interactive)
             hidden-mode-line-mode)
    (run-with-idle-timer
     0 nil 'message
     (concat "Hidden Mode Line Mode enabled.  "
             "Use M-x hidden-mode-line-mode to make the mode-line appear."))))

(bind-key "m" 'hidden-mode-line-mode toggle-map)

Narrowing and Widening

Before this function, I was alternating between C-x n s (org-narrow-to-subtree) and C-x n w (widen) in Org files. I originally implemented this to toggle between those two cases as well as the region. Artur Malabarba and Sacha Chua have made successive improvements: a prefix argument to narrow no matter what, and increasing features for Org.

(defun narrow-or-widen-dwim (p)
  "If the buffer is narrowed, it widens. Otherwise, it narrows
intelligently.  Intelligently means: region, org-src-block,
org-subtree, or defun, whichever applies first.  Narrowing to
org-src-block actually calls `org-edit-src-code'.

With prefix P, don't widen, just narrow even if buffer is already
narrowed."
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
        ((and (boundp 'org-src-mode) org-src-mode (not p))
         (org-edit-src-exit))
        ((region-active-p)
         (narrow-to-region (region-beginning) (region-end)))
        ((derived-mode-p 'org-mode)
         (cond ((ignore-errors (org-edit-src-code))
                (delete-other-windows))
               ((org-at-block-p)
                (org-narrow-to-block))
               (t (org-narrow-to-subtree))))
        ((derived-mode-p 'prog-mode) (narrow-to-defun))
        (t (error "Please select a region to narrow to"))))

(bind-key "n" 'narrow-or-widen-dwim toggle-map)

Toggle Read Only

A lot of modes let you change from read-only to writeable, or backwards: files, Dired, and also wgrep-enabled modes. I use ag, the silver searcher, instead of grep or ack. Anyways, this function decides which mode I am in and acts accordingly. That way, I need to remember just one key bind, C-x t r.

(defun read-write-toggle ()
  "Toggles read-only in any relevant mode: ag-mode, Dired, or
just any file at all."
  (interactive)
  (if (equal major-mode 'ag-mode)
      ;; wgrep-ag can support ag-mode
      (wgrep-change-to-wgrep-mode)
    ;; dired-toggle-read-only has its own conditional:
    ;; if the mode is Dired, it will make the directory writable
    ;; if it is not, it will just toggle read only, as desired
    (dired-toggle-read-only)))

(bind-key "r" 'read-write-toggle toggle-map)

Move Lines

Via Harry Schwartz.

(defun move-line-up ()
  (interactive)
  (transpose-lines 1)
  (forward-line -2))

(defun move-line-down ()
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1))

(bind-keys ("M-<up>" . move-line-up)
           ("M-<down>" . move-line-down))

Window Management

Adapted from Sacha’s config and a reddit comment.

(defun vsplit-last-buffer ()
  (interactive)
  (split-window-vertically)
  (other-window 1 nil)
  (switch-to-next-buffer))

(defun hsplit-last-buffer ()
  (interactive)
  (split-window-horizontally)
  (other-window 1 nil)
  (switch-to-next-buffer))

(bind-key "C-x 2" 'vsplit-last-buffer)
(bind-key "C-x 3" 'hsplit-last-buffer)

Zap Up To Char

(autoload 'zap-up-to-char "misc"
  "Kill up to, but not including ARGth occurrence of CHAR.")
(bind-key "M-Z" 'zap-up-to-char)

Twitter

Hashtags

I work with hashtags pretty frequently for work. Here are some helper functions.

(defun add-hashtag-at-point ()
  (interactive)
  "Adds a hashtag at the beginning of the current word or phrase."
  (let (p1 p2 sbstr hashtxt)
    (backward-word)
    (setq p1 (point))
    (forward-word)
    (setq p2 (point))
    (setq sbstr (buffer-substring p1 p2))
    (delete-region p1 p2)
    (insert (concat "#" sbstr))))

(defun avy-hashtag-word ()
  (interactive)
  "Uses avy to add hashtags interactively."
  (progn
    (avy-goto-word-or-subword-1)
    (forward-char)
    (add-hashtag-at-point)))

(bind-keys ("s-3" . add-hashtag-at-point)
           ("s-#" . avy-hashtag-word))

(bind-keys :map avy-map
           ("h" . avy-hashtag-word))

Tweetable?

(defun tweet-check (posBegin posEnd)
  (interactive "r")
  "Checks if a string in region has under 140 characters."
  (message "Counting")
  (save-excursion
    (let (charCount boolean)
      (setq charCount (- posEnd posBegin))
      (goto-char posBegin)
      (while (and (< (point) posEnd)
                  (re-search-forward "\\w+\\W*" posEnd t)))
      (if (> charCount 140)
          (setq boolean "Not yet tweetable; there are ")
        (setq boolean "This is tweetable; there are "))
      (message "%s%d chars." boolean charCount))))

(bind-key "s-?" 'tweet-check)

Org-Todo-Done

I use org-todo-keywords, which makes running org-todo interactively a little more work. This creates a virtually identical bind to quickly mark something done.

(defun org-todo-done ()
  (interactive)
  (org-todo 'done))

(bind-key "C-c C-S-t" 'org-todo-done)