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.
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.
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.
If I recall correctly, 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. This could be improved, but it’s not so bad.
Use-Package
Use-package is a handful of things: you can make sure a package is downloaded, efficiently configure it (e.g. after load, or as needed), bind keys in a concise way, and more.
(require 'package)
(setq package-archives
'(("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")))
(setq load-prefer-newer t)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t)Async
Async enables asynchronous processing in Emacs, as well as some basic implementations of asynchronous capabilities (e.g. for dired and packages and so on.
(use-package async
:init
(autoload 'dired-async-mode "dired-async.el" nil t)
(dired-async-mode 1)
(async-bytecomp-package-mode 1)
(autoload 'dired-async-mode "dired-async.el" nil t)
(async-bytecomp-package-mode 1)
(dired-async-mode 1))Paradox
I like Paradox - it is an alternative / extension to the built-in package manager.
(use-package paradox
:config
(setq paradox-execute-asynchronously t))Detect Operating System
These functions identify what operating system is hosting Emacs, which can be handy for system specific configuration. I have run Emacs on Windows, OS X, Linux, and BSD. I currently use Linux most of the time, and OS X some of the time, so my configuration is geared towards those. Still, I may want to run my configuration on Windows or BSD in the future so I include those functions.
(defun is-mac-p
()
(eq system-type 'darwin))
(defun is-linux-p
()
(eq system-type 'gnu/linux))
(defun is-windows-p
()
(or
(eq system-type 'ms-dos)
(eq system-type 'windows-nt)
(eq system-type 'cygwin)))
(defun is-bsd-p
()
(eq system-type 'gnu/kfreebsd))Graphical Features
Theme
I still have to do a load-theme -> solarized-dark upon restarting.
(use-package solarized-theme)Font
(set-default-font "Source Code Pro" nil t)
(set-face-attribute 'default nil :height 150)Prettify Symbols
(global-prettify-symbols-mode +1)Cursor
Adaptive cursor width shows width of character, e.g. TAB. Via Pragmatic Emacs.
(setq x-stretch-cursor 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 have a very simple mode line that has the name of the file on the left and the date and time on the right. I’ve found I don’t really need the mode information very often - I usually know which modes are active; if I do need the mode information, I can access that with C-h m, describe-mode. Moreover, that means I don’t need to diminish most packages.
I commented out any variables that I eliminated from the mode-line, so that I can add them in later if I deem them useful.
(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
;; battery-mode-line-string
mode-line-end-spaces))
(setq display-time-format "%a, %b %e %R"
battery-mode-line-format "%p%%" ; Default: "[%b%p%%]"
global-mode-string (remove 'display-time-string global-mode-string)
mode-line-end-spaces (list (propertize " "
'display '(space :align-to (- right 17)))
'display-time-string))
(display-time-mode 1)
(display-time-update)Security
TLS
(setq tls-checktrust t
gnutls-verify-error t)Encryption
(setenv "GPG_AGENT_INFO" nil)Backups
I find Emacs default behavior of saving files relative to the current directory annoying, as it puts backup files everywhere. Instead, this saves backups in one directory, a backup folder within my Emacs directory.
(setq backup-directory-alist
`(("." . ,(expand-file-name
(concat user-emacs-directory "backups")))))Prompts
Yes or No
Make yes or no prompts be y or n prompts.
(fset 'yes-or-no-p 'y-or-n-p)Buffer / File Warnings
Remove the warning if a buffer or file does not exist, so you can create them. (Source.)
(setq confirm-nonexistent-file-or-buffer nil)
(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)Other
Macros
Think about macros! Play with macros!
(setq kmacro-ring-max 30)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 functionality
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 makes the upcase/downcase/capitalize-word functions more usable. This was originally based on this article by Oleh (abo-abo). I found that his code snippets threw errors, as looking-back is supposed to be called with multiple arguments. He seems to have found that problem, and replaced it with the following in his configuration (although I have different binds).
(defun char-upcasep (letter)
(eq letter (upcase letter)))
;;;###autoload
(defun capitalize-word-toggle ()
(interactive)
(let ((start
(car
(save-excursion
(backward-word)
(bounds-of-thing-at-point 'symbol)))))
(if start
(save-excursion
(goto-char start)
(funcall
(if (char-upcasep (char-after))
'downcase-region
'upcase-region)
start (1+ start)))
(capitalize-word -1))))
;;;###autoload
(defun upcase-word-toggle ()
(interactive)
(let ((bounds (bounds-of-thing-at-point 'symbol))
(regionp
(if (eq this-command last-command)
(get this-command 'regionp)
(put this-command 'regionp nil)))
beg end)
(cond
((or (region-active-p) regionp)
(setq beg (region-beginning)
end (region-end))
(put this-command 'regionp t))
(bounds
(setq beg (car bounds)
end (cdr bounds)))
(t
(setq beg (point)
end (1+ beg))))
(save-excursion
(goto-char (1- beg))
(and (re-search-forward "[A-Za-z]" end t)
(funcall (if (char-upcasep (char-before))
'downcase-region
'upcase-region)
beg end)))))
(bind-keys ("M-c" . capitalize-word-toggle)
("M-l" . upcase-word-toggle)
("M-u" . upcase-word-toggle))Also, unbind downcase region, which has plagued my documents for eons.
(unbind-key "C-x C-l")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.
Text Expansion
(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 allow you to move lines and characters with an automatic prefix argument of 5, which accelerates movements. Via 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
I make use of meta-binds to get additional, easy bindings. Prefix arguments can be invoked with control key or C-u.
(bind-keys ("M-1" . delete-other-windows)
("M-O" . mode-line-other-buffer))Copying and Killing
This advises kill-region (C-w) so that, if no region is selected, it kills or copies the current line.
(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))Cycle Spacing
(bind-key "C-x SPC" 'cycle-spacing)Special Key Maps
Toggle Map
Augmented by a post on Irreal. Some keys on the toggle map are elsewhere in this config.
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"))))
(eval-after-load 'org-src
'(bind-key "C-x C-s" 'org-edit-src-exit org-src-mode-map))Cold Folding
For code folding, which is similar to narrowing and widening but different.
(use-package hideshow
:config
(add-hook 'prog-mode-hook 'hs-minor-mode))
(defun toggle-fold ()
(interactive)
(save-excursion
(end-of-line)
(hs-toggle-hiding)))
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)))Keymap
(bind-keys :prefix-map toggle-map
:prefix "C-x t"
("d" . toggle-debug-on-error)
("f" . toggle-fold)
("l" . linum-mode)
("n" . narrow-or-widen-dwim)
("o" . org-mode)
("r" . read-write-toggle)
("t" . text-mode)
("w" . whitespace-mode))Launcher Map
Scratch
(defun scratch ()
(interactive)
(switch-to-buffer-other-window (get-buffer-create "*scratch*")))The default scratch buffer in Emacs uses lisp-interaction-mode, which is great, but it’s useful to have one that uses Org-Mode.
(defun make-org-scratch ()
(interactive)
(find-file "~/org/scratch.org"))Keymap
(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" . eww)
("E" . eshell)
("h" . man)
("l" . paradox-list-packages)
("u" . paradox-upgrade-packages)
("p l" . paradox-list-packages)
("p u" . paradox-upgrade-packages)
("P" . proced)
("s" . scratch)
("S" . make-org-scratch))
(when (is-linux-p)
(bind-keys :map launcher-map
("." . counsel-linux-app)))Macro Map
(bind-keys :prefix-map macro-map
:prefix "C-c m"
("a" . kmacro-add-counter)
("b" . kmacro-bind-to-key)
("e" . kmacro-edit-macro)
("i" . kmacro-insert-counter)
("I" . insert-kbd-macro)
("k" . kmacro-end-or-call-macro-repeat)
("n" . kmacro-cycle-ring-next)
("N" . kmacro-name-last-macro)
("p" . kmacro-cycle-ring-previous)
("r" . apply-macro-to-region-lines)
("s" . kmacro-set-counter))System
All of my packages for interacting with my computer.
OS
OS X
Key Bindings
(when (is-mac-p)
(setq mac-command-modifier 'meta
mac-option-modifier 'super
mac-control-modifier 'control
ns-function-modifier 'hyper))Face Attributes
(when (is-mac-p)
(set-face-attribute 'default nil :height 165))Shells
Over time, I’ve come to prefer Eshell over shell mode or Ansi-term. The main features I tend to use are setting aliases, executing e-Lisp, and writing command output to a buffer.
Eshell
(use-package eshell
:bind (("<f1>" . eshell))
:init
(add-hook 'eshell-mode-hook 'with-editor-export-editor)
(setq eshell-banner-message "")
(defun new-eshell ()
(interactive)
(eshell 'true)))Shell Mode
(use-package shell
:bind (:map shell-mode-map
("<s-up>" . comint-previous-input)
("<s-down>" . comint-next-input))
:init
(dirtrack-mode)
(setq explicit-shell-file-name (cond ((is-linux-p) "/bin/bash")
((is-mac-p) "/usr/bin/bash")))
(when (is-mac-p)
(use-package exec-path-from-shell
:init
(exec-path-from-shell-initialize))))
(add-hook 'after-save-hook
'executable-make-buffer-file-executable-if-script-p)Directories and Files (Dired)
For me, Dired is one of Emacs’ (less-heralded) killer apps, along with Org-Mode and Magit.
(use-package dired
:ensure f
:bind (("<f2>" . dired)
("C-x C-d" . dired)
:map dired-mode-map
("C-x o" . ace-window)
("<return>" . dired-find-alternate-file)
("'" . wdired-change-to-wdired-mode)
("s-/" . dired-filter-mode))
:init
:config
(bind-key "^" (lambda () (interactive) (find-alternate-file "..")) dired-mode-map)
(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+
:init
(setq diredp-hide-details-initially-flag 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)
(use-package dired-subtree
:init
(unbind-key "M-O" dired-mode-map) ;; to support mode-line-other-buffer in Dired
(bind-keys :map dired-mode-map
:prefix "C-,"
:prefix-map dired-subtree-map
:prefix-docstring "Dired subtree map."
("C-i" . dired-subtree-insert)
("i" . dired-subtree-insert)
("C-/" . dired-subtree-apply-filter)
(";" . dired-subtree-remove)
("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)))
(use-package dired-quick-sort
:init
(dired-quick-sort-setup))
(use-package dired-collapse
:config (add-hook 'dired-mode-hook #'dired-collapse-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.
Searching (Ag)
(use-package ag
:bind (:map ag-mode-map
("q" . kill-this-buffer))
:init
(use-package wgrep)
(use-package wgrep-ag)
:config
(setq ag-highlight-search t))Emacs
These are helper packages that make Emacs even more awesome.
Hydra
(use-package hydra
:config
(setq hydra-lv nil))Zooming
(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))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)Zoom Mode
This replaces Golden Ratio mode.
(use-package zoom
:init
(setq zoom-mode t
zoom-size '(0.618 . 0.618)))Completion (Ivy, Counsel, and Swiper; IDO and Smex)
I prefer Ivy, Counsel, and Swiper, but I keep IDO around for Smex (in particular smex-major-mode-commands).
Counsel
(use-package counsel
:bind (("C-x C-f" . counsel-find-file)
("C-x C-m" . counsel-M-x)
("C-x C-f" . counsel-find-file)
("C-h f" . counsel-describe-function)
("C-h v" . counsel-describe-variable)
("M-i" . counsel-imenu)
("M-I" . counsel-imenu)
("C-c i" . counsel-unicode-char)
:map read-expression-map
("C-r" . counsel-expression-history)))Recent Files
Recent files keeps track of which files you’re using; I access it by rebinding find-file-read-only with counsel-recentf.
(use-package recentf
:bind ("C-x C-r" . counsel-recentf)
:init
(recentf-mode t)
(setq recentf-max-saved-items 100))Ivy and Swiper
(use-package swiper
:bind (("C-s" . swiper)
("C-r" . swiper)
("C-c C-r" . ivy-resume)
:map ivy-minibuffer-map
("C-SPC" . ivy-restrict-to-matches))
:init
(ivy-mode 1)
:config
(setq ivy-display-style 'fancy
ivy-height 4
ivy-use-virtual-buffers t
ivy-initial-inputs-alist '((man . "^") (woman . "^")) ;; http://irreal.org/blog/?p=6512
enable-recursive-minibuffers t))IDO
(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
:init
(ido-vertical-mode)
(setq ido-vertical-define-keys 'C-n-and-C-p-only))
(use-package flx-ido
:init
(setq flx-ido-threshold 1000)
(flx-ido-mode 1))Smex
Smex (Smart M-X) implements IDO functionality for the M-X window.
(use-package smex
:bind (("C-x M-m" . smex-major-mode-commands)
("M-x" . smex-major-mode-commands)
("C-c C-c M-x" . execute-extended-command))
:init
(smex-initialize))Company Mode
(use-package company
:bind (("C-." . company-complete)
:map company-active-map
("C-n" . company-select-next)
("C-p" . company-select-previous)
("C-d" . company-show-doc-buffer)
("<tab>" . company-complete))
:init
(global-company-mode 1))Jumping (Avy, Ace-Window and Friends)
Jump to Characters and Words
(use-package avy
:bind ("M-SPC" . avy-goto-char)
:config
(setq avy-background t
avy-keys '(?a ?o ?e ?u ?i ?d ?h ?t ?n ?s)))Jump to Windows
(use-package ace-window
:bind (("C-x o" . ace-window)
("M-2" . ace-window))
:init
(setq aw-background nil
aw-keys '(?a ?o ?e ?u ?i ?d ?h ?t ?n ?s)))Zapping
Generic Zapping
(autoload 'zap-up-to-char "misc"
"Kill up to, but not including ARGth occurrence of CHAR.")
(bind-key "M-Z" 'zap-up-to-char)Jump to Zap
(use-package avy-zap)Jump to Links
(use-package ace-link
:init
(ace-link-setup-default))Jumping Keymap
(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))Selection (Expand Region)
Configured like Magnars in Emacs Rocks, Episode 09.
(use-package expand-region
:bind (("C-@" . er/expand-region)
("C-=" . er/expand-region)
("M-3" . er/expand-region)))
(pending-delete-mode t)Deletion
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
: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)easy-kill
(use-package easy-kill
:bind ("M-w" . easy-kill))Hungry Delete Mode
I learned about this package via Endless Parentheses. This is the first Emacs package that I contributed to!
(use-package hungry-delete
:init
(global-hungry-delete-mode))Files
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")
(when (is-linux-p)
(bind-key "C-x C-s" 'save-buffer))(defvar backup-dir (expand-file-name "~/.emacs.d/emacs_backup/"))
(defvar autosave-dir (expand-file-name "~/.emacs.d/autosave/"))
(setq backup-directory-alist (list (cons ".*" backup-dir))
auto-save-list-file-prefix autosave-dir
auto-save-file-name-transforms `((".*" ,autosave-dir t))
tramp-backup-directory-alist backup-directory-alist
tramp-auto-save-directory autosave-dir)Auto Revert Mode
Revert buffers automatically when underlying files are changed externally.
(global-auto-revert-mode t)
(setq global-auto-revert-non-file-buffers t
auto-revert-verbose nil)Save Place
I learned about save place from Magnars; if you close a buffer, it remembers where you were in the file, so that when you re-open that file the buffer goes straight to that place. The configuration of this mode is very simple as of Emacs 25.1.
(setq-default save-place t)
(setq save-place-file (expand-file-name ".places" user-emacs-directory))
(save-place-mode 1)Regular Expressions
Regexes are great. Not everyone knows them, and most user interfaces don’t expose them, but I think most people who use computers could use them. Luckily, Emacs is great about this. It’s easier to use them if you have good tools for noticing if your regular expressions match input.
Build Regexes
(use-package re-builder
:bind (("C-c R" . re-builder))
:config
(setq reb-re-syntax 'string))Replace Strings with Regexes
(use-package visual-regexp
:bind (("M-5" . vr/replace)
("M-%" . vr/query-replace)))Multiple Occurrences
Moving Between Multiple Occurences (Highlight-Symbol)
I used to use Smart Scan (see Mickey’s explanation and the readme) but have since replaced Smart Scan with highlight-symbol and related functions from Wilfred’s config.
(use-package highlight-symbol
:bind (("M-p" . highlight-symbol-prev)
("M-n" . highlight-symbol-next)
("M-'" . highlight-symbol-query-replace))
:init
(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)))Editing Multiple Occurences (Iedit)
Iedit is probably the best tool I’ve found for editing multiple occurences of the same symbol or string.
(use-package iedit
:bind ("C-;" . iedit-mode))Edit List
Edit List lets you edit a list variable as if it were a buffer.
(use-package edit-list)Discoverability
which-key
(use-package which-key
:init
(which-key-mode))help-fns+
(use-package help-fns+
:bind ("C-h M-k" . describe-keymap)) ; For autoloading.discover-my-major
(use-package discover-my-major
:bind ("C-h C-m" . discover-my-major))Interaction Log
Interaction Log is like view-lossage (C-h l) or kmacro-edit-macro but it is live-updating and not tied to macros. It’s useful for when you type an (awesome? terrible?) Emacs command and want to figure out which function you used so you can use it again or destroy it forever. For a long time I was plagued by accidentally hitting downcase-region and didn’t know what the function was - this would have been so useful!
(use-package interaction-log)
(interaction-log-mode +1)
(defun open-interaction-log ()
(interactive)
(display-buffer ilog-buffer-name))
(bind-key "C-h C-l" 'open-interaction-log)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
:bind (("C-c ," . goto-last-change)
("C-c ." . goto-last-change-reverse)))Selected
(use-package selected
:commands selected-minor-mode
:init
(setq selected-org-mode-map (make-sparse-keymap))
(selected-global-mode 1)
:bind (:map selected-keymap
("d" . downcase-region)
("i" . indent-region)
("m" . apply-macro-to-region-lines)
("q" . selected-off)
("u" . upcase-region)
("w" . count-words-region)
("y" . yank)
:map selected-org-mode-map
("t" . org-table-convert-region)))Beginend
(use-package beginend
:init
(beginend-global-mode))Browsing
External Browsers
(setq browse-url-browser-function 'browse-url-generic
browse-url-generic-program (cond ((is-mac-p) "open")
((is-linux-p) "firefox-beta")))
(bind-key "C-c B" 'browse-url-at-point)EWW
This package brings one neat feature of Conkeror to eww.
(use-package eww-lnum
:after eww
:bind (:map eww-mode-map
("f" . eww-lnum-follow)
("F" . eww-lnum-universal)))Programming and Development
Here are language-specific (largely Lisps) or development-related packages.
Programming Languages
Clojure
Clojure Mode
(use-package clojure-mode
:mode (("\\.boot$" . clojure-mode)
("\\.clj$" . clojure-mode)
("\\.cljs$" . clojurescript-mode)
("\\.edn$" . clojure-mode))
:config
(use-package align-cljlet
:bind (:map clojure-mode-map
("C-! a a" . align-cljlet)
:map clojurescript-mode-map
("C-! a a" . align-cljlet)
:map clojurec-mode-map
("C-! a a" . align-cljlet))))Clojure Refactor
(use-package clj-refactor
:init
(defun my-clj-refactor-mode-hook ()
(clj-refactor-mode 1)
(yas-minor-mode 1))
(add-hook 'clojure-mode-hook #'my-clj-refactor-mode-hook)
(setq cljr-clojure-test-declaration "[clojure.test :refer :all]"
cljr-cljs-clojure-test-declaration "[cljs.test :refer-macros [deftest is use-fixtures]]")
:config
(cljr-add-keybindings-with-prefix "<menu>")
(add-to-list 'cljr-magic-require-namespaces
'("s" . "clojure.spec.alpha"))
(add-to-list 'cljr-magic-require-namespaces
'("S" . "com.rpl.specter"))
(advice-add 'cljr-add-require-to-ns :after
(lambda (&rest _)
(yas-next-field)
(yas-next-field))))Configurations from Endless Parentheses (clj-refactor: Unleash your Clojure wizard and A small improvement to clj-refactor).
CIDER
The function “cider-interactive-eval” comes from A CIDER Excursion.
(use-package cider
:bind (:map cider-repl-mode-map
("M-r" . cider-refresh)
("M-R" . cider-use-repl-tools))
: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
cider-repl-use-pretty-printing t
cider-cljs-lein-repl "(do (use 'figwheel-sidecar.repl-api) (start-figwheel!) (cljs-repl))")
(defun cider-use-repl-tools ()
(interactive)
(cider-interactive-eval
"(use 'clojure.repl)"))
(fset 'cider-eval-last-sexp-and-comment
"\C-u\C-x\C-e\C-a\260 ;; \C-e")
(bind-key "C-j" 'cider-eval-last-sexp-and-comment clojure-mode-map)
;; 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)))Emacs Lisp
Elisp-Slime-Nav
(use-package elisp-slime-nav
: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)
(add-hook 'emacs-lisp-mode-hook 'eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'eldoc-mode)
(add-hook 'ielm-mode-hook 'eldoc-mode)
(add-hook 'cider-mode-hook 'eldoc-mode)Haskell
(use-package haskell-mode)Development Tools
Version Control (Git)
This code from Magnars opens magit-status in one frame, and then restores the old window configuration when you quit.
(use-package magit
:bind (("C-x g" . magit-status)
("C-c g" . magit-status)
:map magit-status-mode-map
("TAB" . magit-section-toggle)
("<C-tab>" . magit-section-cycle)
:map magit-branch-section-map
("RET" . magit-checkout))
:config
(add-hook 'after-save-hook 'magit-after-save-refresh-status)
(setq magit-use-overlays nil
magit-completing-read-function 'ivy-completing-read
magit-push-always-verify nil)
(use-package git-timemachine
:bind (("C-x v t" . git-timemachine)))
(use-package git-link
:bind (("C-x v L" . git-link))
:init
(setq git-link-open-in-browser t))
(use-package pcmpl-git)
(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)
;; Do Not Show Recent Commits in status window
;; https://github.com/magit/magit/issues/3230#issuecomment-339900039
(magit-add-section-hook 'magit-status-sections-hook
'magit-insert-unpushed-to-upstream
'magit-insert-unpushed-to-upstream-or-recent
'replace))Project Management (Projectile)
Projectile configuration adapted from Improving Projectile with extra commands on Endless Parentheses.
(use-package projectile
:init
(projectile-global-mode)
(use-package ibuffer-projectile
:bind (("C-x C-b" . ibuffer)
:map ibuffer-mode-map
("c" . clean-buffer-list)
("n" . ibuffer-forward-filter-group)
("p" . ibuffer-backward-filter-group))
:init
(add-hook 'ibuffer-hook
(lambda ()
(ibuffer-projectile-set-filter-groups)
(unless (eq ibuffer-sorting-mode 'alphabetic)
(ibuffer-do-sort-by-alphabetic)))))
:config
(setq projectile-enable-caching t
projectile-create-missing-test-files t
projectile-completion-system 'ivy
projectile-use-git-grep t
projectile-switch-project-action #'projectile-commander
;; I'm redefining a lot of bindings, so unset pre-defined methods
;; and define everyting here.
projectile-commander-methods nil)
(def-projectile-commander-method ?? "Commander help buffer."
(ignore-errors (kill-buffer projectile-commander-help-buffer))
(with-current-buffer (get-buffer-create projectile-commander-help-buffer)
(insert "Projectile Commander Methods:\n\n")
(dolist (met projectile-commander-methods)
(insert (format "%c:\t%s\n" (car met) (cadr met))))
(goto-char (point-min))
(help-mode)
(display-buffer (current-buffer) t))
(projectile-commander))
(def-projectile-commander-method ?a
"Run ag on project."
(counsel-projectile-ag))
(def-projectile-commander-method ?b
"Open an IBuffer window showing all buffers in the current project."
(counsel-projectile-switch-to-buffer))
(def-projectile-commander-method ?B
"Display a project buffer in other window."
(projectile-display-buffer))
(def-projectile-commander-method ?c
"Run `compile' in the project."
(projectile-compile-project nil))
(def-projectile-commander-method ?d
"Open project root in dired."
(projectile-dired))
(def-projectile-commander-method ?D
"Find a project directory in other window."
(projectile-find-dir-other-window))
(def-projectile-commander-method ?e
"Open an eshell buffer for the project."
;; This requires a snapshot version of Projectile.
(projectile-run-eshell))
(def-projectile-commander-method ?f
"Find a project directory in other window."
(counsel-projectile-find-file))
(def-projectile-commander-method ?F
"Find project file in other window."
(projectile-find-file-other-window))
(def-projectile-commander-method ?g
"Open project root in vc-dir or magit."
(projectile-vc))
(def-projectile-commander-method ?G
"Run grep on project."
(projectile-grep))
(def-projectile-commander-method ?i
"Open an IBuffer window showing all buffers in the current project."
(projectile-ibuffer))
(def-projectile-commander-method ?j
"Jack in to CLJ or CLJS depending on context."
(let* ((opts (projectile-current-project-files))
(file (ido-completing-read
"Find file: "
opts
nil nil nil nil
(car (cl-member-if
(lambda (f)
(string-match "core\\.clj\\'" f))
opts)))))
(find-file (expand-file-name
file (projectile-project-root)))
(run-hooks 'projectile-find-file-hook)
(if (derived-mode-p 'clojurescript-mode)
(cider-jack-in-clojurescript)
(cider-jack-in))))
(def-projectile-commander-method ?r
"Find recently visited file in project."
(projectile-recentf))
(def-projectile-commander-method ?s
"Switch project."
(counsel-projectile-switch-project))
(def-projectile-commander-method ?t
"Find test file in project."
(projectile-find-test-file))
(def-projectile-commander-method ?\C-?
"Go back to project selection."
(projectile-switch-project)))Style Checking (Checkdoc with Flycheck)
Flycheck presents a handsome and usable interface for checkdoc, amongst other things.
(use-package flycheck
:init
(use-package flycheck-clojure)
(global-flycheck-mode)
(setq flycheck-indication-mode 'right-fringe)
:config
(flycheck-clojure-setup)
(require 'flycheck-joker))REST Exploring (Restclient)
See Magnars’ tutorial on Emacs Rocks.
(use-package restclient)Remote Pairing (Floobits)
(use-package floobits)Developing in Emacs
Whitespace
(add-hook 'before-save-hook 'whitespace-cleanup)Managing Parentheses (Smartparens)
(use-package smartparens
: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
:ensure f)
(bind-key "s" 'smartparens-mode toggle-map)
(when (is-mac-p)
(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
:init
(add-hook 'prog-mode-hook 'rainbow-delimiters-mode)))Line Numbering (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
:init
(setq linum-format 'linum-relative)
:config
(setq linum-relative-current-symbol ""))Commenting (comment-dwim-2)
Additions via A comment-or-uncomment-sexp command in Emacs · Endless Parentheses. Would love a solution integrated into comment-dwim-2.
(use-package comment-dwim-2
:bind
(("M-;" . comment-dwim-2)
("C-M-;" . comment-or-uncomment-sexp))
:init
(defun uncomment-sexp (&optional n)
"Uncomment a sexp around point."
(interactive "P")
(let* ((initial-point (point-marker))
(inhibit-field-text-motion t)
(p)
(end (save-excursion
(when (elt (syntax-ppss) 4)
(re-search-backward comment-start-skip
(line-beginning-position)
t))
(setq p (point-marker))
(comment-forward (point-max))
(point-marker)))
(beg (save-excursion
(forward-line 0)
(while (and (not (bobp))
(= end (save-excursion
(comment-forward (point-max))
(point))))
(forward-line -1))
(goto-char (line-end-position))
(re-search-backward comment-start-skip
(line-beginning-position)
t)
(ignore-errors
(while (looking-at-p comment-start-skip)
(forward-char -1)))
(point-marker))))
(unless (= beg end)
(uncomment-region beg end)
(goto-char p)
;; Indentify the "top-level" sexp inside the comment.
(while (and (ignore-errors (backward-up-list) t)
(>= (point) beg))
(skip-chars-backward (rx (syntax expression-prefix)))
(setq p (point-marker)))
;; Re-comment everything before it.
(ignore-errors
(comment-region beg p))
;; And everything after it.
(goto-char p)
(forward-sexp (or n 1))
(skip-chars-forward "\r\n[:blank:]")
(if (< (point) end)
(ignore-errors
(comment-region (point) end))
;; If this is a closing delimiter, pull it up.
(goto-char end)
(skip-chars-forward "\r\n[:blank:]")
(when (eq 5 (car (syntax-after (point))))
(delete-indentation))))
;; Without a prefix, it's more useful to leave point where
;; it was.
(unless n
(goto-char initial-point))))
(defun comment-sexp--raw ()
"Comment the sexp at point or ahead of point."
(pcase (or (bounds-of-thing-at-point 'sexp)
(save-excursion
(skip-chars-forward "\r\n[:blank:]")
(bounds-of-thing-at-point 'sexp)))
(`(,l . ,r)
(goto-char r)
(skip-chars-forward "\r\n[:blank:]")
(save-excursion
(comment-region l r))
(skip-chars-forward "\r\n[:blank:]"))))
(defun comment-or-uncomment-sexp (&optional n)
"Comment the sexp at point and move past it.
If already inside (or before) a comment, uncomment instead.
With a prefix argument N, (un)comment that many sexps."
(interactive "P")
(if (or (elt (syntax-ppss) 4)
(< (save-excursion
(skip-chars-forward "\r\n[:blank:]")
(point))
(save-excursion
(comment-forward 1)
(point))))
(uncomment-sexp n)
(dotimes (_ (or n 1))
(comment-sexp--raw)))))Indenting (aggressive-indent)
(use-package aggressive-indent
: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.
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!
Configuration
I use the stock package of org-mode as the default major mode.
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.
(use-package org
:bind (("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))
:init
(setq default-major-mode 'org-mode
org-directory "~/org/"
org-log-done t
org-startup-indented t
org-startup-truncated nil
org-startup-with-inline-images t
org-completion-use-ido 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-src-fontify-natively t
org-lowest-priority 68
org-default-priority 68
org-ellipsis "↴"
org-expiry-inactive-timestamps t
org-show-notification-handler 'message
org-special-ctrl-a/e t
org-special-ctrl-k t
org-yank-adjusted-subtrees t
org-stuck-projects
'("+LEVEL=2/-MAYBE-DONE-SOMEDAY-CANCELLED" ("TODO" "STARTED") nil "\\<IGNORE\\>")
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")))
(add-to-list 'org-global-properties
'("Effort_ALL". "0:05 0:15 0:30 1:00 2:00 3:00 4:00")))Packages
org-modules
(require 'org-install)
(setq org-modules '(org-habit org-info))
(org-load-modules-maybe t)org-habits
I use the org-habits module.
(setq org-habit-graph-column 105)
(defun org-make-habit ()
(interactive)
(org-set-property "STYLE" "habit"))org-gcal
(use-package org-gcal
:bind (:map org-agenda-mode-map
;; "r" is bound to org-agenda-redo
("g" . org-gcal-sync))
:init
(add-hook 'org-capture-after-finalize-hook (lambda () (org-gcal-sync))))org-cliplink
org-cliplink lets you insert a link from your clipboard with a title that is fetched from the page’s metadata.
(use-package org-cliplink
:bind ("C-x p i" . org-cliplink))org-bullets
(use-package org-bullets
:init
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))Configuration
Functionality
Agendas
Configuration(setq org-agenda-inhibit-startup nil
org-agenda-show-future-repeats nil
org-agenda-start-on-weekday nil)
(unbind-key "C-c [")
(unbind-key "C-c ]")(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)(add-hook 'org-agenda-finalize-hook (lambda () (delete-other-windows)))(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))
(bind-key "y" 'org-agenda-todo-yesterday org-agenda-mode-map)Refiling
(setq org-refile-targets (quote ((nil :maxlevel . 9)
(org-agenda-files :maxlevel . 9)))
org-refile-use-cache t
org-refile-use-outline-path t)Clocking
I really like Org-mode’s clocking functionality. I mostly use it for keeping time of billable tasks.
Configuration(setq org-log-done 'time
org-clock-idle-time nil
org-clock-continuously nil
org-clock-persist t
org-clock-in-switch-to-state "STARTED"
org-clock-in-resume nil
org-clock-report-include-clocking-task t
org-clock-out-remove-zero-time-clocks t
;; Too many clock entries clutter up a heading
org-log-into-drawer t
org-clock-into-drawer 1)(defhydra hydra-org-clock (:color blue :hint nil)
"
^Clock:^ ^In/out^ ^Edit^ ^Summary^ | ^Timers:^ ^Run^ ^Insert
-^-^-----^-^----------^-^------^-^----------|--^-^------^-^-------------^------
(_?_) _i_n _e_dit _g_oto entry | (_z_) _r_elative ti_m_e
^ ^ _c_ontinue _q_uit _d_isplay | ^ ^ cou_n_tdown i_t_em
^ ^ _o_ut ^ ^ _r_eport | ^ ^ _p_ause toggle
^ ^ ^ ^ ^ ^ ^ ^ | ^ ^ _s_top
"
("i" org-clock-in)
("c" org-clock-in-last)
("o" org-clock-out)
("e" org-clock-modify-effort-estimate)
("q" org-clock-cancel)
("g" org-clock-goto)
("d" org-clock-display)
("r" org-clock-report)
("?" (org-info "Clocking commands"))
("r" org-timer-start)
("n" org-timer-set-timer)
("p" org-timer-pause-or-continue)
("s" org-timer-stop)
("m" org-timer)
("t" org-timer-item)
("z" (org-info "Timers")))
(bind-key "C-c w" 'hydra-org-clock/body)ID’s
By using unique ID’s for links in Org-mode, links will work even if you move them across files.
(setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id
org-clone-delete-id t)Speed Commands
Set User Speed Commands(setq org-use-speed-commands t
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)
("m" org-mark-subtree)
("s" org-sort)
("x" smex-major-mode-commands)
("X" org-todo-done)
("R" org-done-and-archive)
("y" org-todo-yesterday)))Structure Templates
Add structure templates for editing Emacs Lisp and encrypting an org-mode file.
(add-to-list 'org-structure-template-alist '("g" "# -*- mode:org; epa-file-encrypt-to: (\"michaelwfogleman@gmail.com\") -*-"))
(add-to-list 'org-structure-template-alist '("l" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC" "<src lang=\"emacs-lisp\">\n?\n</src>"))Jumping to Speed: org-go-speed
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)Movement (org-teleport)
This function comes from John Kitchin.
(defun org-teleport (&optional arg)
"Teleport the current heading to after a headline selected with avy.
With a prefix ARG move the headline to before the selected
headline. With a numeric prefix, set the headline level. If ARG
is positive, move after, and if negative, move before."
(interactive "P")
;; Kill current headline
(org-mark-subtree)
(kill-region (region-beginning) (region-end))
;; Jump to a visible headline
(avy-with avy-goto-line (avy--generic-jump "^\\*+" nil avy-style))
(cond
;; Move before and change headline level
((and (numberp arg) (> 0 arg))
(save-excursion
(yank))
;; arg is what we want, second is what we have
;; if n is positive, we need to demote (increase level)
(let ((n (- (abs arg) (car (org-heading-components)))))
(cl-loop for i from 1 to (abs n)
do
(if (> 0 n)
(org-promote-subtree)
(org-demote-subtree)))))
;; Move after and change level
((and (numberp arg) (< 0 arg))
(org-mark-subtree)
(goto-char (region-end))
(when (eobp) (insert "\n"))
(save-excursion
(yank))
;; n is what we want and second is what we have
;; if n is positive, we need to demote
(let ((n (- (abs arg) (car (org-heading-components)))))
(cl-loop for i from 1 to (abs n)
do
(if (> 0 n) (org-promote-subtree)
(org-demote-subtree)))))
;; move to before selection
((equal arg '(4))
(save-excursion
(yank)))
;; move to after selection
(t
(org-mark-subtree)
(goto-char (region-end))
(when (eobp) (insert "\n"))
(save-excursion
(yank))))
(outline-hide-leaves))
(add-to-list 'org-speed-commands-user
(cons "q" (lambda ()
(avy-with avy-goto-line
(avy--generic-jump "^\\*+" nil avy-style)))))
(add-to-list 'org-speed-commands-user (cons "T" 'org-teleport))
(bind-key "T" 'org-teleport selected-org-mode-map)Other
Prettify Symbols
(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)))Email (mu4e)
I am currently using mu4e, which was indeed pretty easy to set up. For receiving mail, I use mbsync, not offlineimap. I use a stock Emacs package, smptmail, to send mail. It plugs into the gnutls command line utilities, which my Arch machine has installed already.
I also have queuing set up, so that I can still “send” emails without Internet access. Once this is enabled, you can see some new options in the main view, to toggle online/offline [m], and to send queued mail [f].
The folder home/user/Maildir/queue needs to be created with the command “mu mkdir.” After that, run “touch ~/Maildir/queue/.noindex” to make sure mu doesn’t index this folder.
Messages that Emacs cannot read can be read in the browser with the “aV” shortcut.
See the mu4e user manual re: Attaching files with dired.
(use-package mu4e
:if (is-linux-p)
:load-path "/usr/share/emacs/site-lisp/mu4e/"
:ensure f
:bind (:map mu4e-headers-mode-map
("C-c o" . org-mu4e-store-and-capture)
:map mu4e-view-mode-map
("C-c o" . org-mu4e-store-and-capture))
:init
;;store org-mode links to messages
(require 'org-mu4e)
(require 'gnus-dired)
(setq mu4e-maildir (expand-file-name "~/mbsync")
mu4e-drafts-folder "/[Gmail].Drafts"
mu4e-sent-folder "/[Gmail].Sent Mail"
mu4e-trash-folder "/[Gmail].Trash"
mu4e-get-mail-command "mbsync gmail"
mu4e-update-interval 1800
;; Rename files when moving, NEEDED FOR MBSYNC
mu4e-change-filenames-when-moving t
mu4e-maildir-shortcuts
'( ("/INBOX" . ?i)
("/[Gmail].Sent Mail" . ?s)
("/[Gmail].Trash" . ?t)
("/[Gmail].All Mail" . ?a))
mu4e-headers-skip-duplicates t
mu4e-view-show-images t
mu4e-view-image-max-width 800
mu4e-compose-signature
(concat
"Michael Fogleman\n"
"http://www.mwfogleman.com\n")
mu4e-sent-messages-behavior 'delete
message-kill-buffer-on-exit t
mu4e-headers-skip-duplicates t
;;store link to message if in header view, not to header query
org-mu4e-link-query-in-headers-mode nil
gnus-dired-mail-mode 'mu4e-user-agent)
(use-package smtpmail
:init
(setq message-send-mail-function 'smtpmail-send-it
smtpmail-stream-type 'starttls
smtpmail-default-smtp-server "smtp.gmail.com"
smtpmail-smtp-server "smtp.gmail.com"
smtpmail-smtp-service 587
smtpmail-queue-mail nil
;; Use mu mkdir ~/mbsync/queue to set up first
smtpmail-queue-dir "/home/michael/mbsync/queue/cur"))
;; make the `gnus-dired-mail-buffers' function also work on
;; message-mode derived modes, such as mu4e-compose-mode
(defun gnus-dired-mail-buffers ()
"Return a list of active message buffers."
(let (buffers)
(save-current-buffer
(dolist (buffer (buffer-list t))
(set-buffer buffer)
(when (and (derived-mode-p 'message-mode)
(null message-sent-message-via))
(push (buffer-name buffer) buffers))))
(nreverse buffers)))
(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
(defun mu4e-open-email-inbox ()
"Update and open my email inbox. For interactive use in workflows."
(interactive)
(progn
(mu4e-update-mail-and-index t)
(mu4e~headers-jump-to-maildir "/INBOX")))
(bind-key "C-c e" 'mu4e-open-email-inbox)
:config
(add-to-list 'mu4e-view-actions
'("ViewInBrowser" . mu4e-action-view-in-browser) t)
(add-hook 'mu4e-compose-mode-hook 'turn-on-orgstruct)
(add-hook 'mu4e-compose-mode-hook 'auto-fill-mode))Markdown
(use-package markdown-mode
:init
(add-hook 'markdown-mode-hook 'turn-on-orgstruct))Calculator (Calc)
(use-package calc
:config
(setq calc-display-trail ()))Spell Checking (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"))Document Conversions (Pandoc)
(use-package pandoc-mode
:config
(when (is-mac-p)
(add-to-list 'exec-path "/usr/local/texlive/2016basic/bin/universal-darwin")))CSV
(use-package csv-mode
:mode ("\\.csv$" . csv-mode))RSS Feeds (Elfeed)
Mark all feeds as read from Manuel Ubeti.
(use-package elfeed
:bind (:map elfeed-search-mode-map
("g" . elfeed-update)
("R" . my-elfeed-mark-all-read)
("?" . discover-my-major)
:map elfeed-show-mode-map
("o" . ace-link-eww))
:config
(defun my-elfeed ()
(interactive)
(progn
(elfeed)
(elfeed-update)))
(defun my-elfeed-mark-all-read ()
"Mark all feeds as read."
(interactive)
(call-interactively 'mark-whole-buffer)
(elfeed-search-untag-all-unread)
(kill-this-buffer))
(bind-key "C-c f" 'my-elfeed))Read It Later (Pocket)
(use-package pocket-mode
:defer t
:config
(setq pocket-items-per-page 30))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/.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 "~/Documents/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.2.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
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 Dired, the packages menu, or Elfeed 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))
(bind-keys :map elfeed-search-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 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)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))Flush Empty Lines
(defun flush-empty-lines ()
(interactive)
(flush-lines "^$"))Tasks
Find replacement for org-timeline
MAYBE Find fix for capitalize/lowercase functions
Document behavior
MAYBE Ping Oleh
Set up org-capture with Firefox
Org Capture :: Add-ons for Firefox Orca - new package to improve org-capture from browser · (or emacs