Complete Computing Environment: Core Emacs

Table of Contents

(provide 'cce-emacs-core)

Bootstrapping Emacs

Make sure our customizations, if they exist, aren't made inside of the init file itself, since they'll be wiped out.

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

I have some packages that are vendorized in this repository, make sure they get loaded.

(add-to-list 'load-path "~/.emacs.d/cce/vendor")

package.el Setup

My strategy with regard to packaging is simple – let the system handle it. In the past, I've tried to use things like Cask1 or use-package2, but Emacs bundles a package manager that is, frankly, Good Enough for my tastes. Cask requires a python bootstrap script, and Use Package's declarative syntax doesn't fit with how I want to structure CCE or my previous literate configurations. So I just use package.el, especially since I don't need to support Emacs 23 or anything crazy like that.

I mainly use Melpa for my packages, I am going to experiment with using only Org, ELPA and MELPA, but I probably will end up having to pull in Marmalade as well.


(add-to-list 'package-archives
             '("org" . "") t)
(add-to-list 'package-archives
             '("gnu" . "") t)
(add-to-list 'package-archives
             '("melpa" . "") t)

I define cce/did-refresh-packages, which is used as a signal in install-pkgs that we need to refresh the package archives.

(setq cce/did-refresh-packages nil)

install-pkgs is a simple elisp function that will iterate over a list, and install each package in it, if it is not installed. If cce/did-refresh-packages is set to nil, it'll also refresh the package manager.

(defun install-pkgs (list)
  (dolist (pkg list)
    (unless (package-installed-p pkg)
      (unless cce/did-refresh-packages
        (setq cce/did-refresh-packages t))
      (package-install pkg))))

Make sure org always comes from the Org ELPA.

(setq package-pinned-archives '())
(add-to-list 'package-pinned-archives '(org-plus-contrib . "org"))
(add-to-list 'package-pinned-archives '(org . "org"))

Getting Org to install from the Orgmode repository is … really really hard if there is an org-mode 8 which loads from the system. I have an interactive script which makes sure that Emacs loads Org-mode 9 in to an environment which does not have org-mode 8 installed:

- name: org-mode installed
  become: yes
  become_user: "{{local_account}}"
  shell: emacs -q --eval "(progn (package-initialize) (setq package-archives '((\"org\" . \"\"))) (setq package-pinned-archives '((org . \"org\") (org-plus-contrib . \"org\"))) (package-refresh-contents) (list-packages))"
  register: org_install
  changed_when: not org_install.stdout == ""

el-get Setup

El-get is a recipe-based package manager that can be used to easily install things that aren't in the Package archives, such as random libraries that are only hosted on Emacswiki, or some random github gist or text file somewhere.

(add-to-list 'load-path "~/.emacs.d/el-get/el-get")
(setq el-get-notify-type 'message)

(unless (require 'el-get nil 'noerror)
    (goto-char (point-max))

(setq cce/el-get-packages nil)

After every other module is loaded, we should install their dependent packages, which is done using (el-get 'sync).

(add-hook 'after-cce-hook (lambda ()
                            (el-get 'sync cce/el-get-packages)) t)

Helper Methods

I define a bunch of weird little helper methods all over the place, these are simple, DRY methods that I can use everywhere in my system.

I am fairly certain there is a chomp equivalent in the emacs standard library, but I've not been able to figure out what it's called yet, so I have my own for now.

(defun cce/str-chomp (str)
  "Chomp leading and trailing whitespace from STR."
  (while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'" str)
    (setq str (replace-match "" t t str)))
(defmacro cce/with-any-domain (envs &rest body)
  "Run BODY if the current CCE Env is one of ENVS."
  (let ((hostname (with-temp-buffer (shell-command "hostname" (current-buffer)) (cce/str-chomp (buffer-string)))))
    `(when (member ,hostname ,envs)
(defun scissors ()
  (insert "--8<---------------cut here---------------start------------->8---\n")
    (insert "\n--8<---------------cut here---------------end--------------->8---\n")))

Long running Emacs jobs

I have a few long running jobs that I leave terminals open for. It's not great, and it's just un-needed extra overhead for things that I don't touch more than twice a day. They're not things that I can easily migrate to SystemD user services, since they require interactive input such as SSH key passphrases and that sort of things.

(defun cce/async-forever (command buffer-name)
  "Run a command in an async buffer forever"
  (async-shell-command (concat "while true; do " command "; sleep 5; done")
                       (get-buffer-create buffer-name)))

I use this, for example, for this script which sets a blink(1) my roommate gave me to a certain color based on my computer's load:

import os
import sys
import subprocess

hostname = subprocess.check_output('hostname').rstrip()
if hostname != "kusanagi":


value = os.getloadavg()[0]

if value > 5.0:
    hue = 64-int(value*1.5 / upper_thresh * 64)
    sat = 255
elif value > 3.0:
    hue = 64-int(value / upper_thresh * 64 + 64)
    sat = 255
    hue = int(value / upper_thresh * 64 + 64)
    sat = int(value / upper_thresh * 255)

print "load at {load}, setting to hue {hue} and sat {sat}".format(load=value, hue=hue, sat=sat)

os.system("sudo ~/Code/blink1/commandline/blink1-tool --hsb={hue},{sat},255".format(hue=hue, sat=sat))
- name: blink wrapper installed
  become: yes
  become_user: "{{local_account}}"
    src: out/blink-load
    dest: ~/bin/blink-load
    mode: 0750
(defun blink-on-load ()
  (cce/async-forever "blink-load" "*blink-load*"))

Core Workflow and Computing Environment

I almost always want Emacs's server running. The ability to be able to attach to Emacs to edit files from the command line, or to rescue a broken X11 session, or to do batch operations using Emacs's text-processing libraries are all super powerful, and it makes little sense to not use this.

(unless (boundp 'server-process)

Desktop Save Mode3 is the session management system for Emacs; it holds state of open buffers and session variables across instantiation of Emacs, which is super useful in mobile setups like laptops which reboot a lot. To make startup sane, I'm choosing to eagerly restore the 10 most recently used buffers on startup, and then in Idle the system will restore the remaining buffers.

(desktop-save-mode 1)
(setq desktop-restore-eager 10)
(setq desktop-files-not-to-save "\\(^/[^/:]*:\\|(ftp)$\\|KILL\\)")
(setq desktop-restore-frames nil)

Emacs should automatically save my state, and does so every five minutes.

(defun cce/desktop-save ()
  "Write the desktop save file to ~/.emacs.d"
  (desktop-save user-emacs-directory))
(if (not (boundp 'cce/desktop-save-timer))
    (setq cce/desktop-save-timer
          (run-with-idle-timer 300 t 'cce/desktop-save)))

The splashscreen is useful if you've never used Emacs before, but I'd rather just drop straight in to the Scratch buffer.

(setq inhibit-splash-screen t)

Uniquify buffer names; this makes working on multiple codebases more sane. Sometimes a single project can have multiple files with the same name, for example tests/index.js and tests/units/index.js, tests/lib/index.js, etc. The buffers will be listed as index.js:tests, index.js:units, and index.js:lib respectively. You can tweak that by looking at the eldoc fo uniquify-buffer-name-style.

(require 'uniquify)
(setq uniquify-buffer-name-style 'post-forward
      uniquify-separator ":")

Diminish some common modes; Diminishing a mode makes it eat less space in the modeline, by replacing the text on the modeline with something else. The Emacs config I stole these from uses a bunch of unicode characters, so I kind of backfill that, too. I also hide some modes that I don't give any shits about, so.

(install-pkgs '(diminish))
(require 'diminish)
(diminish 'visual-line-mode "")
(diminish 'isearch-mode "?")

By default, my machine drops me in to a *scratch* buffer. Originally designed to be an lisp playground that you could dive right in to on start up, it's sort of eclipsed that for me in to a general purpose buffer, where I will put things like elisp I am prototyping or playtesting, small snippets of code that I want to use in dayjob, etc. But when you kill emacs, or it dies, that buffer disappears. This code will save the Scratch buffer every five minutes and restores it on Emacs startup.

(defun save-persistent-scratch ()
  "Write the contents of *scratch* to the file name
  (with-current-buffer (get-buffer-create "*scratch*")
    (write-region (point-min) (point-max) "~/.emacs.d/persistent-scratch")))

(defun load-persistent-scratch ()
  "Load the contents of `persistent-scratch-file-name' into the
  scratch buffer, clearing its contents first."
  (if (file-exists-p "~/.emacs.d/persistent-scratch")
      (with-current-buffer (get-buffer "*scratch*")
        (delete-region (point-min) (point-max))
        (insert-file-contents "~/.emacs.d/persistent-scratch"))))

(add-hook 'after-init-hook 'load-persistent-scratch)
(add-hook 'kill-emacs-hook 'save-persistent-scratch)

(if (not (boundp 'cce/save-persistent-scratch-timer))
    (setq cce/save-persistent-scratch-timer
          (run-with-idle-timer 300 t 'save-persistent-scratch)))

I restart emacs a lot, especially on my n900, and it would be nice to have the history of things like M-x saved across those sessions. savehist mode gives us that4.

(require 'savehist)
(setq savehist-file (concat user-emacs-directory "savehist"))
(savehist-mode 1)
(setq savehist-save-minibuffer-history 1)
(setq savehist-additional-variables

A lot of systems outside of the Emacs environment will edit files for me, especially Org-mode and Git. global-auto-revert-mode will make that sane.

(global-auto-revert-mode t)

Jump to the *scratch* buffer easily with bh/switch-to-scratch

(defun bh/switch-to-scratch ()
  (switch-to-buffer "*scratch*"))

Toggle line wrapping with <f7>

(global-set-key (kbd "<f7>") 'bh/set-truncate-lines)
(defun bh/set-truncate-lines ()
  "Toggle value of truncate-lines and refresh window display."
  (setq truncate-lines (not truncate-lines))
  ;; now refresh window display (an idiom from simple.el):
    (set-window-start (selected-window)
                      (window-start (selected-window)))))

recentf gives us a "Recent Files" menu and also some pretty neat Projectile integrations

(recentf-mode 1)

Use ibuffer instead of list-buffers

(global-set-key (kbd "C-x C-b") 'ibuffer)
(defun kill-this-buffer-y-or-n ()
  (let ((buf (current-buffer)))
    (if (y-or-n-p (format "Kill %s?" (buffer-name buf)))
        (kill-buffer buf))))

Prevent Emacs from litering backup files all over the place; this means that they won't get sync'd and written to other hosts on Syncthing, but I'm not sure if that's actually a problem.

(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)

Emacs ships with save-place-mode, which writes the location you had a file open to when you close it. I think desktop-mode does this as well, across sessions.

(setq-default save-place t)
(setq save-place-file (expand-file-name ".places" user-emacs-directory))

(save-place-mode 1)

Modal Editing with Evil Mode

(setq evil-want-keybinding nil)
(install-pkgs '(evil
(require 'evil)
(evil-mode 1)
(global-evil-leader-mode 1)
(require 'evil-collection)
(setq evil-emacs-state-cursor '("firebrick" box))
(setq evil-normal-state-cursor '("firebrick" box))
(setq evil-visual-state-cursor '("cyan" box))
(setq evil-insert-state-cursor '("cyan" box))
(setq evil-replace-state-cursor '("red" bar))
(setq evil-operator-state-cursor '("red" hollow))
(loop for (mode . state) in '((text-mode . normal)
                              (exwm-mode . emacs)
                              (sauron-mode . emacs)
                              (shell-mode . insert)
                              (git-commit-mode . insert)
                              (git-rebase-mode . emacs)
                              (magit-branch-manager-mode . emacs)
                              (mingus-playlist-mode . emacs)
                              (mingus-browse-mode . emacs)
                              (mpc-mode . emacs)
                              (mpc-status-mode . emacs)
                              (mpc-tagbrowser-mode . emacs)
                              (mpc-tagbrowser-dir-mode . emacs)
                              (mpc-songs-mode . emacs))
      do (evil-set-initial-state mode state))

Set up and configure a Leader key.

(eval-after-load 'evil (lambda ()
                         (add-hook 'evil-normal-state-entry-hook 'evil-leader-mode)
                         (evil-leader/set-leader "SPC")))
(eval-after-load "org"
    (load-library "syndicate")
    (add-hook 'org-mode-hook #'syndicate-mode)
    (evil-define-key 'normal syndicate-mode-map
      "gc" 'org-cycle)))

Common Keybindings with Hydra

In the past, I would provide myself with jumps in to other modes and features that I use often using evil-leader. However, in this new brave world that I am working in, I will rarely be in evil-normal-state, which makes Leader inaccessible. This leads me to Hydra5, which allows you to define, basically, easily accessed minor modes such as a "window management" minor-mode6, etc.

It's basically little more than a big-hairy-macro, but it works nicely. I use C-x x as a sort of self-tracked prefix for these, and then a Hydra after that.

I have a set of prefix mnemonics that I try to use for my bindings:

  • b: Things that operate on buffers
  • p: Things that projectile does
  • e: Things that operate on Errors

Let's install and load Hydra.

(install-pkgs '(hydra))
(require 'hydra)

Window Manipulation

First, we define, hydra-window, a hydra that allows you to move between frames and windows, using a combination of windmove, ace-window and winner. We bind that to C-x w.

(install-pkgs '(ace-window
(require 'hydra-examples)
(require 'transpose-frame)
(defhydra hydra-window (:color red :hint nil :columns 8)
  ("h" windmove-left "Left")
  ("j" windmove-down "Right")
  ("k" windmove-up "Up")
  ("l" windmove-right "Down")

  ("H" hydra-move-splitter-left "Splitter Left")
  ("J" hydra-move-splitter-down "Splitter Right")
  ("K" hydra-move-splitter-up "Splitter Up")
  ("L" hydra-move-splitter-right "Splitter Right")
  ("|" (lambda ()
         (windmove-right)) "Split | and Right")
  ("_" (lambda ()
         (windmove-down))"Split - and Down")
  ("v" split-window-right "Split | and Left")
  ("x" split-window-below "Split - and Up")

  ("u" winner-undo "Undo")
  ("r" winner-redo "Redo")

  ("o" other-window "Other Window")
  ("a" ace-window "Select Window" :exit t)
  ("s" ace-swap-window "Swap Windows")

  ("f" make-frame "New Frame" :exit t)

  ("da" ace-delete-window "Select + Delete Window")
  ("dw" delete-window "Delete Window")
  ("db" kill-this-buffer "Kill Buffer")
  ("df" delete-frame "Delete Frame" :exit t)
  ("i" ace-maximize-window "Select and Maximize")
  ("b" ido-switch-buffer "Buffer")
  ("t" transpose-frame "Transpose")

  ("wi" ivy-push-view "Push View")
  ("wo" ivy-pop-view "Pop View")

  ("p" previous-buffer "Previous Buffer")
  ("n" next-buffer "Next Buffer")

  ("q" nil))

(evil-leader/set-key "w" 'hydra-window/body)
(defun vsplit-last-buffer ()
  (other-window 1 nil)

(defun hsplit-last-buffer ()
  (other-window 1 nil)

(global-set-key (kbd "C-x 2") 'vsplit-last-buffer)
(global-set-key (kbd "C-x 3") 'hsplit-last-buffer)

"Show Me" – a Hydra for presenting information.

The showme hydra on C-c s is various things that pop up mini buffers for more information; kill rings, history, and that sort of thing, searching using surfraw7.

(install-pkgs '(sauron))
(defhydra hydra-showme ()
  ("s" sauron-toggle-hide-show "Sauron" :exit t)
  ("k" counsel-yank-pop "Kills" :exit t)
  ("b" ibuffer "Buffers" :exit t)
  ("m" list-marks "Marks" :exit t)
  ("c" calculator "Calculator" :exit t)
  ("g" eww "Browse" :exit t)
  ("C" display-time-world "Times" :exit t)
  ("w" wttrin "Weather" :exit t)
  ("d" calendar "Calendar" :exit t))

(evil-leader/set-key "s" 'hydra-showme/body)

Quick Zoom/Unzoom of text

The zoom hydra allows me to easily decrease and increase text size in a buffer-local fashion.

(defhydra hydra-zoom ()
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))

(evil-leader/set-key "z" 'hydra-zoom/body)

NEXT Make hydra-zoom have a max/unmax

I want to make a zoom Head that maximizes/unmaximizes a single window, but I haven't got around to that yet.

System Integrations Hydra

(install-pkgs '(gnomenm))
(require 'kv)
(require 'gnomenm)
(defhydra hydra-sysint (:columns 4 :exit t)
  "Systems Integration"
  ("c" gnomenm-connect "Connect to Wifi")
  ("v" (async-shell-command "sudo /usr/sbin/openvpn --config ~/vpn/operator.ovpn --dev tun0" "*openvpn*") "Connect to VPN")
  ("d" gnomenm-disconnect "Go offline")
  ("w" (async-shell-command "sh ~/.screenlayout/" "*arandr*") "Walking")
  ("p" (async-shell-command "sh ~/.screenlayout/" "*arandr*") "Plugged In"))

(evil-leader/set-key "i" 'hydra-sysint/body)

DIP Switches

(defun tasshin/read-write-toggle ()
  "Toggles read-only in any relevant mode: ag-mode, Dired, or
just any file at all."
  (if (equal major-mode 'ag-mode)
      ;; wgrep-ag can support ag-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
(defhydra hydra-dipswitch ()
  ("e" toggle-debug-on-error "Debug on Error")
  ("q" toggle-debug-on-quit "Debug on Quit")
  ("r" tasshin/read-write-toggle "Read/Write")
  ("w" whitespace-mode "Whitespace")
  ("l" lsp-ui-mode "LSP UI")
  ("t" bh/set-truncate-lines "Truncate")
  ("v" variable-pitch-mode "Variable Pitch"))

(evil-leader/set-key "t" 'hydra-dipswitch/body)


I'm trying to use dired instead of a graphical file manager like Dolphin.

When you have two dired buffers side by side, if you rename (R) or copy (C) in a dired buffer, with another dired buffer next to it, settings dired-dwim-target to non-nil will auto-fill the adjacent buffer in those operations.

(setq dired-dwim-target t)

Rebind RET from dired-advertised-find-file to dired-find-alternate-file so that we don't have dired buffer bloat.

(define-key dired-mode-map (kbd "RET") 'dired-find-alternate-file)

Rebind ^ to use find-alternate-file to go up a directory, again to prevent dired buffer bloat.

(define-key dired-mode-map (kbd "^") (lambda () (interactive) (find-alternate-file "..")))

Emacs Appearance

I choose to hide the tool bar chrome by default because I don't feel like they're very useful. I also disable scrollbars and menu bars; the modeline contains the buffer's progress, and I don't actually use the scrollbar to navigate. This leaves a tiny bit more room for the fringe and the buffers, which I consider a win.

(menu-bar-mode 0)
(when (functionp 'tool-bar-mode) (tool-bar-mode 0))
(scroll-bar-mode 0)
(column-number-mode -1)
(line-number-mode -1)
(setq x-stretch-cursor t)

I don't disable visual-line-mode any more and am using auto-fill-mode in text-mode buffers to make them legible. The way I figure it, in prog-mode I should be keeping my code concise enough to not need a wrap, and if it does I should be thinking better about it.

I wrap somewhat arbitrarily at 100 columns; 80 is too wide for vertical-splits and is too narrow to be useful. 100 provides a good, legible length and is not too narrow.

(setq-default fill-column 100)
(add-hook 'text-mode-hook 'auto-fill-mode)
(diminish 'auto-fill-function "F")

I have my own color theme called "fireside" which used to be a red and white on black theme, but has slowly morphed in to a low-contrast grayscale theme which I waffle on quite a bit. Right now, I'm actually using Alect Black.

(install-pkgs '(alect-themes))
(add-hook 'after-cce-hook (lambda ()
                            (when (file-exists-p custom-file)
                              (load custom-file))
                            (load-theme 'alect-black-alt)))
(set-frame-parameter (selected-frame) 'alpha '(100 100))
(add-to-list 'default-frame-alist '(alpha 100 100))

We put some properties to disable warning about certain obvious features, namely narrowing, which I use when refactoring code.

(add-hook 'after-cce-hook (lambda ()
                            (put 'narrow-to-page 'disabled nil)
                            (put 'narrow-to-region 'disabled nil)))

Right now, I am using Input Mono for my code, with a fallback set for Deja Vu Sans if Input isn't installed. I find Input to be a nice font, easy on the eyes and scales up and down well. In terms of scaling, I have my font set for text-mode things to be derived from Input Sans instead of Input Mono, which I make a bit larger than the normal, because it doesn't quite feel as heavy, especially in the whitespace.

Furthermore, I do some stupid shit with xrandr output to detect whether I am on my work machine, and to scale up the font in my Emacs appropriately.

(add-hook 'prog-mode-hook (lambda () (variable-pitch-mode -1)))
(add-hook 'text-mode-hook (lambda () (variable-pitch-mode 1)))

(defun cce/set-font-scale (size)
  (interactive "nWhat font size do you want? ")
  (set-face-attribute 'mode-line nil :inherit 'default :height (+ 10 size))
  (eval-after-load "org"
    (set-face-attribute 'org-block nil :inherit 'fixed-pitch))
  (eval-after-load "linum"
    (lambda () (set-face-attribute 'linum nil :inherit 'default :height size)))
  (set-face-attribute 'variable-pitch nil :family "Input Sans Regular" :height (+ 10 size))
   ((find-font (font-spec :family "Vulf Mono"))
      (set-face-attribute 'default nil :family "Vulf Mono" :height size)
      (set-face-attribute 'fixed-pitch nil :family "Vulf Mono" :inherit 'default)
      (set-face-attribute 'variable-pitch nil :slant 'oblique :family "Vulf Mono" :height (+ 10 size))))
   ((find-font (font-spec :family "Input Mono"))
      (set-face-attribute 'default nil :family "Input Mono" :height size)
      (set-face-attribute 'fixed-pitch nil :family "Input Mono" :inherit 'default)))
   ((find-font (font-spec :family "DejaVu Sans Mono"))
      (set-face-attribute 'default nil :family "DejaVu Sans Mono" :weight 'light :height size)
      (set-face-attribute 'fixed-pitch nil :family "DejaVu Sans Mono" :inherit 'default)))))

(defun cce/external-display-connected ()
  (let ((xrandr-buffer (get-buffer-create " *xrandr*")))
    (shell-command "xrandr | grep ^DP | grep '\sconnected'" xrandr-buffer)
    (not (string-blank-p
          (with-current-buffer xrandr-buffer

(add-hook 'after-cce-hook #'cce/refresh-display-scale)
(defun cce/refresh-display-scale ()
  (cond ((cce/external-display-connected) (cce/set-font-scale 175))
        ((equal (system-name) "work") (cce/set-font-scale 175))
        ((equal (system-name) "beebs") (cce/set-font-scale 125))
        ((equal (system-name) "tres-ebow") (cce/set-font-scale 125))
        ((equal (system-name) "penguin") (cce/set-font-scale 125))
        ((equal (system-name) "pocket") (cce/set-font-scale 175))
        (t (cce/set-font-scale 105))))

I explicitely disable some common modes that I don't think should always be enabled. Prose has no use for line numbers. Whitespace mode should only turn on for certain buffers. I do this explicitely because it seems like Emacs turns some things on by default.

(global-linum-mode 0)
(global-whitespace-mode 0)
(global-hl-line-mode 0)
(hl-line-mode 0)
(add-hook 'before-save-hook 'delete-trailing-whitespace)

Enable hl-line-mode for certain modes, primarly ones where I am doing read-only actions such as moving through Gnus folders or Messages. Interestingly, I also like having it turned on in Eshell and ERC modes because I find that these are sorts of buffers which I do a lot of reading in, and being able to move along logfile and keep track of where I am like that is quite nice.

(defun rrix/enable-hl-line ()
       (hl-line-mode 1))

(mapc (function (lambda (mode)
                 (message (symbol-name mode))
                 (add-hook mode 'rrix/enable-hl-line)))

I'm starting to turn off transient-mark mode8 and move towards a model of actually treating the Mark as more than just a selection tool, and towards treating it as a navigation tool. In light of that, I'm going to start disabling transient-mark-mode and only relying on visible-mark-mode for showing the mark, which alleviates most of the issues you see with disabling transient-mark-mode

(install-pkgs '(visible-mark))
(require 'visible-mark)
(defun rrix/disable-transient-mark ()
  (transient-mark-mode -1)
(add-hook 'text-mode-hook 'rrix/disable-transient-mark)
(add-hook 'prog-mode-hook 'rrix/disable-transient-mark)

(setq visible-mark-max 1)
(setq visible-mark-faces '(visible-mark-active))

(set-face-attribute 'visible-mark-active nil :background nil)
(set-face-attribute 'visible-mark-active nil :foreground nil)
(set-face-attribute 'visible-mark-active nil :inherit 'cursor)

mark-tools provides a buffer that allows you to view the global and local mark rings and navigate to them with RET. This is used in hydra-showme.

(install-pkgs '(mark-tools))

Ivy and Counsel

Ivy is a completion/selection framework similar to helm, but probablymaybe a bit more performant. It is a lightweight core, with a bunch of nice addons built in to the counsel and swiper packages. My system will have all of them installed, and then bound to useful key bindings.

(install-pkgs '(ivy
(ivy-mode 1)
(diminish 'ivy-mode)
(setq magit-completing-read-function 'ivy-completing-read)
(setq projectile-completion-system 'ivy)
(setq ivy-height 15)
(global-set-key (kbd "M-u") 'ivy-resume)

(global-set-key (kbd "C-h f") 'counsel-describe-function)
(global-set-key (kbd "C-h v") 'counsel-describe-variable)
(global-set-key (kbd "C-h w") 'counsel-descbinds)

(defhydra hydra-help (:columns 4)
  ("v" counsel-describe-variable "Desc Variable")
  ("w" counsel-descbinds "Desc Bindings")
  ("s" describe-syntax "Desc Syntax")
  ("P" describe-package "Desc Package")
  ("o" describe-symbol "Desc Symbols")
  ("m" describe-mode "Desc Mode")
  ("k" describe-key "Desc Keys")
  ("f" counsel-describe-function "Desc Functions")
  ("d" apropos-documentation "Apropos Docs")
  ("a" apropos-command "Apropos Commands")
  ("j" cce/man-at-point "Man for symbol at point.")
  ("r" info-emacs-manual "Emacs Info Pages")
  ("p" finder-by-keyword "Find Package by Keyword")
  ("l" view-lossage "Recent Commands")
  ("i" info "Info Index")
  ("e" view-echo-area-messages "*Messages*")
  ("b" describe-bindings "List Bindings")
  ("S" info-lookup-symbol "Lookup Symbol in Info")
  ("q" nil))
(evil-leader/set-key "h" 'hydra-help/body)

(global-set-key (kbd "C-x C-f") 'counsel-find-file)

(global-set-key (kbd "C-x b") 'ivy-switch-buffer)
(evil-leader/set-key "b" 'ivy-switch-buffer)

(setq counsel-find-file-at-point t)
(setq counsel-find-file-ignore-regexp
       ;; file names beginning with # or .
       ;; file names ending with # or ~

(with-eval-after-load 'org
  (define-key org-mode-map (kbd "C-c C-q") #'counsel-org-tag))
(with-eval-after-load 'org-agenda
  (define-key org-agenda-mode-map (kbd "C-c C-q") #'counsel-org-tag-agenda))
(define-key evil-normal-state-map (kbd "/") 'swiper)
(define-key evil-normal-state-map (kbd "?") 'swiper)
(evil-leader/set-key "SPC" 'counsel-M-x)
(global-set-key (kbd "M-x") 'counsel-M-x)
(defun ivy--matcher-desc () ; used in `hydra-ivy'
  (if (eq ivy--regex-function

(defhydra hydra-ivy (:hint nil :color pink)
^^_,_        _f_ollow      occ_u_r      _g_o          ^^_c_alling %-7s(if ivy-calling \"on\" \"off\")      _w_/_s_/_a_: %-14s(ivy-action-name)
_p_/_n_      _d_one        ^^           _i_nsert      ^^_m_atcher %-7s(ivy--matcher-desc)^^^^^^^^^^^^      _C_ase-fold: %-10`ivy-case-fold-search
^^_._        _D_o it!      ^^           _q_uit        _<_/_>_ shrink/grow^^^^^^^^^^^^^^^^^^^^^^^^^^^^      _t_runcate: %-11`truncate-lines
  ;; arrows
  ("," ivy-beginning-of-buffer) ; default h
  ("p" ivy-previous-line) ; default j
  ("n" ivy-next-line) ; default k
  ("." ivy-end-of-buffer) ; default l
  ;; quit ivy
  ("q" keyboard-escape-quit :exit t) ; default o
  ("C-g" keyboard-escape-quit :exit t)
  ;; quit hydra
  ("i" nil)
  ("C-o" nil)
  ;; actions
  ("f" ivy-alt-done :exit nil)
  ;; Exchange the default bindings for C-j and C-m
  ("C-m" ivy-alt-done :exit nil) ; RET, default C-j
  ("C-j" ivy-done :exit t) ; default C-m
  ("d" ivy-done :exit t)
  ("g" ivy-call)
  ("D" ivy-immediate-done :exit t)
  ("c" ivy-toggle-calling)
  ("m" ivy-toggle-fuzzy)
  (">" ivy-minibuffer-grow)
  ("<" ivy-minibuffer-shrink)
  ("w" ivy-prev-action)
  ("s" ivy-next-action)
  ("a" ivy-read-action)
  ("t" (setq truncate-lines (not truncate-lines)))
  ("C" ivy-toggle-case-fold)
  ("u" ivy-occur :exit t))

(define-key ivy-minibuffer-map  (kbd "C-m")
  'ivy-alt-done)                                        ; RET, default C-j
(define-key ivy-minibuffer-map (kbd "C-j")
  ' ivy-done)                        ; default C-m
(define-key ivy-minibuffer-map (kbd "C-S-m")
(define-key ivy-minibuffer-map (kbd "C-t") 'ivy-toggle-fuzzy)
(define-key ivy-minibuffer-map (kbd "C-o") 'hydra-ivy/body)

Ivy View is a new thing that lets you save and restore window views, I'm going to configure it and see if I use it.

(setq ivy-use-virtual-buffers t)

Text Manipulation

My rules of choice: 4 space tabstops, no tabs.

(setq-default indent-tabs-mode nil
              tab-width 4)

expand-region is a neat little guy that lets you grow your region just by calling it. Pretty self explanatory, but it's a great tool to have in your belt. I bind it over the mostly-useless M-o.

(install-pkgs '(expand-region))
(global-set-key (kbd "M-o") 'er/expand-region)

Undo Tree

Undo Tree is a neat visualization and navigation tool for walking through a tree history.

(install-pkgs '(undo-tree))
(require 'undo-tree)
(global-undo-tree-mode 1)
(diminish 'undo-tree-mode "")

Pasting and Sharing Code

scpaste9 is a neat package that takes a region or buffer, renders it to HTML, and uses scp to push it somewhere. I have it wired up to Hydra to paste to either work shared HTML space or to my personal site.

(install-pkgs '(scpaste))
(defhydra hydra-scpaste (global-map "C-c j")
  ("p" (let ((scpaste-http-destination "")
             (scpaste-scp-destination ""))
         (call-interactively 'scpaste-region)))
  ("w" (let ((scpaste-http-destination scpaste-work-http)
             (scpaste-scp-destination scpaste-work-scp))
         (call-interactively 'scpaste-region))))

Buffer Navigation

Moving around with Avy

Avy is the framework that powers ace-jump but it's a hell of a lot more now; it's a generic framework for moving about, and is pretty incredibly powerful.

(install-pkgs '(avy avy-zap ace-link))
(defhydra hydra-avy (global-map "M-i" :color teal)
  ("c" avy-goto-char "char")
  ("w" avy-goto-word-0 "word")
  ("l" avy-goto-line "line")
  ("p" avy-pop-mark "pop")
  ("o" counsel-ace-link "url"))

(evil-leader/set-key "a" 'hydra-avy/body)

Focusing, Dimming and Highlighting

Focusing on a bit of code or text comes in two varieties for me; one is the highlighting of a symbol, either manually or with auto-highlight-symbol. The other is the opposite, dimming everything but exactly what I'm trying to grok right now.

This little fellow, auto-highlight-symbol, tags all occurrences of the symbol under the cursor.

(install-pkgs '(highlight-symbol auto-highlight-symbol))
(require 'highlight-symbol)

Focus Mode10 provides a way to limit what you're focusing on to a function or sentence at a time. This makes it easy for me to read

(install-pkgs '(focus))
(eval-after-load 'focus
  (lambda ()
    (define-key focus-mode-map (kbd "j") #'focus-next-thing)
    (define-key focus-mode-map (kbd "k") #'focus-prev-thing)
    (evil-define-key 'normal focus-mode-map (kbd "k") #'focus-prev-thing)
    (evil-define-key 'normal focus-mode-map (kbd "j") #'focus-next-thing)))

And we define a hydra to make them accessible, via C-c h.

(defhydra hydra-highlight-symbol (global-map "C-c h")
Highlight -----------> Dim
_h_: Highlight at Point _f_: focus-mode
_j_: Previous Symbol    _r_: focus-ro
_k_: Next Symbol
_d_: Clear All Symbols
_a_: Toggle AHS
  ("h" highlight-symbol-at-point)
  ("j" highlight-symbol-prev)
  ("k" highlight-symbol-next)
  ("d" highlight-symbol-remove-all)
  ("a" auto-highlight-symbol-mode)
  ("f" focus-mode)
  ("r" focus-read-only-mode))

This function is from Tasshin Fogleman's .emacs.d and is an easy keybinding to switch between narrow and wide views of a buffer, iteratively between region, source block, subtree, and function.

(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
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
        ((and (boundp 'org-src-mode) org-src-mode (not p))
         (narrow-to-region (region-beginning) (region-end)))
        ((derived-mode-p 'org-mode)
         (cond ((ignore-errors (org-edit-src-code))
               (t (org-narrow-to-subtree))))
        ((derived-mode-p 'prog-mode) (narrow-to-defun))
        (t (error "Please select a region to narrow to"))))

(evil-leader/set-key (kbd "n") #'narrow-or-widen-dwim)


Author: Ryan Rix

Created: 2019-05-07 Tue 11:13

Validate XHTML 1.0