summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAlan Pearce2019-06-16 23:19:21 +0200
committerAlan Pearce2019-06-16 23:21:50 +0200
commit3d5c13ffae1f256952a1d6984ce287e8b707985e (patch)
treec40cded9e9a1559ae8e2a3f4ff4f3dfcfcb98ce6
parent27da3161affcf5066cfbb83d2a569f50c5fb8cd1 (diff)
downloadnixfiles-3d5c13ffae1f256952a1d6984ce287e8b707985e.tar.lz
nixfiles-3d5c13ffae1f256952a1d6984ce287e8b707985e.tar.zst
nixfiles-3d5c13ffae1f256952a1d6984ce287e8b707985e.zip
Emacs: rework config
I missed some things, but time will tell if I actually need them
-rw-r--r--emacs/.emacs.d/init.el3
-rw-r--r--emacs/.emacs.d/main.el2513
2 files changed, 332 insertions, 2184 deletions
diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el
index 27ab85cc..48fc30a3 100644
--- a/emacs/.emacs.d/init.el
+++ b/emacs/.emacs.d/init.el
@@ -21,5 +21,6 @@
 (when (featurep 'auto-compile)
   (auto-compile-on-load-mode))
 
-(load-file (expand-file-name "main.el" user-emacs-directory))
+(let ((gc-cons-threshold most-positive-fixnum))
+  (load (expand-file-name "main.el" user-emacs-directory) :nomessage t))
 ;;; init ends here
diff --git a/emacs/.emacs.d/main.el b/emacs/.emacs.d/main.el
index bbfa3164..444b13e2 100644
--- a/emacs/.emacs.d/main.el
+++ b/emacs/.emacs.d/main.el
@@ -1,261 +1,53 @@
-;;; emacs-config --- Summary
-;; #+TITLE: Emacs Configuration for Alan Pearce
-;; #+OPTIONS: ^:nil
-;; #+PROPERTY: results silent
-;; #+PROPERTY: eval no-export
-;; #+PROPERTY: header-args :comments link
-;;; Commentary:
-;;; This is my Emacs configuration.
-;;; Header:
-;; This is a living document, detailing my Emacs configuration using org-mode
-;;; Code:
-;;;; Basics
-;;;;; Startup
-;; Open Emacs with just a plain window.  No graphics or messages, please!
-(setq inhibit-startup-screen t)
-(setq gc-cons-threshold 100000000)
-(add-hook 'after-init-hook
-          (lambda ()
-            (setq gc-cons-threshold 800000)))
-(remove-hook 'find-file-hooks #'vc-refresh-state)
-
-;; Are we running on Windows via the WSL?
-
-(when (file-exists-p "/proc/sys/kernel/osrelease")
-  (with-temp-buffer
-    (insert-file-contents-literally "/proc/sys/kernel/osrelease")
-    (decode-coding-region (point-min) (point-max) 'utf-8 t)
-    (when (string-match "Microsoft$" (buffer-string))
-      (setq system-type 'gnu/linux/windows))))
-
-;;;;; Compatibility
-
-(if (version< emacs-version "25.0")
-    (defmacro with-eval-after-load (file &rest body)
-      `(eval-after-load ,file (lambda () ,@body))))
-
-;;;;; Scratch buffers
-;; I usually use scratch buffers for any sort of text.  If I need a
-;; programming mode in one, then I’ll just call it manually.  I also like
-;; the buffer to be empty.
-(setq initial-scratch-message ""
-      initial-major-mode 'text-mode)
-
-;;;;; Personal Information
-(setq user-full-name "Alan Pearce")
-;; #+end_src
-
-;;;; Packaging
-
-;;;;; Use-package
-
-(autoload 'package-installed-p "package.el")
-(eval-and-compile
-  (require 'seq)
-  (defun is-nix-emacs ()
-    (and invocation-directory
-         (string-match "^/nix/store" invocation-directory)
-         (not (null (seq-some (lambda (dir) (string-match "^/nix/store" dir)) load-path)))))
-  (defvar nix-emacs (is-nix-emacs))
-
-  (setq tls-checktrust t
-        gnutls-verify-error t
-        package-menu-async t
-        package-user-dir (concat "~/.emacs.d/packages/" emacs-version "/elpa")
-        package-menu-hide-low-priority t
-        package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
-                           ("melpa-stable" . "https://stable.melpa.org/packages/")
-                           ("melpa" . "https://melpa.org/packages/")))
-  (unless nix-emacs
-    (setq package-pinned-packages '(("use-package" . melpa-stable)
-                                    ("bind-key" . melpa-stable))
-          package-archive-priorities '(("melpa" . 10)
-                                       ("gnu" . 10)
-                                       ("melpa-stable" . 5)
-                                       ("marmalade" . 0))))
-  (when (eq system-type 'darwin)
-    (with-eval-after-load "gnutls"
-      (add-to-list 'gnutls-trustfiles "/etc/ssl/cert.pem")))
-  (unless nix-emacs
-    (unless (package-installed-p 'use-package)
-      (package-refresh-contents)
-      (package-install 'use-package))))
-(eval-when-compile (require 'use-package))
-(unless (featurep 'use-package)
-  (require 'bind-key)
-  (use-package use-package
-    :commands (use-package-autoload-keymap)
-    :defer 5))
-(setq use-package-always-ensure (not nix-emacs)
-      use-package-always-demand (daemonp)
+(setq inhibit-startup-screen t
+      initial-scratch-message ""
+      initial-major-mode 'text-mode
       package-enable-at-startup nil)
 
-;;;;; Helpers
-
-;;;;;; Hook Helpers
-
-;; An improvement over add-hook with lamda functions that allows
-;; modification and removal, without the boilerplate of an extra function
-;; definition.
+(eval-when-compile (require 'use-package))
+(setq use-package-always-demand (daemonp))
 
+;;; Helpers
 (eval-and-compile
   (require 'subr-x)
   (use-package hook-helpers))
 
-;;;; Customize
-;; I don’t really like using customize for normal configuration.
-;; Instead, I use it for things that get saved automatically.  That’s why
-;; I use a different file, which is ignored by the VCS.  It also means
-;; that it’s not important whether the file exists or not, which is why I
-;; pass =:noerror= to =load=
+;;; Customize
 
 (setq custom-file "~/.emacs.d/custom.el")
 (load custom-file :noerror :nomessage)
 
-;;;; Styles
+(use-package crux
+  :custom ((crux-reopen-as-root-mode t)))
+
+;;; Styles
 
 ;; I prefer an always-visible cursor.  Feels less distracting.
-(when (fboundp #'blink-cursor-mode)
-  (blink-cursor-mode -1))
+(customize-set-variable 'blink-cursor-mode nil)
 
 ;; Disable all the bars, unless on OSX, in which case, keep the menu bar.
 
-(when (and menu-bar-mode (not (eq window-system 'ns)))
-  (menu-bar-mode -1))
-(with-eval-after-load 'scroll-bar
-  (set-scroll-bar-mode nil))
-(with-eval-after-load 'tooltip
-  (tooltip-mode -1))
-(with-eval-after-load 'tool-bar
-  (tool-bar-mode -1))
+(customize-set-variable 'menu-bar-mode nil)
+(customize-set-variable 'scroll-bar-mode nil)
+(customize-set-variable 'tool-bar-mode nil)
 (set-fringe-mode '(4 . 4))
 
 ;; Ring the bell sometimes, but not so often
 (setq ring-bell-function
       (lambda ()
         (unless (memq this-command
-                      '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit undo-tree-undo))
+                      '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit minibuffer-keyboard-quit undo-tree-undo))
           (ding))))
 
-;;;;; Colours
-
-(load-theme 'spacemacs-light t)
-
-;; Highlighting quasi-quoted expressions in lisps is quite useful, but I
-;; don't need it all the time.  I'll keep it around for a while so that I
-;; can enable it if needed.
-(use-package highlight-stages)
+(when (or (daemonp)
+           window-system)
+  (load-theme 'eink t))
 
 (global-hl-line-mode +1)
 
-(define-hook-helper first-frame ()
-  (let ((line (face-attribute 'mode-line :underline)))
-    (set-face-attribute 'mode-line          nil :overline   line)
-    (set-face-attribute 'mode-line-inactive nil :overline   line)
-    (set-face-attribute 'mode-line-inactive nil :underline  line)
-    (set-face-attribute 'mode-line          nil :box        nil)
-    (set-face-attribute 'mode-line-inactive nil :box        nil)
-    (set-face-attribute 'mode-line-inactive nil :background (face-attribute 'hl-line :background))))
-
-;;;;; Fonts
-
-;; When possible, set up fonts.  I don’t have any settings here for X11,
-;; because I manage those in my [[file:~/projects/dotfiles/tag-xresources/xresources/main][XResources file]].
-(when (or (display-graphic-p)
-          (daemonp))
-
-  (setq-default line-spacing 0.2)
-
-  (defun use-variable-fonts ()
-    (interactive)
-    (variable-pitch-mode)
-    (setq cursor-type '(bar . 1)))
-
-  (defun use-fixed-fonts ()
-    (interactive)
-    (variable-pitch-mode -1)
-    (setq cursor-type 'box))
-
-  (defun ap/set-fonts (mono-face mono-font-size variable-face variable-font-size antialias &optional new-line-spacing)
-    (if (boundp 'ns-antialias-text)
-        (setq ns-antialias-text antialias))
-    (if (boundp 'new-line-spacing)
-      (setq line-spacing new-line-spacing))
-    (when mono-face
-      (let ((default-font (font-spec :family mono-face :size  mono-font-size)))
-        (add-to-list 'default-frame-alist `(font . ,(format "%s %s" mono-face mono-font-size)))
-        (set-face-font 'fixed-pitch default-font)
-        (set-frame-font default-font t t)))
-    (when variable-face
-      (set-face-font 'variable-pitch (font-spec :name variable-face :size variable-font-size))))
-
-  (defun ap/set-fonts-according-to-system ()
-    (interactive)
-    (cond
-     ((eq window-system 'w32)
-      (ap/set-fonts "Liberation Mono" 11 "Segoe UI" 11 t))
-     ((or (eq window-system 'mac)
-          (eq window-system 'ns))
-      (let ((displays (string-to-number (shell-command-to-string "system_profiler SPDisplaysDataType | grep \"Online: Yes\" | wc -l"))))
-        (ap/set-fonts "SF Mono" 12 "Helvetica Neue" 12 t 0.1)))
-     ((and (eq window-system 'x)
-           (eq system-type 'gnu/linux/windows))
-      (ap/set-fonts "Noto Mono" 12 "Sans" 12 nil)))))
-
-(add-hook 'first-frame-hook #'ap/set-fonts-according-to-system)
-
-;; Reduce font decoration.  I’m trying to see whether this helps me focus
-;; on the right things.
-(setq font-lock-maximum-decoration '((dired-mode . 1)
-                                     (t . 1)))
-
-;; Make symbols prettier.  Turns out, in many cases, this is already
-;; configured, just not enabled.  If using the mac-port version of Emacs,
-;; it has it's own, more extensive version.
-
-(if (eq window-system 'mac)
-    (if (fboundp 'mac-auto-operator-composition-mode)
-        (mac-auto-operator-composition-mode +1))
-    (global-prettify-symbols-mode +1))
-
-;;;;; Page Breaks
-
-;; By default, Emacs displays page breaks as ^L.  Lines look much nicer.
-;; On Windows, Emacs incorrectly detects that U+2500 (Box Drawings Light
-;; Horizontal) can only be displayed with a different font, which is not
-;; correct, at least for Liberation Mono.
-
-(use-package page-break-lines
-  :defer 5
-  :config (progn
-            (global-page-break-lines-mode)
-            (unless (eq (char-displayable-p ?─) (char-displayable-p ?a))
-              (set-fontset-font "fontset-default"
-                                (cons page-break-lines-char page-break-lines-char)
-                                (face-attribute 'default :family)))))
-(require 'f)
-(setq frame-title-format (list "Emacs"))
-
-;;;;; Chrome
-
-(setq-default cursor-in-non-selected-windows nil)
-
-(add-to-list 'default-frame-alist '(border-width . 0))
-(add-to-list 'default-frame-alist '(internal-border-width . 0))
-(when (eq system-type 'darwin)
-  (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
-  (add-to-list 'default-frame-alist '(ns-appearance . light)))
-(when (or (eq window-system 'x)
-          (eq window-system 'mac))
-  (setq window-divider-default-bottom-width 1
-        window-divider-default-right-width 1
-        window-divider-default-places t)
-  (window-divider-mode +1))
-
+;;; Chrome
 (use-package minions
-  :config (progn
-            (setq minions-mode-line-lighter "#")
-            (minions-mode +1)))
+  :custom ((minions-mode-line-lighter "#")
+           (minions-mode t)))
 
 (use-package moody
   :config (progn
@@ -263,48 +55,59 @@
             (moody-replace-mode-line-buffer-identification)
             (moody-replace-vc-mode)))
 
-;;;; Environment Variables
-
-;; MacOS doesn’t have a reasonable way to set environment variables and
-;; read them automatically any more.  So, let’s use the
-;; [[https://github.com/purcell/exec-path-from-shell][exec-path-from-shell]] package to set up ~exec-path~ and similar
-;; variables from whatever my shell configuration is.
+(setq frame-title-format (list "Emacs"))
 
-;; On Windows, I like to run Emacs from the system tray menu of VcXsrv.
-;; It starts up without an environment in this case as well.
+;;; Windows
 
-(use-package exec-path-from-shell
-  :if (or (eq system-type 'darwin)
-          (eq system-type 'gnu/linux/windows)
-          (and (eq system-type 'gnu/linux)
-               (daemonp)))
-  :config (progn
-            (setq exec-path-from-shell-arguments '("-l"))
-            (exec-path-from-shell-initialize)))
+(use-package eyebrowse
+  :after (evil)
+  :custom ((eyebrowse-new-workspace #'counsel-projectile-switch-project)
+           (eyebrowse-mode t))
+  :general (evil-window-map
+            "0" #'eyebrowse-switch-to-window-config-0
+            "1" #'eyebrowse-switch-to-window-config-1
+            "2" #'eyebrowse-switch-to-window-config-2
+            "3" #'eyebrowse-switch-to-window-config-3
+            "4" #'eyebrowse-switch-to-window-config-4
+            "5" #'eyebrowse-switch-to-window-config-5
+            "6" #'eyebrowse-switch-to-window-config-6
+            "7" #'eyebrowse-switch-to-window-config-7
+            "8" #'eyebrowse-switch-to-window-config-8
+            "9" #'eyebrowse-switch-to-window-config-9)
+  :ghook ('evil-after-load-hook #'eyebrowse-setup-evil-keys))
 
-(with-eval-after-load 'browse-url
-  (when (executable-find "xdg-open")
-    (setq browse-url-browser-function #'browse-url-xdg-open)))
+(use-package winner
+  :custom ((winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")))
+  :general (:keymap evil-window-map
+                    "u" #'winner-undo
+                    "r" #'winner-redo
+                    "C-r" #'winner-redo))
+;;; Dates & Times
 
-;;;;; NixOS sandboxes
+(custom-set-variables
+ '(calendar-week-start-day 1)
+ '(calendar-date-style 'iso))
 
-;; I'm currently exploring using nix to create sandboxes for
-;; development.  This package allows using tools from inside sandboxes,
-;; and some convenience commands for building packages and launching shells.
+(defun insert-date (prefix)
+  "Insert the current date.
+With PREFIX, use British format.
+With two prefix arguments, write out the day and month name."
+  (interactive "P")
+  (let ((format (cond
+                 ((not prefix) "%Y-%m-%d")
+                 ((equal prefix '(4)) "%d/%m/%Y")
+                 ((equal prefix '(16)) "%A, %d %B %Y"))))
+    (insert (format-time-string format))))
 
-(use-package nix-sandbox
-  :defines (flycheck-command-wrapper-function
-            flycheck-executable-find)
-  :config (progn
-            (with-eval-after-load 'flycheck
-              (setq flycheck-command-wrapper-function
-                    (lambda (cmd)
-                      (apply 'nix-shell-command (nix-current-sandbox)
-                             (list (mapconcat 'shell-quote-argument cmd " "))))
-                    flycheck-executable-find
-                    (lambda (cmd) (nix-executable-find (nix-current-sandbox) cmd))))))
+(defun insert-datetime (prefix)
+  "Insert current date and time.  With PREFIX, use ISO8601 format."
+  (interactive "P")
+  (let ((format (cond
+                 ((not prefix) "%Y-%m-%d %H:%M:%S")
+                 ((equal prefix '(4)) "%Y-%m-%dT%H:%M:%SZ"))))
+    (insert (format-time-string format))))
 
-;;;; Keybindings
+;;; Keybindings
 
 ;; I think =set-keyboard-coding-system= stops OS X from doing something
 ;; annoying to add accents.  The modifier setup is to match my
@@ -312,7 +115,6 @@
 ;; Option/alt, then Control.
 
 (when (eq system-type 'darwin)
-  (set-keyboard-coding-system nil)
   (custom-set-variables
    '(mac-option-modifier 'meta)
    '(mac-right-option-modifier 'none)
@@ -320,241 +122,120 @@
    '(mac-right-control-modifier 'left)
    '(mac-command-modifier 'super)
    '(mac-right-command-modifier 'left)
-   '(mac-function-modifier 'hyper))
-  (unbind-key "s-x"))
+   '(mac-function-modifier 'hyper)))
 
-(unbind-key "<f4>")
-(bind-key* "<f5>" #'compile)
-(bind-key* "<f6>" #'kmacro-start-macro-or-insert-counter)
-(bind-key* "<f7>" #'kmacro-end-or-call-macro)
 
-(bind-key* "<apps>" #'execute-extended-command)
+(use-package general
+  :functions (general-unbind general-define-key)
+  :config (progn
+            (when (eq system-type 'darwin)
+              (general-unbind "s-x"))))
 
-(unbind-key "C-x C-c")
+(use-package ace-link
+  :after avy
+  :config (ace-link-setup-default))
 
-(bind-key* "C-c i" #'insert-char)
-(bind-key* "M-/" #'hippie-expand)
+;; Popup keybindings following a prefix automatically.
 
-(unbind-key "s-h")
-(unbind-key "s-n")
-(unbind-key "s-p")
-(unbind-key "s-w")
+(use-package which-key
+  :custom ((which-key-mode +1))
+  :config (progn
+            (which-key-setup-side-window-right-bottom)))
 
-(bind-key* "s-x" (define-prefix-command 'super-x-map))
-(bind-key* "s-," #'switch-to-dotfiles)
-(bind-key* "C-x M-x" #'execute-extended-command)
+;;; Modeline
 
-;;;;; Crux
+(use-package ivy
+  :config (progn
+            (ivy-mode +1)))
+(use-package ivy-hydra)
 
-;; I can replace most of the simple helper/wrapper functions in my
-;; configuration with crux.el
+(use-package relative-buffers
+  :custom ((global-relative-buffers-mode t)))
 
-(use-package crux
-  :bind (("C-x 4 t" . crux-transpose-windows)
-         ("C-c e" . crux-eval-and-replace)
-         ("C-c D" . crux-delete-file-and-buffer)
-         ("C-c R" . crux-rename-file-and-buffer)))
+;; transition smex history to amx
+(let ((smex-save-file (concat user-emacs-directory "smex-items")))
+  (use-package amx
+    :custom ((amx-history-length 100))))
 
-;;;; Projects
+(use-package counsel
+  :general ("M-x" #'counsel-M-x))
 
-(defun switch-to-dotfiles ()
-  "Switch to dotfiles project."
-  (interactive)
-  (projectile-switch-project-by-name (car (split-string (shell-command-to-string "ghq list --full-path dotfiles")))))
+;;; Minibuffer
 
-;;;;; Grep
+(setq enable-recursive-minibuffers t)
+(minibuffer-depth-indicate-mode t)
 
-(use-package grep
-  :config (progn
-            (dolist (v '("node_modules"
-                         "bower_components"
-                         ".sass_cache"
-                         ".cache"
-                         ".npm"))
-              (add-to-list 'grep-find-ignored-directories v))
-            (dolist (v '("*.min.js"
-                         "*.bundle.js"
-                         "*.min.css"
-                         "*.lock"
-                         "package-lock.json"
-                         "*.log"))
-              (add-to-list 'grep-find-ignored-files v))))
-
-;;;;; The Silver Searcher
-
-(use-package ag
-  :defer 30
-  :config (progn
-            (setq ag-project-root-function #'projectile-project-root)
-            (add-to-list 'ag-arguments "--hidden")))
+;;; Evil
 
-(use-package wgrep-ag
-  :after ag)
+(use-package evil
+  :demand t
+  :init (custom-set-variables '(evil-want-integration t)
+                              '(evil-want-keybinding nil))
+  :after (undo-tree)
+  :custom ((evil-shift-width 2)
+           (evil-mode-line-format '(before . mode-line-front-space)))
+  :general
+  (:states 'motion
+           "C-;" #'evil-avy-goto-line)
+  (:states 'normal
+           ";" #'evil-ex)
+  :config (progn
+            (evil-mode +1)))
 
-;;;;; Ripgrep
+(use-package evil-collection
+  :config (evil-collection-init))
 
-;; Step over Silver Search, here comes a new challenger.
+(general-create-definer my-leader-def
+  :prefix ",")
 
-(use-package ripgrep
-  :if (executable-find "rg")
+(use-package evil-space
+  :defer 1
   :config (progn
-            (setq ripgrep-arguments '("--hidden"))))
+            (evil-space-mode)))
 
-(use-package projectile-ripgrep
-  :after (ripgrep projectile)
-  :if (executable-find "rg")
-  :config (bind-key "s r" #'projectile-ripgrep projectile-command-map))
+(use-package evil-surround
+  :custom ((global-evil-surround-mode t)))
 
-;;;;; Projectile
+(use-package evil-commentary
+  :custom ((evil-commentary-mode t)))
 
-;; Projectile is awesome for working in projects, especially VCS-backed
-;; ones.
+(use-package evil-magit
+  :after magit
+  :custom ((evil-magit-use-y-for-yank nil)))
 
-(add-to-list 'byte-compile-not-obsolete-funcs 'projectile-global-mode)
-(use-package projectile
-  :bind (("s-p" . projectile-switch-project)
-         ("C-c C-f" . projectile-find-file)
-         ("s-x s-f" . projectile-find-file)
-         ("C-x g" . projectile-vc)
-         ("C-M-g" . projectile-vc))
-  :demand t
-  :config (progn
-            (projectile-global-mode +1)
-            (add-to-list 'projectile-globally-ignored-directories ".stversions")
-            (add-to-list 'projectile-globally-ignored-directories "node_modules")
-            (add-to-list 'projectile-globally-ignored-files "package-lock.json")
-            (setq projectile-mode-line "P")
-
-            (defun yarn-install (&optional arg)
-              (interactive "P")
-              (projectile-with-default-dir (projectile-project-root)
-                (cond
-                 ((string-equal (projectile-project-type) "node-yarn")
-                  (cmd-to-echo "yarn" "install"))
-                 (t (cmd-to-echo "npm" "install")))))
-            (defalias 'npm-install #'yarn-install)
-
-            (defun yarn-add-dev (package)
-              (interactive "spackage: ")
-              (projectile-with-default-dir (projectile-project-root)
-                (cond
-                 ((string-equal (projectile-project-type) "node-yarn")
-                  (cmd-to-echo "yarn" (concat "add --dev " package)))
-                 (t (cmd-to-echo "npm" (concat "install --save-dev " package))))))
-            (defalias 'npm-save-dev #'yarn-add-dev)
-
-            (defun yarn-add (package)
-              (interactive "spackage: ")
-              (projectile-with-default-dir (projectile-project-root)
-                (cond
-                 ((string-equal (projectile-project-type) "node-yarn")
-                  (cmd-to-echo "yarn" (concat "add " package)))
-                 (t (cmd-to-echo "npm" (concat "install --save " package))))))
-            (defalias 'npm-save #'yarn-add)
-
-            (defun yarn-remove (package)
-              (interactive "spackage: ")
-              (projectile-with-default-dir (projectile-project-root)
-                (cond
-                 ((string-equal (projectile-project-type) "node-yarn")
-                  (cmd-to-echo "yarn" (concat "remove " package)))
-                 (t (cmd-to-echo "npm" (concat "remove " package))))))
-            (defalias 'npm-remove #'yarn-remove)
-
-            (defun yarn-run (cmd)
-              (interactive (list
-                            (projectile-completing-read "command: " (alist-get 'scripts (json-read-file (expand-file-name "package.json" (projectile-project-root)))))))
-              (projectile-with-default-dir (projectile-project-root)
-                (cond
-                 ((string-equal (projectile-project-type) "node-yarn")
-                  (cmd-to-echo "yarn" (concat "run " cmd)))
-                 (t (cmd-to-echo "npm" (concat "run " cmd))))))
-            (defalias 'npm-run #'yarn-run)
-
-            (defun npx-run (cmd)
-              (interactive "scommand: ")
-              (projectile-with-default-dir (projectile-project-root)
-                (cmd-to-echo "npx" cmd)))
-
-            (defun npm-version (type)
-              (interactive (list
-                            (projectile-completing-read "version: " '("major" "minor" "patch" "premajor" "preminor" "prepatch" "prerelease" "from-git"))))
-              (projectile-with-default-dir (projectile-project-root)
-                (message (shell-command-to-string (concat "npm" " version " type)))))
-
-            (defun ap/open-project (&optional arg)
-              (interactive "P")
-              (let ((project-dir (projectile-completing-read
-                                  "Open project: "
-                                  (ghq--find-projects-full-path))))
-                (projectile-switch-project-by-name
-                 project-dir arg)))
-
-            (defun git-bug (bug)
-              (interactive "sbug: ")
-              (projectile-with-default-dir (projectile-project-root)
-                (call-process-shell-command (concat "git bug " bug))))
-
-            (defun git-feature (feature)
-              (interactive "sfeature: ")
-              (projectile-with-default-dir (projectile-project-root)
-                (call-process-shell-command (concat "git feature " feature))))
-
-            (defun git-chore (chore)
-              (interactive "schore: ")
-              (projectile-with-default-dir (projectile-project-root)
-                (call-process-shell-command (concat "git chore " chore))))
-
-            (setq projectile-switch-project-action #'projectile-commander
-                  projectile-completion-system 'ivy
-                  projectile-create-missing-test-files t)
-
-            (defun ap/projectile-test-suffix (project-type)
-              (cond
-               ((member project-type '(node-yarn node-npm)) ".test")
-               (t (projectile-test-suffix project-type))))
-            (setq projectile-test-suffix-function #'ap/projectile-test-suffix)
-
-            (projectile-register-project-type 'node-yarn '("yarn.lock") :run "yarn start" :test "yarn test")
-            (projectile-register-project-type 'node '("package.json") :run "npm start" :test "npm test")))
+(use-package evil-quickscope
+  :custom ((global-evil-quickscope-mode t)))
 
-(use-package counsel-projectile
-  :after (counsel projectile ivy-hydra)
-  :config (progn
-            (counsel-projectile-mode +1)
-            (def-projectile-commander-method ?A
-              "Find rg on project."
-              (call-interactively #'counsel-projectile-rg))
-            (if (boundp 'counsel-projectile-command-map)
-                (define-key counsel-projectile-command-map (kbd "s s") #'counsel-projectile-rg))))
+(use-package evil-org
+  :commands (evil-org-set-key-theme)
+  :ghook ('org-mode-hook #'evil-org-mode)
+  :gfhook #'evil-org-set-key-theme)
 
-;;;;; vc
+(use-package evil-org-agenda
+  :ghook ('org-agenda-mode-hook #'evil-org-agenda-set-keys))
 
-;; This is nice for some things that magit doesn’t do, and for those rare
-;; occasions that I’m working with something other than git.
+;;; Projects
 
-(use-package vc
-  :defer t
-  :bind (("C-x v C" . vc-resolve-conflicts))
-  :config (progn
-            (setq vc-follow-symlinks t)
-            (setq vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)"
-                                               vc-ignore-dir-regexp
-                                               tramp-file-name-regexp))))
+(use-package projectile
+  :defines projectile-command-map
+  :custom ((projectile-mode +1)
+           (projectile-completion-system 'ivy)))
 
-;;;;; git-gutter-fringe
+(use-package counsel-projectile
+  :after (counsel projectile ivy-hydra)
+  :custom ((counsel-projectile-mode +1)))
 
-;; It’s nice to be able to see at a glance which lines of a file have
-;; changed.  This package colours the fringe.  I have it set to the right
-;; fringe so it doesn’t interfere with flycheck.
+(use-package magit
+  :custom ((global-magit-file-mode +1)
+           (magit-completing-read-function #'ivy-completing-read)))
 
 (eval-when-compile (require 'fringe-helper))
+(use-package git-gutter)
 (use-package git-gutter-fringe
-  :defer 2
   :config (progn
             (global-git-gutter-mode 1)
             ;; places the git gutter outside the margins.
-            (setq-default fringes-outside-margins t)
+            (setq-default fringes-outside-margins nil)
             ;; thin fringe bitmaps
             (fringe-helper-define 'git-gutter-fr:added '(center repeated)
               ".XXX....")
@@ -564,60 +245,70 @@
               ".XXX....")
             (setq git-gutter-fr:side 'right-fringe)))
 
-;;;;; magit
-
-;; Magit is my favourite way to use git.  I use selective staging all the
-;; time.  Make sure to set it up with a nice =completing-read-function=
-
-(use-package magit
+(use-package git-messenger
   :defer 5
-  :commands (magit-status)
-  :config (progn (setq magit-completing-read-function #'ivy-completing-read
-                       magit-popup-use-prefix-argument 'default
-                       magit-repository-directories (list (cons (file-name-as-directory (ghq--find-root)) 3))
-                       magit-display-buffer-function #'magit-display-buffer-fullcolumn-most-v1
-                       global-magit-file-mode t)
-                 (add-to-list 'magit-no-confirm 'safe-with-wip))
-  :init (add-hook 'magit-mode-hook #'magit-load-config-extensions))
+  :custom ((git-messenger:use-magit-popup t)))
 
-;;;;; git-messenger
+(use-package git-timemachine)
+
+(use-package editorconfig
+  :init (progn
+          (unless (executable-find "editorconfig")
+            (warn "Missing `editorconfig' executable.")))
+  :config (editorconfig-mode +1))
 
-;; Popup the last commit that changed the line at point.
+;;; Completion
 
-(use-package git-messenger
-  :bind* (("C-x v p" . git-messenger:popup-message))
-  :config (progn
-            (setq git-messenger:use-magit-popup t)))
+(use-package company
+  :custom ((global-company-mode +1)
+           (company-idle-delay .2)
+           (company-begin-commands '(self-insert-command))
+           (company-auto-complete #'company-explicit-action-p)
+           (company-auto-complete-chars '(?\ ?\( ?\) ?.)))
+  :general (:states 'insert
+                    "TAB" #'company-complete))
 
-;;;;; git-timemachine
+(use-package company-box
+  :custom ((company-box-enable-icon nil))
+  :ghook 'company-mode-hook)
 
-;; This package allow me to go through a file’s history with just a few
-;; keys.  It makes it very easy to figure what what exactly was in a file
-;; in the past.  I often find it useful when I remember writing something
-;; a particular way, but it changed later.
+;;; Documentation
 
-(use-package git-timemachine
-  :commands git-timemachine)
+(use-package eldoc
+  :custom ((global-eldoc-mode +1)
+           (eldoc-idle-delay 0.5)))
 
-;;;;; ghq
+(use-package eldoc-box
+  :after (eldoc eglot)
+  :custom ((eldoc-box-hover-mode +1)
+           (eldoc-box-hover-at-point-mode +1)))
 
-;; [[https://github.com/motemen/ghq][=ghq=]] clones VCS-backed projects to a common directory.  It should
-;; seem familiar to anyone who's used =go get= before.  [[https://github.com/rcoedo/emacs-ghq][=emacs-ghq=]] is a
-;; simple wrapper for it.
+(use-package ehelp)
 
-(use-package ghq
-  :if (executable-find "ghq"))
+(use-package helpful
+  :after ehelp
+  :general (ehelp-map
+            "k" #'helpful-key
+            "v" #'helpful-variable
+            "f" #'helpful-callable))
 
-;;;; Files
+;;; Files
 
-;;;;; Auto-saving
+;;;; Auto-saving
 
 ;; Auto-save everything to a temporary directory, instead of cluttering
 ;; the filesystem.  I don’t want emacs-specific lockfiles, either.
 
 (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t))
       create-lockfiles nil)
-;;;;; Backups
+
+;;;; Auto-reloading
+
+(use-package autorevert
+  :custom ((global-auto-revert-mode t)
+           (auto-revert-verbose t)))
+
+;;;; Backups
 
 ;; I like to keep my backups out of regular folders.  I tell emacs to use
 ;; a subfolder of its configuration directory for that.  Also, use the
@@ -628,6 +319,7 @@
   (setq backup-directory-alist `((".*" . ,backup-dir))
         backup-by-copying-when-linked t
         backup-by-copying-when-mismatch t))
+
 (if (eq system-type 'darwin)
     (setq delete-by-moving-to-trash t)
   (if (and (executable-find "trash") (not (fboundp #'system-move-file-to-trash)))
@@ -636,1420 +328,54 @@
                       nil 0 nil
                       file))))
 
-;;;;; autorevert
-
-(use-package autorevert
-  :init (progn
-          (global-auto-revert-mode 1)
-          (setq auto-revert-verbose t
-                auto-revert-use-notify (not (eq system-type 'darwin)))))
-
-;;;;; Encoding
-
-;; UTF-8 is usually appropriate.  Note that =prefer-coding-system= expects
-;; only a coding system, not a coding system and line ending combination.
-
-(prefer-coding-system 'utf-8)
-(setq-default buffer-file-coding-system 'utf-8-auto-unix)
-
-;;;;; Buffer-file management
-
-;; Ask if I want to create a directory when it doesn’t exist.  This is
-;; especially nice when starting new projects.
-
-(defun my-create-non-existent-directory ()
-  "Offer to create non-existent directories of found-file."
-  (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 #'my-create-non-existent-directory)
-
-;; I often want to rename or delete the file that I’m currently visiting
-;; with a buffer.
-
-(defun kill-or-delete-this-buffer-dwim (&optional arg)
-  "Kill current buffer.  With prefix ARG, delete it."
-  (interactive "P")
-  (if (equal arg '(4))
-      (crux-delete-file-and-buffer)
-    (if server-buffer-clients
-        (server-edit)
-      (let ((buf (buffer-name)))
-        (when (equal buf "*HTTP Response*")
-          (other-window 1))
-        (kill-buffer buf)))))
-
-;;;;; Whitespace
-
-;; Show bad whitespace, so that I can fix it.
-
-(defun show-trailing-whitespace-on ()
-  "Show trailing whitespace."
-  (interactive)
-  (setq-local show-trailing-whitespace t))
-(defun show-trailing-whitespace-off ()
-  "Hide trailing whitespace."
-  (interactive)
-  (setq-local show-trailing-whitespace nil))
-(add-hook 'prog-mode-hook #'show-trailing-whitespace-on)
-(add-hook 'text-mode-hook #'show-trailing-whitespace-on)
-
-;;;;; shrink-whitespace
-
-;; DWIM whitespace removal.  So I don’t need =M-SPC=, =M-\= and =C-x o=
-;; for similar things any more.
-
-(use-package shrink-whitespace
-  :bind ("M-SPC" . shrink-whitespace))
-
-;;;;; Tramp
-
-;; Tramp is awesome.  It makes SSH feel Unix-y.  The proxy setup is so
-;; that I can sudo on remote machines
-
-(use-package tramp
-  :defer 7
-  :defines tramp-ssh-controlmaster-options
-  :config (progn
-            (unless (and (getenv "SSH_AUTH_SOCK")
-                         (file-exists-p (getenv "SSH_AUTH_SOCK")))
-              (setenv "SSH_AUTH_SOCK" (format "/run/user/%s/gnupg/S.gpg-agent.ssh" (user-uid))))
-            (setq tramp-default-method "ssh"
-                  tramp-default-user-alist '(("\\`su\\(do\\)?\\'" nil "root"))
-                  tramp-backup-directory-alist backup-directory-alist
-                  tramp-completion-reread-directory-timeout 60
-                  tramp-ssh-controlmaster-options nil
-                  backup-enable-predicate (lambda (name)
-                                            (and (normal-backup-enable-predicate name)
-                                                 (not (let ((method (file-remote-p name 'method)))
-                                                        (when (stringp method)
-                                                          (member method '("su" "sudo")))))))
-                  tramp-shell-prompt-pattern "\\(?:^\\|
\\)[^]#$%>\n]*#?[]#$%>❯›] *\\(\\[\\??[0-9;]*[a-zA-Z] *\\)*")
-            (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" (concat "/" tramp-default-method ":%h:")))
-            (add-to-list 'tramp-default-proxies-alist `(,(regexp-quote (system-name)) nil nil))
-            (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil))))
-
-;;;;; ediff
-
-;; I like a horizonal diff setup, with everything in one frame.
-
-(use-package ediff
-  :defer t
-  :config (progn
-            (setq ediff-split-window-function 'split-window-horizontally
-                  ediff-window-setup-function 'ediff-setup-windows-plain)))
-
-;;;; Indentation
-
-;; Ah, a complicated topic.  One day we’ll all be using elastic
-;; tabstops.  I’ve recently switched to using two spaces, since elastic
-;; tabstops is probably never going to happen.
-
-(setq-default tab-width 2
-              indent-tabs-mode nil)
-
-;;;;; smart-tabs-mode
-
-;; Not related to [[smart-tab][=smart-tab=]], this mode indents with tabs and aligns
-;; with spaces.  Perfect!
-
-(use-package smart-tabs-mode
-  :defer 1
-  :config (progn
-            (smart-tabs-insinuate 'c 'cperl 'python)))
-
-;;;;; editorconfig
-
-(use-package editorconfig
-  :init (progn
-          (unless (executable-find "editorconfig")
-            (warn "Missing `editorconfig' executable.")))
-  :config (editorconfig-mode 1))
-
-;;;;; dtrt-indent-mode
-
-;; Sometimes people use different indentation settings.  [[https://github.com/jscheid/dtrt-indent][dtrt-indent]]
-;; guesses the correct settings for me.
-
-(use-package dtrt-indent
-  :config (progn
-            (define-hook-helper prog-mode ()
-              (unless (and (boundp editorconfig-mode)
-                           editorconfig-mode)
-                (dtrt-indent-adapt)))
-            (defadvice dtrt-indent-try-set-offset (after toggle-smart-tabs activate)
-              (smart-tabs-mode (or indent-tabs-mode -1)))))
-
-;;;; Security
-
-;;;;; password-store
-
-;; This is a frontend to the GPG-powered =pass= program.
-(use-package password-store
-  :defer 15
-  :config (progn
-            (setq password-store-password-length 16)))
-
-;;;; Buffers
-
-;;;;; Ibuffer
-;; Ibuffer is quite nice for listing all buffers.
-
-(use-package ibuffer
-  :bind (("C-x C-b" . ibuffer))
-  :config (progn
-            (setq ibuffer-saved-filter-groups
-                  (quote (("default"
-                           ("org" (mode . org-mode))
-                           ("emacs" (mode . emacs-lisp-mode))
-                           ("zsh" (filename . "/zsh"))
-                           ("server" (filename . "/su:root@server"))))))
-
-            ;; Human-readable base-2 size column
-            (define-ibuffer-column size-h
-              (:name "Size" :inline t)
-              (cond
-               ((> (buffer-size) 1024)
-                (format "%7.2fK" (/ (buffer-size) 1024.0)))
-               ((> (buffer-size) 1048576)
-                (format "%7.2fM" (/ (buffer-size) 1048576.0)))
-               (t
-                (format "%8d" (buffer-size)))))
-
-            (setq ibuffer-formats
-                  '((mark modified read-only " "
-                          (name 18 18 :left :elide)
-                          " "
-                          (size-h 9 -1 :right)
-                          " "
-                          (mode 16 16 :left :elide)
-                          " "
-                          filename-and-process)))))
-
-;;;;; Relative Buffer names
-
-(use-package relative-buffers
-  :defer 15
-  :config (progn
-            (global-relative-buffers-mode)))
-
-;;;;; Narrowing
-
-;; Enable it without prompting
-
-(put 'narrow-to-defun  'disabled nil)
-(put 'narrow-to-page   'disabled nil)
-(put 'narrow-to-region 'disabled nil)
-
-;;;; Windows
-
-;; Scrolling is tricky.  I use this setup to help me keep track of the
-;; point whilst I’m moving about.
-
-(setq scroll-conservatively 100
-      scroll-margin 1
-      scroll-preserve-screen-position t
-      mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control)))
-      split-height-threshold 80
-      split-width-threshold 160
-      frame-resize-pixelwise nil)
-(if (boundp 'ns-pop-up-frames)
-    (setq ns-pop-up-frames nil))
-
-(when (version<= "26.0" emacs-version)
-  (use-package display-line-numbers
-    :config (progn
-              (setq display-line-numbers-type 'visual)
-              (global-display-line-numbers-mode +1))))
-
-;;;;; eyebrowse
-
-;; Workspaces, a bit like dwm.  On Windows and Linux (at least the WMs
-;; I'm likely to use), super+{0-9} are taken from the OS, so use meta
-;; instead.  On macOS, super makes a lot of sense, as it's used by most
-;; programs to switch between program windows or views.
-
-(use-package eyebrowse
-  :after (evil)
-  :config (progn
-            (setq eyebrowse-new-workspace t)
-            (when (eq system-type 'darwin)
-              (bind-keys
-               ("s-0" . eyebrowse-switch-to-window-config-0)
-               ("s-1" . eyebrowse-switch-to-window-config-1)
-               ("s-2" . eyebrowse-switch-to-window-config-2)
-               ("s-3" . eyebrowse-switch-to-window-config-3)
-               ("s-4" . eyebrowse-switch-to-window-config-4)
-               ("s-5" . eyebrowse-switch-to-window-config-5)
-               ("s-6" . eyebrowse-switch-to-window-config-6)
-               ("s-7" . eyebrowse-switch-to-window-config-7)
-               ("s-8" . eyebrowse-switch-to-window-config-8)
-               ("s-9" . eyebrowse-switch-to-window-config-9)))
-            (eyebrowse-mode +1)
-            (with-eval-after-load "evil-vars"
-              (bind-keys :map evil-window-map
-                         ("0" . eyebrowse-switch-to-window-config-0)
-                         ("1" . eyebrowse-switch-to-window-config-1)
-                         ("2" . eyebrowse-switch-to-window-config-2)
-                         ("3" . eyebrowse-switch-to-window-config-3)
-                         ("4" . eyebrowse-switch-to-window-config-4)
-                         ("5" . eyebrowse-switch-to-window-config-5)
-                         ("6" . eyebrowse-switch-to-window-config-6)
-                         ("7" . eyebrowse-switch-to-window-config-7)
-                         ("8" . eyebrowse-switch-to-window-config-8)
-                         ("9" . eyebrowse-switch-to-window-config-9)))
-            (define-hook-helper evil-after-load ()
-              :name evil-eyebrowse-setup
-              (eyebrowse-setup-evil-keys))))
-
-;;;; Sessions
-
-;;;;; winner
-
-;; Undo, for window-based commands.
-
-(use-package winner
-  :config (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*"))
-  :init (progn
-          (winner-mode 1)))
-
-;;;; Blogging
-
-;; I have a [[https://alanpearce.uk][blog]] that I publish with hugo.
-
-(use-package easy-hugo
-  :config (setq easy-hugo-basedir (car (split-string (shell-command-to-string "ghq list --full-path alanpearce.uk")))
-                easy-hugo-url "https://alanpearce.uk"
-                easy-hugo-default-ext ".md"))
-
-;;;; Completion
-
-;; Make built-in completion a bit more intelligent, by adding substring
-;; and initial-based completion and ignoring case.
-
-(setq completion-styles '(basic initials partial-completion substring)
-      completion-ignore-case t
-      tab-always-indent t)
-
-;;;;; Company
-
-;; The main choices for automatic completion in Emacs are company and
-;; auto-complete-mode.  I’ve not tried auto-complete-mode as company
-;; seems to work perfectly well for me.
-
-(use-package company
-  :bind* (("C-<tab>" . company-complete))
-  :bind  (("TAB" . company-complete))
-  :init (progn
-          (setq company-backends '(company-web-html company-tide company-tern company-nxml company-css company-eclim company-semantic company-elisp
-                                                company-clang company-xcode company-cmake company-capf
-                                                company-files (company-gtags
-                                                               company-etags company-keywords) company-oddmuse)
-                company-frontends '(company-pseudo-tooltip-unless-just-one-frontend
-                                    company-preview-frontend
-                                    company-echo-metadata-frontend)
-                company-idle-delay .3
-                company-begin-commands '(self-insert-command)
-                company-auto-complete #'company-explicit-action-p
-                company-auto-complete-chars '(?\ ?\( ?\) ?.)
-                company-tooltip-align-annotations t
-                company-selection-wrap-around t)
-          (global-company-mode +1)))
-
-(use-package company-web
-  :after company)
-
-;;;;; EACL
-
-;; Auto-complete lines by grepping the project.
-
-(use-package eacl
-  :bind (("C-c <tab>" . eacl-complete-line)
-         ("C-c C-;" . eacl-complete-statement)
-         ("C-c C-\]" . eacl-complete-snippet)
-         ("C-c C-/" . eacl-complete-tag)))
-
-
-;;;; Dates & Times
-
-;;;;; Calendar
-
-;; Weeks start on Monday for me and I prefer ISO-style dates.
-(use-package calendar
+(use-package undo-tree
   :defer 1
-  :config (progn
-            (setq calendar-week-start-day 1)
-            (calendar-set-date-style 'iso)))
-
-;; Sometimes I want to insert a date or time into a buffer.
-(defun insert-date (prefix)
-  "Insert the current date.
-With PREFIX, use British format.
-With two prefix arguments, write out the day and month name."
-  (interactive "P")
-  (let ((format (cond
-                 ((not prefix) "%Y-%m-%d")
-                 ((equal prefix '(4)) "%d/%m/%Y")
-                 ((equal prefix '(16)) "%A, %d %B %Y"))))
-    (insert (format-time-string format))))
-
-(defun insert-datetime (prefix)
-  "Insert current date and time.  With PREFIX, use ISO8601 format."
-  (interactive "P")
-  (let ((format (cond
-                 ((not prefix) "%Y-%m-%d %H:%M:%S")
-                 ((equal prefix '(4)) "%Y-%m-%dT%H:%M:%SZ"))))
-    (insert (format-time-string format))))
-
-(defun yesterday-time ()
-  "Provide the date/time 24 hours before the time now in the format of `current-time'."
-  (timer-relative-time (current-time) -86400))
-
-;;;; Directories
-
-;; Dired works quite nicely, but not always in the way I want.  I don’t
-;; like having so many prompts for recursive operations.  Also, when I
-;; have two dired windows open, assume that I’m going to be
-;; copying/moving files between them.
-
-(use-package dired
-  :defer 3
-  :ensure nil
-  :config (progn
-            (bind-key "<return>" #'dired-find-file dired-mode-map)
-            (bind-key "^" (lambda () (interactive) (find-alternate-file "..")) dired-mode-map)
-            (setq dired-dwim-target t
-                  dired-recursive-copies 'top
-                  dired-recursive-deletes (if delete-by-moving-to-trash
-                                              'always
-                                              'top)
-                  dired-listing-switches "-alh")
-            (when (and (eq system-type 'darwin) (executable-find "gls"))
-              (setq insert-directory-program (executable-find "gls")))
-            (put 'dired-find-alternate-file 'disabled nil)))
-
-;; Don’t show uninteresting files in dired listings.
-
-(defun turn-on-dired-omit-mode ()
-  "Enable dired-omit mode."
-  (interactive)
-  (dired-omit-mode 1))
-
-(use-package dired-x
-  :commands (dired-omit-mode
-             dired-expunge)
-  :ensure nil
-  :config (progn
-            (setq dired-omit-files "#\\|\\.$"
-                  dired-omit-verbose nil
-                  dired-find-subdir t
-                  dired-bind-jump nil))
-  :init (progn
-          (add-hook 'dired-mode-hook #'turn-on-dired-omit-mode)))
-
-;; Expand subfolders like a tree inside the parent
-
-(with-eval-after-load 'dired
-  (use-package dired-subtree
-    :functions (dired-subtree--get-ov
-                dired-subtree-maybe-up)
-    :init (progn
-            (setq dired-subtree-use-backgrounds nil)
-            (defun dired-subtree-maybe-up ()
-              "Jump up one subtree or directory"
-              (interactive)
-              (let ((ov (dired-subtree--get-ov)))
-                (if ov
-                    (progn (goto-char (overlay-start ov))
-                           (dired-previous-line 1))
-                  (dired-up-directory))))
-            (bind-key "^" #'dired-subtree-maybe-up dired-mode-map)
-            (bind-key "i" #'dired-subtree-toggle dired-mode-map))))
-
-;;;;; Disk usage
-
-;; Combine dired and du (disk usage).
-
-(use-package dired-du
-  :after dired
-  :config (progn
-            (setq dired-du-size-format t)))
-
-;;;; Documentation
-
-;;;;; ehelp
-
-;; ehelp is a less well-known package that’s part of Emacs and slightly
-;; improves the normal help commands, mostly by making quitting them easier.
-
-(use-package ehelp
-  :bind-keymap ("C-h" . ehelp-map))
-
-;;;;; helpful
-
-(use-package helpful
-  :after ehelp
-  :bind (:map ehelp-map
-              ("k" . helpful-key)
-              ("v" . helpful-variable)
-              ("f" . helpful-callable)))
-
-;;;;; discover-my-major
-
-;; A nicer way to browse keybindings for major modes.
-
-(use-package discover-my-major
-  :bind (("<f1>" . discover-my-major)
-         ("C-c C-m" . discover-my-major)))
-
-;;;;; which-key
-
-;; Popup keybindings following a prefix automatically.
-
-(use-package which-key
-  :config (progn
-            (which-key-mode 1)
-            (which-key-setup-side-window-right-bottom)))
-
-;;;;; eldoc
-
-;; Documentation in the echo-area (where the minibuffer is displayed) is
-;; rather useful.
-
-(use-package eldoc
-  :commands (eldoc-mode global-eldoc-mode)
-  :config (progn
-            (setq eldoc-idle-delay 0.1)
-            (global-eldoc-mode +1)
-            (eldoc-add-command 'paredit-backward-delete 'paredit-close-round)))
-;;;; Mail
-
-;;;;; Basics
-
-(with-eval-after-load "mailcap"
-  (when (eq system-type 'darwin)
-    (mailcap-add-mailcap-entry "application" "pdf" '((viewer . "/usr/bin/qlmanage -p %s") (type . "application/pdf")))))
-
-(with-eval-after-load "mm-decode"
-  (add-to-list 'mm-discouraged-alternatives "text/html")
-  (add-to-list 'mm-discouraged-alternatives "text/richtext"))
-
-(with-eval-after-load "mml-sec"
-  (setq mml-secure-openpgp-encrypt-to-self t))
-
-;;;; Misc
-
-(defun ap/remove-extra-cr ()
-  "Remove extraneous CR codes from a file."
-  (interactive)
-  (save-excursion
-    (goto-char (point-min))
-    (while (search-forward "
-  " nil t)
-      (replace-match ""))))
-
-;;;;; Auxillary Configuration
-
-(defvar have-private-key
-  (file-exists-p (expand-file-name "secring.gpg" "~/.gnupg/")))
-
-(defvar gpg-agent-ssh-sock
-  (or (getenv "GPG_AGENT_INFO")
-      (concat "/run/user/" (number-to-string (user-uid)) "/gnupg/S.gpg-agent.ssh")))
-
-(defun read-gpg-file (file)
-  "Read (decrypt) given GPG file FILE."
-  (let ((file-to-decrypt (expand-file-name file user-emacs-directory))
-        (ctx (epg-make-context epa-protocol)))
-    (if (file-exists-p file-to-decrypt)
-        (epg-decrypt-file ctx file-to-decrypt nil)
-      (message "Decrypting %s...failed" file-to-decrypt)
-      (error "File %s does not exist" file-to-decrypt))))
-
-(defun load-gpg (file)
-  "Load FILE if private key is available."
-  (if have-private-key
-      (load file)
-    (message "WARNING: Couldn't load %s (No gpg key found)" file)))
-
-; load this in a post-frame hook because gpg-agent asks for a password on first
-; startup and caches it. Don't want emacs daemon to hang because of gpg-agent.
-(defun load-private-data ()
-  "Load encrypted config in file based upon hostname."
-  (interactive)
-  (if (not (file-exists-p (expand-file-name (concat (system-name) ".el.gpg") user-emacs-directory)))
-      (message "No encrypted configuration matches system name `%s'" (system-name))
-    (if (not have-private-key)
-        (message "ERROR: Private GPG key not found")
-      (unless (or (getenv "GPG_AGENT_INFO")
-                  (getenv "SSH_AUTH_SOCK"))
-        (start-process "gpg-agent" nil "gpg-agent" "--daemon")
-        (setenv "SSH_AUTH_SOCK" gpg-agent-ssh-sock))
-      (setq password-cache-expiry nil)
-      (unless (file-exists-p (concat pinentry--socket-dir "pinentry"))
-        (pinentry-start)
-        (add-hook 'kill-emacs-hook 'pinentry-stop))
-      (add-to-list 'load-suffixes ".el.gpg")
-      (load-gpg (expand-file-name (system-name) user-emacs-directory)))))
-
-(defvar first-frame-hook nil
-  "Hook for running code after first-frame is opened.")
-
-(defun first-frame-hook-handler (frame)
-  "Hook run only after first frame FRAME is created."
-  (remove-hook 'after-make-frame-functions #'first-frame-hook-handler)
-  (run-at-time nil nil (lambda () (run-hooks 'first-frame-hook))))
-
-(if (or (daemonp)
-        (not (eq 1 (length (frame-list)))))
-    (add-hook 'after-make-frame-functions #'first-frame-hook-handler)
-  (run-at-time nil nil (lambda () (run-hooks 'first-frame-hook))))
-
-(add-hook 'first-frame-hook #'load-private-data)
-
-;;;; Minibuffer
-
-;; Sometimes I want to use the minibuffer, but I’m already inside it.
-;; Fortunately, this is possible.  Of course, I need to know how many
-;; minibuffers there are on the stack.
-
-(setq enable-recursive-minibuffers t)
-(minibuffer-depth-indicate-mode t)
-
-;; This avoids some issue with the minibuffer and the point being behind
-;; the prompt.  I don’t remember what exactly.
-(setq minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt))
-
-;; Occasionally, I exit emacs.  I should probably reduce the frequency of this.
-(if (daemonp)
-    (defalias 'exit-emacs #'delete-frame)
-  (defalias 'exit-emacs #'save-buffers-kill-emacs))
-
-;;;;; swiper/ivy
-
-;; Ivy is the new kid on the completion block.  It seems to be a strong
-;; replacement for helm so far.
-
-(use-package swiper
-  :bind (("C-s" . swiper)
-         ("C-r" . swiper)
-         ("C-=" . swiper))
-  :demand t
-  :config (progn
-            (ivy-mode 1)
-            (setq ivy-re-builders-alist '((t . ivy--regex-plus))
-                  ivy-extra-directories '("./"))
-            (ivy-set-actions 'ivy-switch-buffer '(("k" (lambda (x)
-                                                         (kill-buffer x)
-                                                         (ivy--reset-state ivy-last))
-                                                   "kill")))
-            (add-to-list 'ivy-initial-inputs-alist '(counsel-M-x . ""))))
-
-(use-package ivy-hydra)
-
-;;;;; counsel
-
-(use-package counsel
-  :config (progn
-            (bind-key "M-x" #'counsel-M-x)
-            (bind-key "<apps>" #'counsel-M-x)
-            (bind-key "<menu>" #'counsel-M-x)
-            (bind-key "C-c M-x" #'execute-extended-command)
-            (bind-key "C-x C-f" #'counsel-find-file)
-            (bind-key "M-y" #'counsel-yank-pop)
-            (bind-key "C-x i" #'counsel-imenu)
-            (bind-key "M-y" #'ivy-next-line ivy-minibuffer-map)
-            (setq counsel-ag-base-command "ag --nocolor --nogroup --hidden %s")
-            (defadvice counsel-find-file (after find-file-sudo activate)
-              "Find file as root if necessary."
-              (when (and buffer-file-name
-                         (not (file-writable-p buffer-file-name)))
-                (message "File not writable %s" buffer-file-name)
-                (find-alternate-file (concat "/sudo::" buffer-file-name))))
-            (setq counsel-rg-base-command "rg -i --no-heading --line-number --hidden %s .")))
-
-
-;;;;; smex
-
-;; Smex is my favourite way to use =M-x=.  Counsel’s =counsel-M-x=
-;; function uses it internally, so I’m keeping it around, even though I
-;; don’t use it directly.
-
-(use-package smex
-  :defines (smex-key-advice-ignore-menu-bar)
-  :commands (smex
-             smex-update
-             smex-initialize)
-  :config (progn
-            (setq smex-key-advice-ignore-menu-bar t
-                  smex-auto-update nil)
-            (defun smex-update-after-load (_unused)
-              (if (boundp 'smex-cache)
-                  (smex-update)))
-            (add-hook 'after-load-functions 'smex-update-after-load))
-  :init (progn
-          (setq smex-history-length 100
-                smex-save-file (concat user-emacs-directory
-                                       "smex-items"))))
-
-;;;;; cmd-to-echo
-
-;; I’ve been looking for some way to run programming projects (mostly
-;; node.js) inside emacs.  =cmd-to-echo= seems great for this, as new
-;; output pops up in the echo area.
-
-(use-package cmd-to-echo
-  :commands (cmd-to-echo)
-  :config (setq cmd-to-echo-add-output-to-process-buffers t))
-;;;; Modes
-
-;; Setup some modes for systemd files
-(add-to-list 'auto-mode-alist '("\\.service\\'" . conf-mode))
-(add-to-list 'auto-mode-alist '("\\.target\\'" . conf-mode))
-(add-to-list 'auto-mode-alist '("\\.socket\\'" . conf-mode))
-
-;; =direnv=’s files are basically shell scripts, it’s a nice way to
-;; set environment variables for projects.
-(add-to-list 'auto-mode-alist '("\\.envrc\\'" . sh-mode))
+  :config (global-undo-tree-mode))
+(use-package goto-chg
+  :defer 1)
 
-;; Some modes that I don’t really customise much, mostly for
-;; configuration files.
-(use-package haskell-mode
-  :mode (("\\.hs\\'" . haskell-mode)))
+;;; Directories
 
-(use-package dockerfile-mode
-  :mode (("Dockerfile\\'" . dockerfile-mode)))
+(custom-set-variables
+ '(dired-dwim-target t)
+ '(dired-recursive-copies 'top)
+ '(dired-listing-switches "-alh")
+ '(dired-recursive-deleted (if delete-by-moving-to-trash
+                              'always
+                            'top)))
 
-(use-package docker-compose-mode
-  :mode (("docker-compose.*.yml" . docker-compose-mode))
-  :config (progn
-            (add-hook 'docker-compose-mode-hook #'company-mode-on)))
-
-(use-package nix-mode
-  :mode (("\\.nix\\'" . nix-mode))
-  :config (progn
-            (setq nix-indent-function #'nix-indent-line)))
-
-(define-derived-mode xmonad-mode haskell-mode "XM")
-(add-to-list 'auto-mode-alist '("xmobarrc\\'" . xmonad-mode))
-(add-to-list 'auto-mode-alist '("xmonad.hs\\'" . xmonad-mode))
-
-(use-package nginx-mode
-  :defer t
-  :mode (("/nginx/servers/" . nginx-mode)
-         ("/nginx/.*\\.d/" . nginx-mode)))
-
-(use-package ruby-mode
-  :mode (("\\.rb\\'" . ruby-mode)
-         ("\\.cap\\'" . ruby-mode)))
-
-(use-package go-mode
-  :mode (("\\.go\\'" . go-mode)))
-
-(use-package jinja2-mode
-  :mode (("\\.j2\\'" . jinja2-mode)
-         ("\\.jinja\\'" . jinja2-mode)))
-
-(use-package scss-mode
-  :defer t
-  :config (progn
-            (setq scss-compile-at-save nil)))
-
-(use-package toml-mode
-  :mode ("\\.toml\\'" . toml-mode))
-
-(use-package yaml-mode
-  :mode (("/group_vars/.*" . yaml-mode)
-         ("/host_vars/.*" . yaml-mode)))
-
-(define-derived-mode ansible-mode yaml-mode "Ansible")
-(add-to-list 'auto-mode-alist '("\\(?:ansible.+\\|roles/.+/\\(?:tasks\\|handlers\\)\\)/.+\\.yml\\'" . ansible-mode))
-
-(define-derived-mode saltstack-mode yaml-mode "Salt")
-(add-to-list 'auto-mode-alist '("\\.sls\\'" . saltstack-mode))
-
-;;;;; Beancount
-
-(let ((beancount-dir (car (split-string (shell-command-to-string "ghq list --full-path blais/beancount")))))
-  (when (and beancount-dir
-             (file-directory-p beancount-dir))
-    (add-to-list 'load-path (expand-file-name "editors/emacs/"
-                                              beancount-dir))
-    (use-package beancount
-      :defines (beancount-use-ido
-                beancount-mode-map
-                beancount-mode-map-prefix)
-      :commands beancount-mode
-      :bind (:map beancount-mode-map
-                  ("C-c d" . insert-date))
-      :config (setq beancount-use-ido nil
-                    beancount-mode-map-prefix (kbd ", a")))))
-
-;;;;; Markdown
-
-(use-package markdown-mode
-  :defer t)
-
-;;;;; Org
-
-;; Org is wünderbar.
-
-(use-package org
-  :bind (("C-c C-a" . org-agenda-list)
-         ("C-c a" . org-agenda)
-         ("C-c l" . org-store-link))
-  :defer 8
-  :defines (org-table-duration-custom-format)
-  :init (setq org-replace-disputed-keys t
-              org-support-shift-select 'always
-              org-ellipsis "…")
-  :config (progn
-            (setq org-directory "~/Documents/org"
-                  org-agenda-files `(,(concat org-directory "/agenda"))
-
-                  org-default-notes-file (concat org-directory "/notes")
-
-                  ;; ‘Remember’: new items at top
-                  org-reverse-note-order t
-
-                  org-modules '(org-protocol)
-
-                  ;; Add time done to ‘done’ tasks
-                  org-log-done 'time
-
-                  org-list-allow-alphabetical t
-
-                  org-adapt-indentation nil
-
-                  org-pretty-entities t
-
-                  org-table-duration-custom-format 'seconds
-
-                  org-src-fontify-natively nil
-
-                  org-blank-before-new-entry '((heading . t)
-                                               (plain-list-item . auto))
-                  org-fontify-done-headline t
-
-                  org-goto-interface 'outline-path-completion
-
-                  org-outline-path-complete-in-steps nil
-
-                  org-todo-keywords '((sequence "BACKLOG(b)" "TODO(t)" "WAIT(w@/!)" "STARTED(s!)" "|" "DONE(d!)")
-                                      (sequence "|" "CANCELLED(c@)"))
-                  org-log-into-drawer "LOGBOOK")
-            (set-register ?o `(file . ,(expand-file-name "organiser.org" org-directory)))
-            (add-hook 'org-mode-hook #'turn-on-auto-fill)
-            (org-load-modules-maybe t)))
-
-(use-package org-src
-  :ensure nil
-  :after org
-  :config (progn
-            (bind-key "C-x C-s" #'org-edit-src-exit org-src-mode-map)))
-
-;;;;;;; org-babel
-
-;; Org’s babel feature is really nice.  I use it for this file, and I can
-;; use it to communicate between programming languages.  Sometime I hope
-;; to have my =ledger= setup in an org file with some graph processing
-;; with R or something.
-
-(use-package ob-core
-  :defer t
-  :ensure nil
-  :config (progn
-            (org-babel-do-load-languages 'org-babel-load-languages
-                                         '((ledger . t)
-                                           (shell . t)))
-            (setq org-src-tab-acts-natively t
-                  org-edit-src-content-indentation 0
-                  org-src-preserve-indentation t)))
-
-;;;;;;; org-journal
-
-;; I can use this to keep a journal.  I should use it.
-
-(use-package org-journal
-  :bind ("s-j" . org-journal-new-entry)
-  :defer 20
-  :config (progn
-            (setq org-journal-date-format "%A, %d %B %Y"
-                  org-journal-dir "~/Documents/journal/")
-
-            (define-hook-helper org-journal-mode ()
-              (use-variable-fonts)
-              (text-scale-adjust 4))
-            (defun org-journal-display-entry-yesterday ()
-              "Show org-journal entry for yesterday"
-              (interactive)
-              (org-journal-read-or-display-entry (yesterday-time)))))
-
-
-;;;; Programming
-
-;;;;; flycheck
-
-;; On-the-fly error checking in programming modes?  Yes please.
-
-(use-package flycheck
-  :defer 5
-  :config (progn
-            (global-flycheck-mode)
-            (setq flycheck-check-syntax-automatically '(save mode-enabled))
-            (setq flycheck-indication-mode 'left-fringe)
-            (with-eval-after-load 'git-gutter-fringe
-              (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated)
-                "XXX....."))
-            (if (executable-find "eslint_d")
-                (setq flycheck-javascript-eslint-executable "eslint_d"))))
-
-;;;;;; flycheck-pos-tip
-
-;; Show flycheck errors in a little popup, so I don't lose my place
-
-(use-package flycheck-pos-tip
-  :after flycheck
-  :config (progn
-            (setq flycheck-display-errors-delay 0.5
-                  flycheck-pos-tip-timeout 15)
-            (flycheck-pos-tip-mode 1)))
-
-;;;;; golang
-
-;; Go has a few packages to inter-operate with other emacs packages.
-
-(use-package company-go
-  :commands company-go
-  :config (progn
-            (setq company-go-show-annotation t))
-  :init (progn
-          (define-hook-helper go-mode ()
-            (set (make-local-variable 'company-backends)
-                 '(company-go)))))
-
-(use-package go-eldoc
-  :commands go-eldoc-setup
-  :init (progn
-          (add-hook 'go-mode-hook #'go-eldoc-setup)))
-
-(use-package go-projectile
-  :defer t
-  :config (progn
-            (setq go-projectile-switch-gopath 'maybe)))
-
-;;;;; ggtags
-
-;; A nice completion backend for programming modes.
-
-(use-package ggtags
-  :if (executable-find "gtags")
-  :commands turn-on-ggtags-mode
-  :functions (ggtags-navigation-mode-abort)
-  :config (progn
-            (bind-key "q" #'ggtags-navigation-mode-abort ggtags-navigation-mode-map))
-  :init (progn
-          (defun turn-on-ggtags-mode ()
-            (interactive)
-            (ggtags-mode 1))
-          (add-hook 'c-mode-common-hook #'turn-on-ggtags-mode)))
-
-;;;;; dumb-jump
-
-;; A "clever" way of implementing go-to-definition across languages: use
-;; a project-wide text search and apply heuristics to the results to
-;; guess a definition.
-
-(use-package dumb-jump
-  :bind (("M-g o" . dumb-jump-go-other-window)
-         ("M-g j" . dumb-jump-go)
-         ("M-g x" . dumb-jump-go-prefer-external)
-         ("M-g z" . dumb-jump-go-prefer-external-other-window))
-  :config (setq dumb-jump-selector 'ivy))
-
-;;;;; imenu-anywhere
-
-;; This is like imenu, but shows functions (or similar top-level
-;; entities) across buffers in the same project.  Neat!
-
-(use-package imenu-anywhere
-  :if (featurep 'helm-imenu)
-  :bind ("C-x C-." . ivy-imenu-anywhere))
-
-;;;;; Lisps
-
-;;;;;; All
-
-;; Lisp modes don’t seem to have a common ancestor.  So I made a custom
-;; hook which I trigger in every lispy-mode.
-
-(defcustom lisp-mode-common-hook nil
-  "Hook run when entering any Lisp mode."
-  :type 'hook
-  :group 'lisp)
-
-(create-hook-helper lisp-mode-setup ()
-  :hooks (emacs-lisp-mode-hook
-          scheme-mode-hook
-          lisp-mode-hook
-          clojure-mode-hook)
-  (run-hooks 'lisp-mode-common-hook))
-
-;;;;;;; Redshank
-
-;; Lisp syntax allows for really easy refactoring.  Redshank gives some
-;; operations that aren’t part of paredit, like extracting variables into
-;; let bindings.
-(use-package redshank
-  :after (paredit)
-  :config (progn
-            (add-hook 'lisp-mode-common-hook #'turn-on-redshank-mode)))
-
-;;;;;; Emacs Lisp
-
-;; Go-to function for elisp.  Except it works through the entire Emacs ecosystem.
-
-(use-package elisp-slime-nav
-  :commands elisp-slime-nav-mode
-  :init (progn
-          (add-hook 'emacs-lisp-mode-hook #'elisp-slime-nav-mode)))
-
-;; Interactive elisp
-
-(use-package ielm
-  :defer t
-  :ensure nil
-  :config (progn
-            (define-hook-helper ielm-mode ()
-              (run-hooks 'lisp-mode-common-hook))))
-
-;;;;;; Scheme & Lisp
-
-;; I don’t work with these as often as I would like
-
-(define-hook-helper lisp-mode ()
-  (set (make-local-variable 'lisp-indent-function)
-       #'common-lisp-indent-function))
-
-;;;;;;; geiser
-
-;; A REPL thing for Scheme.  Hopefully I’ll get to use it more in the
-;; future.
-
-(use-package geiser
-  :commands (geiser-mode
-             geiser
-             run-geiser
-             run-racket))
-
-;;;;;;; slime
-
-;; A REPL thing (and more) for Lisp.
-
-(use-package slime
-  :commands (slime)
-  :config (progn
-            (let ((ql-slime-helper (expand-file-name "~/quicklisp/slime-helper.el")))
-              (if (file-exists-p ql-slime-helper)
-                  (load ql-slime-helper))
-              (slime-setup '(slime-fancy slime-asdf)))
-            (setq common-lisp-hyperspec-root "file://opt/local/share/doc/lisp/HyperSpec-7-0/"
-                  inferior-lisp-program (or (executable-find "sbcl")
-                                            (executable-find "ccl64")))))
-
-;;;;;; Clojure
-
-(use-package clojure-mode
-  :defer t
-  :init (progn
-          (define-hook-helper cider-repl-mode ()
-            (highlight-changes-mode -1))))
-
-(use-package clj-refactor
-  :defer t
-  :functions (clj-refactor-mode cljr-add-keybindings-with-prefix)
-  :config (progn
-            (cljr-add-keybindings-with-prefix "C-c C-m"))
-  :init (progn
-          (define-hook-helper clojure-mode ()
-            (clj-refactor-mode 1))))
-
-;;;;;;; cider
-
-;; A REPL thing for Clojure
-
-(use-package cider
-  :defer t
-  :config (progn
-            (setq nrepl-hide-special-buffers t)
-            (unbind-key "C-c C-f" cider-mode-map)))
-
-;;;;; Auto-compile
-
-;; Auto-compile emacs lisp when saving, asynchronously.
-(use-package auto-async-byte-compile
-  :config (add-hook 'emacs-lisp-mode-hook #'enable-auto-async-byte-compile-mode))
-
-;;;;; cc-mode
-
-;; Although I don’t use C or C++, setting up the mode is helpful because
-;; quite a few other modes are derived from it.
-
-(use-package cc-mode
-  :defer 5
-  :config (progn
-            (setq c-default-style '((java-mode . "java")
-                                    (awk-mode . "awk")
-                                    (other . "k&r"))
-                  c-basic-offset 4)
-            (c-set-offset 'case-label '+)))
-
-;;;;; quickrun
-
-;; It’s nice to be able to quickly evaluate some code.  Although I don’t
-;; really seem to use it.
-(use-package quickrun
-  :bind (("C-c C-e" . quickrun)))
-
-;;;;; Web development
-
-;;;;;; js2-mode
-
-;; This mode is really great for editing Javascript.  It turns code into
-;; an AST internally, so it can work with it almost like a lisp.
-
-(use-package js2-mode
-  :mode (("\\.js\\'" . js2-mode))
-  :interpreter ("node" . js2-mode)
-  :functions (js2-next-error
-              js2--struct-put)
-  :config (progn
-            (define-key js2-mode-map [menu-bar Javascript] nil)
-            (add-hook 'js2-mode-hook #'js2-imenu-extras-mode)
-            (defun ap/js2-prev-error ()
-              (interactive)
-              (js2-next-error -1))
-            (bind-key "M-g M-n" #'js2-next-error js2-mode-map)
-            (bind-key "M-g M-p" #'ap/js2-prev-error js2-mode-map)
-            (advice-add #'js--multi-line-declaration-indentation :around (lambda (orig-fun &rest args) nil))
-            (setq js2-basic-offset 2
-                  js-switch-indent-offset 2
-                  js2-include-node-externs t
-                  js2-highlight-level 1
-                  js2-strict-missing-semi-warning nil
-                  js2-strict-inconsistent-return-warning nil)))
-
-;;;;;;; typescript-mode
-
-(use-package typescript-mode
-  :config (progn
-            (setq typescript-indent-level 2)))
-
-;;;;;;; rjsx-mode
-
-;; A set of advice for js2-jsx-mode to work better with React.
-
-(use-package rjsx-mode
-  :after js2-mode
-  :if (fboundp #'js2--struct-put)
-  :mode (("\\.jsx\\'" . rjsx-mode)))
-
-;;;;;;; mocha
-
-(use-package mocha
-  :after js2-mode
-  :config (progn
-            (setq mocha-reporter "spec"
-                  mocha-options "--bail")
-            (defun mocha-test-project ()
-              "Test the current project."
-              (interactive)
-              (mocha-run "'./{src,lib,test}/**/*.test.js'"))))
-
-;;;;;;; js2-refactor
-
-;; Thanks to the AST provided by js2-mode, refactoring is possible.  This
-;; library implements some refactorings.
-
-(use-package js2-refactor
-  :after js2-mode
-  :config (progn
-            (bind-key "C-k" #'js2r-kill js2-mode-map)
-            (add-hook 'js2-mode-hook #'js2-refactor-mode)
-            (js2r-add-keybindings-with-prefix "C-c C-m")))
-
-;;;;;;; add-node-modules-path
+;;; Shells
 
-;; Inside a javascript project, it's common to install tools locally to
-;; the project.  This will allows emacs to find their executables.
-
-(use-package add-node-modules-path
-  :config (progn
-            (create-hook-helper js2-mode ()
-              :hooks (js2-mode-hook
-                      typescript-mode-hook)
-              :name node-modules-flycheck
-              (add-node-modules-path)
-              (when (executable-find "tslint")
-                (setq-local flycheck-typescript-tslint-executable (executable-find "tslint")))
-              (when (executable-find "eslint")
-                (setq-local flycheck-javascript-eslint-executable (executable-find "eslint")))
-              (when (executable-find "prettier-standard")
-                (setq-local flycheck-javascript-standard-executable (executable-find "prettier-standard")))
-              (when (executable-find "standard")
-                (setq-local flycheck-javascript-standard-executable (executable-find "standard"))))))
-
-;;;;;;; Prettier
-
-;; Reformat files on save
-
-(use-package prettier-js
-  :config (progn
-            (add-hook 'typescript-mode #'prettier-js-mode)
-            (add-hook 'js2-mode #'prettier-js-mode)))
-
-;;;;;;; Indium
-
-;; Javascript with an inferior node.js process and a debugger?  Awesome.
-
-;; To debug with node, use version 6.9.1 or later of node and run it with
-;; ~--inspect~ and, to break on the first line, ~--debug-brk~.
-
-;; For Chrom*, it needs to be launched with
-;; ~--remote-debugging-port=9222~
-
-;; Node will tell you to open an URL in Chrome:
-
-;; ~chrome-devtools://inspector.html?...&ws=127.0.0.1:PORT/PATH~
-
-;; Instead, do this:
-
-;; ~M-x indium-connect-to-nodejs RET 127.0.0.1 RET PORT RET~
-
-(use-package indium
-  :config (progn
-            (add-hook 'js2-mode-hook #'indium-interaction-mode)))
-
-;;;;;; tide
-
-;; Let's write some typescript
-
-(use-package tide
-  :after (typescript-mode company flycheck)
-  :hook ((typescript-mode . tide-setup)))
-
-;;;;;; tern
-
-;; Tern understands javascript.  It adds really clever documented
-;; completions, besides other IDE-like things.
-
-(use-package tern
-  :if (executable-find "tern")
-  :defer 5
-  :config (progn
-            (setq tern-command (list (executable-find "tern")))
-            (create-hook-helper tern-mode-on ()
-              :hooks (js2-mode-hook)
-              (tern-mode +1))))
-
-(with-eval-after-load 'tern
-  (use-package company-tern))
-
-;;;;;; json-mode
-
-(use-package json-mode
-  :mode (("\\.json\\'" . json-mode)
-         ("\\.sailsrc\\'" . json-mode)
-         ("composer\\.lock\\'" . json-mode)
-         ("\\.tern-project\\'" . json-mode)))
-
-;;;;;; restclient
-
-;; Restclient is really nice.  It’s like a scratchpad for HTTP api
-;; calls.  Feels a bit like using =org-babel=.  I wonder if there’s an
-;; integration between the two yet.
-
-(use-package restclient
-  :mode ("\\.api\\'" . restclient-mode)
-  :config (progn
-            (defun imenu-restclient-sections ()
-              (setq imenu-prev-index-position-function nil)
-              (add-to-list 'imenu-generic-expression '("Services" "^## ?\\(.+\\)$" 1) t)
-              (add-to-list 'imenu-generic-expression '("Calls" "^# ?\\(.+\\)$" 1) t))
-            (add-hook 'restclient-mode-hook #'imenu-restclient-sections)))
-
-(use-package company-restclient
-  :after (company restclient)
-  :init (add-to-list 'company-backends #'company-restclient t))
-
-;;;;;; sgml-mode
-
-;; This is for HTML, since old versions of HTML were derived from SGML.
-(use-package sgml-mode
-  :defer t
-  :config (setq sgml-basic-offset 2))
-
-;;;;;; emmet-mode
-
-;; Emmet is really nice to write HTML quickly.  Especially with
-;; frameworks that require multiple nested elements to do anything useful.
-(use-package emmet-mode
-  :commands (emmet-mode)
-  :init (progn
-          (setq emmet-indentation 2
-                emmet-self-closing-tag-style " /")
-          (add-hook 'sgml-mode-hook #'emmet-mode)
-          (add-hook 'web-mode-hook #'emmet-mode)
-          (add-hook 'css-mode-hook #'emmet-mode)))
-
-;;;;;; web-mode
-
-;; This mode handles just about every templating language out ther, which
-;; is really nice, because it handles the HTML part the same way in all
-;; of them as well.
-
-(use-package web-mode
-  :mode (("/views/.*\\.php\\'" . web-mode)
-         ("\\.html\\'" . web-mode)
-         ("/templates/.*\\.php\\'" . web-mode)
-         ("\\.handlebars\\'" . web-mode)
-         ("\\.ejs\\'" . web-mode)
-         ("\\.njk\\'" . web-mode))
-  :config (progn
-            (setq web-mode-code-indent-offset 2
-                  web-mode-css-indent-offset 2
-                  web-mode-markup-indent-offset 2
-                  web-mode-style-padding 0
-                  web-mode-script-padding 0
-                  web-mode-comment-style 2
-                  web-mode-enable-auto-pairing nil
-                  web-mode-enable-auto-quoting nil)))
-
-;;;;; Live coding
-
-;; Sometimes I might want to show off my emacs usage.
-
-(defun live-coding ()
-  "Configure display for live coding."
-  (interactive)
-  (ap/set-fonts "SF Mono" 18 nil nil t 0.1)
-  (global-command-log-mode 1))
-
-(defun live-coding-stop ()
-  "Revert live coding display configuration."
-  (interactive)
-  (ap/set-fonts-according-to-system)
-  (global-command-log-mode -1))
-
-;;;;;; command-log-mode
-
-(use-package command-log-mode
-  :defines (command-log-mode-key-binding-open-log)
-  :config (progn
-            (setq command-log-mode-key-binding-open-log nil
-                  command-log-mode-auto-show t
-                  command-log-mode-is-global t)))
-
-;;;; Systems
-
-(use-package kubernetes
-  :commands (kubernetes-overview))
-
-(use-package k8s-mode
-  :config (progn
-            (setq k8s-site-docs-version "v1.11"
-                  k8s-search-documentation-browser-function #'browse-url-chrome)))
+(use-package eshell
+  :functions (eshell/pwd)
+  :custom ((eshell-prompt-function (lambda ()
+                                     (concat (eshell/pwd) "\n$ ")))
+           (eshell-prompt-regexp "^[$][[:blank:]]")))
 
-(use-package kubernetes-evil
-  :after (kubernetes evil))
+(use-package shell
+  :general (:keymaps 'shell-mode-map
+                     "C-d" #'comint-delchar-or-maybe-eof))
 
-;;;; Spelling
+(use-package comint
+  :general (:keymaps 'comint-mode-map
+                     "C-c C-l" #'counsel-shell-history))
 
-(use-package ispell
-  :bind (("<f8>" . ispell-word))
-  :config (progn
-            (cond
-             ((executable-find "aspell") (setq ispell-program-name "aspell"
-                                               ispell-dictionary "british"
-                                               ispell-really-aspell t
-                                               ispell-really-hunspell nil))
-             ((executable-find "hunspell") (setq ispell-program-name "hunspell"
-                                                 ispell-really-aspell nil
-                                                 ispell-really-hunspell t)))))
-
-(use-package flyspell
-  :config (progn
-            (defun flyspell-detect-ispell-args (&optional run-together)
-              "If RUN-TOGETHER is true, spell check the CamelCase words.
- Please note RUN-TOGETHER will make aspell less capable. So it should only be used in prog-mode-hook."
-              (let (args)
-                (when ispell-program-name
-                  (cond
-                   ((string-match "aspell$" ispell-program-name)
-                    (setq args (list "--sug-mode=ultra"))
-                    (if run-together
-                        (setq args (append args '("--run-together" "--run-together-limit=16" "--run-together-min=2")))))
-                   ((string-match "hunspell$" ispell-program-name)
-                    (setq args nil))))
-                args))
-            ;; `ispell-extra-args' is *always* used when start CLI aspell process
-            (setq-default ispell-extra-args (flyspell-detect-ispell-args t))
-            ;; (setq ispell-cmd-args (flyspell-detect-ispell-args))
-            (defadvice ispell-word (around my-ispell-word activate)
-              (let ((old-ispell-extra-args ispell-extra-args))
-                (ispell-kill-ispell t)
-                ;; use emacs original arguments
-                (setq ispell-extra-args (flyspell-detect-ispell-args))
-                ad-do-it
-                ;; restore our own ispell arguments
-                (setq ispell-extra-args old-ispell-extra-args)
-                (ispell-kill-ispell t)))
-
-            (defadvice flyspell-auto-correct-word (around my-flyspell-auto-correct-word activate)
-              (let* ((old-ispell-extra-args ispell-extra-args))
-                (ispell-kill-ispell t)
-                ;; use emacs original arguments
-                (setq ispell-extra-args (flyspell-detect-ispell-args))
-                ad-do-it
-                ;; restore our own ispell arguments
-                (setq ispell-extra-args old-ispell-extra-args)
-                (ispell-kill-ispell t)))
-            (setq flyspell-issue-message-flag nil)
-
-            (defun fly-text-mode-hook-setup ()
-              ;; Turn off RUN-TOGETHER option when spell check text-mode
-              (setq-local ispell-extra-args (flyspell-detect-ispell-args)))
-            (add-hook 'text-mode-hook 'fly-text-mode-hook-setup)
-            (add-hook 'prog-mode-hook #'flyspell-prog-mode)))
-
-;;;;; Dictionary
-
-;; One thing I miss from macOS is the "look up" functionality to define
-;; words by a certain gesture.  =define-word= can provide something
-;; similar, at least in Emacs.
-
-(use-package define-word
-  :bind ("M-<f8>" . define-word-at-point))
-
-;;;;; Style checking
-
-;; [[https://github.com/ValeLint/vale][Vale]] is a linter, but for prose.  Neat idea!  Salesman is a bad term.
-
-(use-package flycheck-vale
-  :if (executable-find "vale")
-  :config (progn
-            (add-to-list 'flycheck-vale-modes 'org-mode)
-            (add-to-list 'flycheck-vale-modes 'org-journal-mode)
-            (flycheck-vale-setup)))
+;;; Major modes
 
-;;;; Scripting
+;;;; js
+(custom-set-variables '(js-indent-level 2)
+                      '(js-enabled-frameworks '(javascript)))
 
-;; Make a shell-script buffer executable after saving it, if it has a shebang.
+;;;; typescript
+(custom-set-variables '(typescript-indent-level 2))
 
-(add-hook 'after-save-hook
-          #'executable-make-buffer-file-executable-if-script-p)
+;;;; shell
+(general-add-hook 'sh-mode-hook
+                  (lambda ()
+                    (general-add-hook 'after-save-hook
+                                      #'executable-make-buffer-file-executable-if-script-p :append :local)))
 
+(add-to-list 'auto-mode-alist '("\\.env\\'" . conf-unix-mode))
 (use-package sh-script
   :mode (("\\.zsh\\'" . shell-script-mode)
          ("zshenv\\'" . shell-script-mode)
@@ -2059,301 +385,122 @@ With two prefix arguments, write out the day and month name."
 
 (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
 
-;;;;; eshell
-
-;; I should try to get into the habit of using this more.  It’s really
-;; nice, when I remember to use it.
-
-(use-package eshell
-  :bind ("C-c s" .  eshell)
-  :defer 10
-  :functions (eshell/pwd)
-  :defines (eshell-prompt-function
-            eshell-prompt-regexp)
-  :config (progn
-            (setq eshell-directory-name "~/.emacs.d/eshell"
-                  eshell-prompt-function (lambda ()
-                                           (concat
-                                            (eshell/pwd)
-                                            "\n$ "))
-                  eshell-prompt-regexp (rx bol (char "$") blank))
-            (define-hook-helper eshell-load ()
-              (bind-key "C-c C-l" #'counsel-esh-history eshell-mode-map))))
-
-(use-package em-smart
-  :ensure nil
-  :commands eshell-smart-initialize
-  :config (progn
-            (setq eshell-where-to-jump 'begin
-                  eshell-review-quick-commands nil
-                  eshell-smart-space-goes-to-end t)))
-
-(autoload #'eshell/cd "em-dirs")
-(defun eshell-goto-current-dir (&optional arg)
-  "Open `default-directory' in eshell.
-Pass optional ARG to `eshell' (which see)."
-  (interactive "P")
-  (let ((dir default-directory))
-    (eshell arg)
-    (eshell/cd dir)))
-(bind-key "C-c S" #'eshell-goto-current-dir)
-
-;;;;;; Shells
-
-(use-package shell
-  :defer t
-  :ensure nil
-  :config (define-key shell-mode-map
-            (kbd "C-d") 'comint-delchar-or-eof-or-kill-buffer))
-
-(use-package comint
-  :defer t
-  :ensure nil
-  :config (bind-key "C-c C-l" #'counsel-shell-history comint-mode-map))
-
-(defun comint-delchar-or-eof-or-kill-buffer (arg)
-  "DWIM command for ^D to behave like in shells.
-Pass ARG to `comint-delchar-or-maybe-eof'."
-  (interactive "p")
-  (if (null (get-buffer-process (current-buffer)))
-      (kill-buffer)
-    (comint-delchar-or-maybe-eof arg)))
-
-;;;; Text editing
-
-;; Emacs has an editor within.
-
-(put 'upcase-region 'disabled nil)
-(put 'downcase-region 'disabled nil)
-(setq sentence-end-double-space t
-      line-move-visual nil)
-(visual-line-mode +1)
-(global-subword-mode +1)
-
-;;;;; align
-
-;; =Align= is a useful command to line things up, once given some rules.
-;; The most important one for me is JSON property alignment.
-
-(use-package align
-  :defer 10
-  :ensure nil
-  :config (progn
-            (add-to-list 'align-rules-list
-                         '(colon-key-value
-                           (regexp . ":\\(\\s-*\\)")
-                           (modes  . '(js2-mode))))))
-
-;;;;; Clipboard
-
-;; I like to use the clipboard more than the primary selection in X11.
-
-(setq select-enable-clipboard t
-      save-interprogram-paste-before-kill t)
-(if (functionp 'x-cut-buffer-or-selection-value)
-    (setq interprogram-paste-function 'x-cut-buffer-or-selection-value))
-(when (boundp 'x-select-request-type)
-  (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))
-
-;;;;; avy
-
-;; Avy is a really nice way to move around files, like ace-jump-mode, but
-;; somehow I prefer it.
-
-(use-package avy
-  :defer 5
-  :bind* (("M-g g" . avy-goto-line)
-          ("M-g M-g" . avy-goto-line)
-          ("M-r" . avy-goto-word-1)
-          ("C-c SPC" . avy-goto-char-timer))
-  :config (progn
-            (avy-setup-default)
-            (setq avy-all-windows nil)))
-
-;;;;;; ace-link
-
-;; Visit any link.  Despite the name, this works with avy.
-
-(use-package ace-link
-  :after avy
-  :config (progn
-            (ace-link-setup-default)))
-
-;;;;; goto-chg
-
-;; This is like popping the mark, only it filters to only change areas
-;; and doesn’t go back to the same place more than once.
-
-(use-package goto-chg)
-
-;;;;; paredit
+;;;; nix
+(custom-set-variables '(nix-indent-function #'nix-indent-line))
+;;;; gitlab-ci.yml
+(with-eval-after-load 'git-gutter-fringe
+              (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated)
+                "XXX....."))
 
-;; Balanced parentheses in lisps are nice, but all the refactoring and
-;; movement commands are much more interesting.
+(custom-set-variables '(gitlab-ci-url "https://gitlab.satoshipay.tech"))
+(use-package gitlab-ci-mode-flycheck
+  :ghook ('gitlab-ci-mode-hook (list #'gitlab-ci-mode-flycheck-enable
+                                     #'flycheck-mode)))
 
-(use-package paredit
-  :config (progn
-            (add-hook 'lisp-mode-common-hook #'enable-paredit-mode)
-            (put #'paredit-forward-delete 'delete-selection 'supersede)
-            (put #'paredit-backward-delete 'delete-selection 'supersede)
-            (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)))
+;;;; *ignore
+(use-package gitignore-mode
+  :mode ((".dockerignore\\'" . gitignore-mode)))
 
-;;;;; undo-tree
+;;;; kubernetes
+(custom-set-variables '(k8s-site-docs-version "v1.13"))
 
-;; Emacs’ default handling of undo is a bit confusing.  Undo-tree makes
-;; it much clearer.  It’s especially helpful for protoyping and refactoring.
+;;;; beancount
 
-(use-package undo-tree
-  :config (progn
-            (global-undo-tree-mode)
-            ;; Keep region when undoing in region
-            (defadvice undo-tree-undo (around keep-region activate)
-              (if (use-region-p)
-                  (let ((m (set-marker (make-marker) (mark)))
-                        (p (set-marker (make-marker) (point))))
-                    ad-do-it
-                    (goto-char p)
-                    (set-mark m)
-                    (set-marker p nil)
-                    (set-marker m nil))
-                ad-do-it))))
-
-;;;;; replace
-
-(with-eval-after-load "replace.el"
-  (setq case-replace nil))
-
-;;;; Evil
-
-(setq evil-want-keybinding nil)
-
-(use-package evil-leader
-  ;; must load before evil-mode
-  :init (global-evil-leader-mode +1)
-  :config (progn
-            (evil-leader/set-leader ",")
-            (evil-leader/set-key
-              "h" help-map
-              "w" evil-window-map
-              "x" ctl-x-map
-              "s" #'save-buffer
-              "q" #'kill-or-delete-this-buffer-dwim
-              "p" projectile-command-map
-              "v" #'split-window-right
-              "o" #'other-window
-              "y" #'evil-avy-goto-line
-              "bb" #'ivy-switch-buffer
-              "bx" #'kill-this-buffer
-              "br" #'revert-buffer
-              "dd" #'dired
-              "fs" #'save-buffer
-              "ff" #'find-file
-              "fw" #'write-file
-              "fd" #'crux-delete-file-and-buffer
-              "fr" #'crux-rename-file-and-buffer
-              "gs" #'magit-status
-              "gm" #'magit-dispatch-popup
-              "gt" #'git-timemachine
-              "bb" #'evil-switch-to-windows-last-buffer
-              "bi" #'ibuffer
-              "bz" #'bury-buffer
-              ";" #'counsel-M-x)))
+(use-package beancount
+  :load-path "~/projects/bitbucket.org/blais/beancount/editors/emacs")
 
-(use-package evil
-  :defines evil-window-map
-  :config (progn
-            (evil-mode +1)
-            (setq-default evil-shift-width 2)
-            (bind-keys :map evil-normal-state-map
-                       (";" . evil-ex))
-            (define-key evil-motion-state-map (kbd "C-;") #'evil-avy-goto-line)
-            (define-key evil-normal-state-map [escape] #'keyboard-quit)
-            (define-key evil-visual-state-map [escape] #'keyboard-quit)
-            (define-key evil-window-map (kbd "q") #'kill-or-delete-this-buffer-dwim)
-            (define-key minibuffer-local-map [escape] #'minibuffer-keyboard-quit)
-            (define-key minibuffer-local-ns-map [escape] #'minibuffer-keyboard-quit)
-            (define-key minibuffer-local-completion-map [escape] #'minibuffer-keyboard-quit)
-            (define-key minibuffer-local-must-match-map [escape] #'minibuffer-keyboard-quit)
-            (define-key minibuffer-local-isearch-map [escape] #'minibuffer-keyboard-quit)
-            (evil-define-key 'normal emacs-lisp-mode-map (kbd "K") #'elisp-slime-nav-describe-elisp-thing-at-point)))
+;;;; org
 
-(use-package evil-collection
-  :if evil-mode
-  :init (progn
-          (setq evil-collection-company-use-tng nil))
-  :config (evil-collection-init))
+(custom-set-variables '(org-ellipsis "…")
+                      `(org-directory "~/Documents/org"))
 
-(use-package evil-commentary
-  :if evil-mode
-  :config (evil-commentary-mode +1))
+(use-package org-journal
+  :gfhook (#'variable-pitch-mode)
+  :custom ((org-journal-date-format "%A, %d %B %Y")
+           (org-journal-dir "~/Documents/journal")))
 
-(use-package evil-magit
-  :if evil-mode
-  :defines (evil-magit-use-y-for-yank)
-  :after magit
-  :config (progn
-            (setq evil-magit-use-y-for-yank nil)))
+;;;; emacs-lisp
 
-(use-package evil-quickscope
-  :if evil-mode
-  :config (progn
-            (global-evil-quickscope-mode +1)))
+(use-package auto-async-byte-compile
+  :ghook ('emacs-lisp-mode-hook #'enable-auto-async-byte-compile-mode))
 
-(use-package evil-org
-  :if evil-mode
-  :config (progn
-            (define-hook-helper org-mode ()
-              (evil-org-mode +1))
-            (define-hook-helper evil-org-mode ()
-              (when (fboundp 'evil-org-set-key-theme)
-                (evil-org-set-key-theme)))))
+;;;; web modes (tsx, html)
 
-(use-package evil-org-agenda
-  :if evil-mode
-  :after evil-org
-  :functions (evil-org-agenda-set-keys)
-  :config (progn
-            (require 'evil-org-agenda)
-            (evil-org-agenda-set-keys)))
+(use-package web-mode
+  :mode (("\\.tsx" . web-mode))
+  :custom ((web-mode-enable-auto-pairing nil)
+           (web-mode-code-indent-offset 2)
+           (web-mode-markup-indent-offset 2)
+           (web-mode-css-indent-offset 2)
+           (web-mode-style-padding 0)
+           (web-mode-script-padding 0)))
+
+;;; IDE features
+
+(fringe-helper-define 'left-vertical-bar '(center repeated)
+  "XXX.....")
+(use-package flymake
+  :custom ((flymake-error-bitmap '(left-vertical-bar compilation-error))
+           (flymake-warning-bitmap '(left-vertical-bar compilation-warning))))
+
+(use-package lsp-mode
+  :ghook ('typescript-mode-hook #'lsp)
+  :custom ((lsp-auto-guess-root t)
+           (lsp-prefer-flymake t)
+           (lsp-enable-symbol-highlighting nil)))
+
+(use-package lsp-ui
+  :after lsp-mode
+  :ghook ('lsp-mode-hook)
+  :custom ((lsp-ui-sideline-enable nil)))
 
-(use-package evil-snipe
-  :defines (evil-snipe-scope)
-  :if evil-mode
-  :config (progn
-            (setq evil-snipe-scope 'visible)
-            (evil-snipe-mode +1)
-            (add-hook 'magit-mode-hook #'turn-off-evil-snipe-override-mode)))
+;; Inside a javascript project, it's common to install tools locally to
+;; the project.  This will allows emacs to find their executables.
 
-(use-package evil-surround
-  :if evil-mode
-  :config (progn
-            (global-evil-surround-mode +1)))
+(use-package add-node-modules-path
+  :ghook ('(js2-mode-hook
+            typescript-mode-hook) #'add-node-modules-path))
 
-(use-package evil-space
-  :if evil-mode
-  :config (progn
-            (evil-space-mode +1)))
+;;;; Reformat on save
 
-(use-package sentence-navigation
-  :if (and evil-mode (boundp 'sentence-nav-evil-forward))
-  :config (progn
-            (define-key evil-motion-state-map ")" #'sentence-nav-evil-forward)
-            (define-key evil-motion-state-map "(" #'sentence-nav-evil-backward)
-            (define-key evil-motion-state-map "g)" #'sentence-nav-evil-forward-end)
-            (define-key evil-motion-state-map "g(" #'sentence-nav-evil-backward-end)
-            (define-key evil-outer-text-objects-map "s" #'sentence-nav-evil-a-sentence)
-            (define-key evil-inner-text-objects-map "s" #'sentence-nav-evil-inner-sentence)))
-
-;;;; End
-
-;; Start a server if possible.  A daemon is already a server.
-(use-package server
-  :defer 2
-  :if (not (daemonp))
-  :config (unless (server-running-p server-name)
-            (server-start)))
+(use-package prettier-js
+  :ghook ('(typescript-mode-hook js2-mode-hook) #'prettier-js-mode t))
+
+;;; Take me to my leader
+
+(my-leader-def
+ :keymaps 'normal
+ "h" '(:keymap ehelp-map)
+ "w" '(:keymap evil-window-map)
+ "x" '(:keymap ctl-x-map)
+ "q" #'evil-delete-buffer
+ "p" projectile-command-map
+ "v" #'split-window-right
+ "o" #'other-window
+ "u" #'universal-argument
+ ";" #'counsel-M-x
+ "bb" #'ivy-switch-buffer
+ "bx" #'kill-this-buffer
+ "br" #'revert-buffer
+ "dd" #'dired
+ "fs" #'save-buffer
+ "ff" #'find-file
+ "fw" #'write-file
+ "fd" #'crux-delete-file-and-buffer
+ "fr" #'crux-rename-file-and-buffer
+ "gs" #'magit-status
+ "gm" #'git-messenger:popup-message
+ "gg" #'magit-dispatch
+ "gn" #'git-gutter:next-hunk
+ "gp" #'git-gutter:previous-hunk
+ "gi" #'git-gutter:popup-hunk
+ "gs" #'git-gutter:stage-hunk
+ "go" #'git-gutter:revert-hunk
+ "gt" #'git-timemachine
+ "bi" #'ibuffer
+ "bz" #'bury-buffer
+ "iu" #'counsel-unicode-char)
 
 ;; # Local Variables:
-;; # lentic-init: lentic-orgel-org-init
 ;; # flycheck-disabled-checkers: 'emacs-lisp-checkdoc
 ;; # End: