#+TITLE: Emacs Configuration for Alan Pearce #+OPTIONS: ^:nil #+PROPERTY: results silent #+PROPERTY: eval no-export #+PROPERTY: header-args :comments link * Introduction This is a living document, detailing my Emacs configuration using org-mode * Basics ** Startup Open Emacs with just a plain window. No graphics or messages, please! #+BEGIN_SRC emacs-lisp (put 'inhibit-startup-echo-area-message 'saved-value (setq inhibit-startup-echo-area-message (user-login-name))) (setq inhibit-startup-screen t) (setq gc-cons-threshold 100000000) (defvar file-name-handler-alist-backup file-name-handler-alist) (setq file-name-handler-alist nil) (remove-hook 'find-file-hooks #'vc-refresh-state) #+END_SRC ** Compatibility #+BEGIN_SRC emacs-lisp (if (version< emacs-version "25.0") (defmacro with-eval-after-load (file &rest body) `(eval-after-load ,file (lambda () ,@body)))) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (setq initial-scratch-message "" initial-major-mode 'text-mode) #+END_SRC ** Personal Information #+BEGIN_SRC emacs-lisp (setq user-mail-address "alan@alanpearce.co.uk" user-full-name "Alan Pearce") #+end_src * Packaging ** Use-package #+BEGIN_SRC emacs-lisp (eval-and-compile (setq tls-checktrust t gnutls-verify-error t package-archives '(("gnu" . "https://elpa.gnu.org/packages/") ("melpa-stable" . "https://stable.melpa.org/packages/") ("melpa" . "https://melpa.org/packages/")) package-user-dir (concat "~/.emacs.d/packages/" emacs-version "/elpa") package-pinned-packages '(("use-package" . melpa-stable) ("diminish" . melpa-stable) ("bind-key" . melpa-stable)) package-archive-priorities '(("melpa-stable" . 10) ("gnu" . 10) ("marmalade" . 5) ("melpa" . 0)) package-menu-async t package-menu-hide-low-priority t) (package-initialize) (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package))) (eval-when-compile (require 'use-package)) (unless (featurep 'use-package) (require 'diminish) (require 'bind-key) (use-package use-package :commands (use-package-autoload-keymap) :defer 5)) (setq use-package-verbose t use-package-always-ensure t package-enable-at-startup nil) #+END_SRC * 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= #+BEGIN_SRC emacs-lisp (setq custom-file "~/.emacs.d/custom.el") (load custom-file :noerror :nomessage) #+END_SRC * Styles I prefer an always-visible cursor. Feels less distracting. #+BEGIN_SRC emacs-lisp (when (fboundp #'blink-cursor-mode) (blink-cursor-mode -1)) #+END_SRC Disable all the bars, unless on OSX, in which case, keep the menu bar. #+BEGIN_SRC emacs-lisp (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)) #+END_SRC Ring the bell sometimes, but not so often #+BEGIN_SRC emacs-lisp (setq ring-bell-function (lambda () (unless (memq this-command '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit undo-tree-undo)) (ding)))) #+END_SRC ** Colours Let’s try a more minimal theme. #+BEGIN_SRC emacs-lisp (use-package minimal-theme :disabled t :config (progn (load-theme 'minimal-light t))) #+END_SRC Let’s try a basic theme. #+BEGIN_SRC emacs-lisp (use-package basic-theme :if (display-graphic-p) :config (progn (load-theme 'basic t) (set-face-background 'mode-line "#a1b56c") (set-face-background 'border "#a1b56c") (set-face-foreground 'border "#a1b56c") (set-face-background 'vertical-border "#a1b56c") (set-face-foreground 'vertical-border "#a1b56c") (set-face-background 'window-divider "#a1b56c") (set-face-foreground 'window-divider "#a1b56c") (defvar mode-line-default-format mode-line-format) (defvar mode-line-default-hidden nil "Whether to hide the mode line by default") (defun show-mode-line () (interactive) (setq mode-line-format mode-line-default-format) (when (called-interactively-p 'interactive) (setq-default mode-line-format mode-line-default-format) (setq mode-line-default-hidden nil))) (defun hide-mode-line () (interactive) (setq mode-line-format nil) (when (called-interactively-p 'interactive) (setq-default mode-line-format nil) (setq mode-line-default-hidden t))) (setq-default cursor-type '(bar . 1)) (setq-default cursor-in-non-selected-windows nil) (defun hide-clutter () (interactive) (fringe-mode '(0 . 4)) (hide-mode-line)) (defun show-clutter () (interactive) (fringe-mode '(8 . 4)) (show-mode-line)) (hide-clutter) (when mode-line-default-hidden (call-interactively #'hide-mode-line)) (defun hide-mode-line-if-default-hidden () (if mode-line-default-hidden (hide-mode-line) (show-mode-line))) (add-to-list 'default-frame-alist '(border-width . 0)) (add-to-list 'default-frame-alist '(internal-border-width . 1)) (when (eq window-system 'x) (setq window-divider-default-bottom-width 1 window-divider-default-right-width 1 window-divider-default-places t) (setq mode-line-default-hidden t) (window-divider-mode +1)) (add-hook 'after-change-major-mode-hook #'hide-mode-line-if-default-hidden) (add-hook 'minibuffer-setup-hook #'show-mode-line) (add-hook 'minibuffer-exit-hook #'hide-mode-line))) #+END_SRC 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. #+BEGIN_SRC emacs-lisp (use-package highlight-stages :diminish highlight-stages-mode) #+END_SRC ** 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]]. #+BEGIN_SRC emacs-lisp (when (or (display-graphic-p) (daemonp)) (defun use-variable-fonts () (interactive) (variable-pitch-mode) (setq cursor-type 'bar)) (defun ap/set-fonts (mono-face mono-font-size variable-face variable-font-size antialias) (if (boundp 'ns-antialias-text) (setq ns-antialias-text antialias)) (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)) ((eq window-system 'ns) (let ((displays (string-to-number (shell-command-to-string "system_profiler SPDisplaysDataType | grep \"Online: Yes\" | wc -l")))) (if (eq displays 1) (ap/set-fonts "Roboto Mono" 13 "Lucida Grande" 13 t) (ap/set-fonts "Monaco" 10 "Lucida Grande" 12 nil)))) ((eq window-system 'x) (set-fontset-font "fontset-default" 'unicode (font-spec :name "Terminus" :size 8)) (ap/set-fonts "Fixed" 8 "Lucida" 8 nil)))) (ap/set-fonts-according-to-system)) #+END_SRC Reduce font decoration. I’m trying to see whether this helps me focus on the right things. #+BEGIN_SRC emacs-lisp (setq font-lock-maximum-decoration '((dired-mode . 1) (t . 1))) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (use-package page-break-lines :defer 5 :diminish page-break-lines-mode :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))))) #+END_SRC ** Modeline #+BEGIN_SRC emacs-lisp (column-number-mode t) (size-indication-mode t) (setq frame-title-format '("%f" (dired-directory dired-directory))) #+END_SRC ** Highlight Changes Highlight what just changed when I undo, yank, and so on. #+BEGIN_SRC emacs-lisp (use-package volatile-highlights :diminish volatile-highlights-mode :config (progn (volatile-highlights-mode t))) #+END_SRC ** Beacon I was against the idea of having flashy animations inside Emacs, but this one is useful. It highlights the cursor when scrolling or switching windows. #+BEGIN_SRC emacs-lisp (use-package beacon :diminish beacon-mode :config (progn (beacon-mode +1) (setq beacon-blink-delay 0.25 beacon-blink-duration 0.25 beacon-size 20 beacon-color "#a1b56c"))) #+END_SRC ** Renaming major modes Diminishing major modes does not happen in the same manner as minor modes. #+BEGIN_SRC emacs-lisp (unless (version<= emacs-version "24.4") (use-package cyphejor :defer 2 :config (progn (setq cyphejor-rules `(("emacs" "ε") ("diff" "Δ") ("js2" "js") ("magit-status" ,(char-to-string (seq-find #'char-displayable-p '(11942 5848 177)))) ("inferior" "i" :prefix) ("interaction" "i" :prefix) ("interactive" "i" :prefix) ("menu" "▤" :postfix) ("ledger" "Ledger") ("mode" "") ("shell" "sh" :postfix))) (cyphejor-mode 1)))) #+END_SRC * 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. #+BEGIN_SRC emacs-lisp (use-package exec-path-from-shell :if (eq system-type 'darwin) :config (exec-path-from-shell-initialize)) #+END_SRC * Keybindings I think =set-keyboard-coding-system= stops OS X from doing something annoying to add accents. The modifier setup is to match my re-arrangement of modifiers on OSX: Cmd on the outside, then Option/alt, then Control. #+BEGIN_SRC emacs-lisp (when (eq system-type 'darwin) (set-keyboard-coding-system nil) (custom-set-variables '(mac-option-modifier 'meta) '(mac-right-option-modifier 'none) '(mac-control-modifier 'control) '(mac-right-control-modifier 'left) '(mac-command-modifier 'super) '(mac-right-command-modifier 'left) '(mac-function-modifier 'hyper)) (unbind-key "s-x")) #+END_SRC #+BEGIN_SRC emacs-lisp (unbind-key "") (bind-key* "" #'compile) (bind-key* "" #'kmacro-start-macro-or-insert-counter) (bind-key* "" #'kmacro-end-or-call-macro) (bind-key* "" #'execute-extended-command) (unbind-key "C-z") (bind-key* "C-" #'other-window) (bind-key* "C-x C-r" #'revert-buffer) (bind-key* "C-x C-j" #'delete-indentation) (unbind-key "C-x C-c") (bind-key* "C-c i" #'insert-char) (bind-key* "M-/" #'hippie-expand) (unbind-key "s-h") (unbind-key "s-n") (unbind-key "s-p") (unbind-key "s-w") (bind-key* "s-k" #'kill-or-delete-this-buffer-dwim) (bind-key "C-M-a" #'backward-paragraph text-mode-map) (bind-key "C-M-e" #'forward-paragraph text-mode-map) (bind-key* "s-x" (define-prefix-command 'super-x-map)) (bind-key* "s-," #'switch-to-dotfiles) (bind-key* "C-M-x" #'execute-extended-command) (set-register ?z `(file . ,(expand-file-name ".config/zsh/zshrc" "~"))) #+END_SRC ** Crux I can replace most of the simple helper/wrapper functions in my configuration with crux.el #+BEGIN_SRC emacs-lisp (use-package crux :bind (("M-o" . crux-smart-open-line-above) ("C-o" . crux-smart-open-line) ("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)) :init (progn (defalias 'delete-current-buffer-file #'crux-delete-file-and-buffer) (defalias 'rename-current-buffer-file #'crux-rename-file-and-buffer))) #+END_SRC * Projects #+BEGIN_SRC emacs-lisp (defvar projects-root-directory "~/projects") #+END_SRC #+BEGIN_SRC emacs-lisp (defun switch-to-dotfiles () (interactive) (projectile-switch-project-by-name (expand-file-name "~/projects/git.alanpearce.uk/alan/dotfiles/"))) #+END_SRC ** The Silver Searcher #+BEGIN_SRC emacs-lisp (use-package ag :defer 30 :config (setq ag-project-root-function #'projectile-project-root)) (use-package wgrep-ag :after ag) #+END_SRC ** Ripgrep Step over Silver Search, here comes a new challenger. #+BEGIN_SRC emacs-lisp (use-package ripgrep :if (executable-find "rg")) (use-package projectile-ripgrep :after (ripgrep projectile) :if (executable-find "rg") :bind (("C-c p s r" . projectile-ripgrep))) #+END_SRC ** Projectile Projectile is awesome for working in projects, especially VCS-backed ones. I added a couple of functions to allow me to open new projects based upon some folder conventions I use. #+BEGIN_SRC emacs-lisp (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) ("s-G" . projectile-vc)) :demand t :diminish projectile-mode :config (progn (projectile-global-mode) (add-to-list 'projectile-globally-ignored-directories ".stversions") (defun directory-directories (dir) (seq-filter #'file-directory-p (directory-files dir t (rx string-start (char alnum))))) (defun project-directories (start-dir) (seq-map (lambda (x) (file-relative-name x start-dir)) (seq-mapcat #'directory-directories (seq-mapcat #'directory-directories (directory-directories start-dir))))) (defun ap/open-subfolder-project (from-dir &optional arg) (let ((project-dir (projectile-completing-read "Open project: " (project-directories from-dir)))) (projectile-switch-project-by-name (expand-file-name project-dir from-dir) arg))) (defun yarn-install (&optional arg) (interactive "P") (projectile-with-default-dir (projectile-project-root) (cmd-to-echo "yarn" "install"))) (defun yarn-add-dev (package) (interactive "spackage: ") (projectile-with-default-dir (projectile-project-root) (cmd-to-echo "yarn" (concat "add --dev " package)))) (defun yarn-add (package) (interactive "spackage: ") (projectile-with-default-dir (projectile-project-root) (cmd-to-echo "yarn" (concat "add " package)))) (defun yarn-run (cmd) (interactive "scommand: ") (projectile-with-default-dir (projectile-project-root) (cmd-to-echo "yarn" (concat "run " cmd)))) (defun ap/open-project (&optional arg) (interactive "P") (ap/open-subfolder-project projects-root-directory arg)) (setq projectile-switch-project-action #'projectile-commander projectile-completion-system 'ivy))) #+END_SRC ** vc 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. #+BEGIN_SRC emacs-lisp (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)))) #+END_SRC ** git-gutter-fringe 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. #+BEGIN_SRC emacs-lisp (use-package git-gutter-fringe :defer 2 :diminish git-gutter-mode :config (progn (global-git-gutter-mode 1) (set-face-foreground 'git-gutter:modified "grey") (setq git-gutter-fr:side 'right-fringe))) #+END_SRC ** 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= #+BEGIN_SRC emacs-lisp (use-package magit :defer 5 :commands (magit-status) :config (progn (setq magit-completing-read-function #'ivy-completing-read magit-popup-use-prefix-argument 'default magit-display-buffer-function #'magit-display-buffer-fullcolumn-most-v1 global-magit-file-mode nil) (add-to-list 'magit-no-confirm 'safe-with-wip)) :init (add-hook 'magit-mode-hook #'magit-load-config-extensions)) #+END_SRC ** git-timemachine 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. #+BEGIN_SRC emacs-lisp (use-package git-timemachine :commands git-timemachine) #+END_SRC ** ghq [[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. #+BEGIN_SRC emacs-lisp (use-package ghq :if (executable-find "ghq")) #+END_SRC * Files ** Auto-saving Auto-save everything to a temporary directory, instead of cluttering the filesystem. I don’t want emacs-specific lockfiles, either. #+BEGIN_SRC emacs-lisp (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) create-lockfiles nil) #+END_SRC ** 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 trash for deleting on OS X. #+BEGIN_SRC emacs-lisp (let ((backup-dir (expand-file-name "~/.emacs.d/backups/"))) (unless (file-directory-p backup-dir) (make-directory backup-dir)) (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))) (defun system-move-file-to-trash (file) (call-process (executable-find "trash") nil 0 nil file)))) #+END_SRC ** autorevert #+BEGIN_SRC emacs-lisp (use-package autorevert :diminish auto-revert-mode :init (progn (global-auto-revert-mode 1) (setq auto-revert-verbose nil auto-revert-use-notify (not (eq system-type 'darwin))))) #+END_SRC ** Encoding UTF-8 is usually appropriate. Note that =prefer-coding-system= expects only a coding system, not a coding system and line ending combination. #+BEGIN_SRC emacs-lisp (prefer-coding-system 'utf-8) (setq-default buffer-file-coding-system 'utf-8-auto-unix) #+END_SRC ** Buffer-file management Ask if I want to create a directory when it doesn’t exist. This is especially nice when starting new projects. #+BEGIN_SRC emacs-lisp (defun my-create-non-existent-directory () (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) #+END_SRC I often want to rename or delete the file that I’m currently visiting with a buffer. #+BEGIN_SRC emacs-lisp (defun kill-or-delete-this-buffer-dwim (&optional arg) "Kills current buffer. With prefix arg, delete it." (interactive "P") (if (equal arg '(4)) (delete-current-buffer-file) (if server-buffer-clients (server-edit) (let ((buf (buffer-name))) (when (equal buf "*HTTP Response*") (other-window 1)) (kill-buffer buf))))) #+END_SRC ** Whitespace Butler I don’t like it when editors change an entire file’s layout when I open it. Whitespace butler fixes whitespace only for lines that I’m editing. #+BEGIN_SRC emacs-lisp (use-package ws-butler :if window-system :diminish ws-butler-mode :config (ws-butler-global-mode 1)) (if (daemonp) (add-hook 'before-make-frame-hook (lambda () (use-package ws-butler :config (ws-butler-global-mode 1))))) #+END_SRC ** shrink-whitespace DWIM whitespace removal. So I don’t need =M-SPC=, =M-\= and =C-x o= for similar things any more. #+BEGIN_SRC emacs-lisp (use-package shrink-whitespace :bind ("M-SPC" . shrink-whitespace)) #+END_SRC ** Tramp Tramp is awesome. It makes SSH feel Unix-y. The proxy setup is so that I can sudo on remote machines #+BEGIN_SRC emacs-lisp (use-package tramp :defer 7 :config (progn (unless (getenv "SSH_AUTH_SOCK") (setenv "SSH_AUTH_SOCK" (format "/run/user/%s/ssh-agent" (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)))) (use-package tramp-sh :ensure nil :defer t :config (progn (add-to-list 'tramp-remote-path "/usr/local/sbin") (add-to-list 'tramp-remote-path "~/bin"))) #+END_SRC ** ediff I like a horizonal diff setup, with everything in one frame. #+BEGIN_SRC emacs-lisp (use-package ediff :defer t :config (progn (setq ediff-split-window-function 'split-window-horizontally ediff-window-setup-function 'ediff-setup-windows-plain))) #+END_SRC * 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. #+BEGIN_SRC emacs-lisp (setq-default tab-width 2 indent-tabs-mode nil) #+END_SRC ** smart-tabs-mode Not related to [[smart-tab][=smart-tab=]], this mode indents with tabs and aligns with spaces. Perfect! #+BEGIN_SRC emacs-lisp (use-package smart-tabs-mode :defer 1 :config (progn (smart-tabs-insinuate 'c 'cperl 'python) (add-hook 'php-mode-hook (lambda () (smart-tabs-mode indent-tabs-mode))))) #+END_SRC ** editorconfig #+BEGIN_SRC emacs-lisp (use-package editorconfig :config (editorconfig-mode 1)) #+END_SRC ** dtrt-indent-mode Sometimes people use different indentation settings. [[https://github.com/jscheid/dtrt-indent][dtrt-indent]] guesses the correct settings for me. #+BEGIN_SRC emacs-lisp (use-package dtrt-indent :config (progn (defun ap/dtrt-adapt-if-needed () (unless editorconfig-mode (dtrt-indent-adapt))) (if (fboundp #'editorconfig-mode) (add-hook 'after-change-major-mode-hook #'ap/dtrt-adapt-if-needed) (add-hook 'after-change-major-mode-hook #'dtrt-indent-adapt)) (defadvice dtrt-indent-try-set-offset (after toggle-smart-tabs activate) (smart-tabs-mode (or indent-tabs-mode -1))))) #+END_SRC * Security ** password-store This is a frontend to the GPG-powered =pass= program. #+BEGIN_SRC emacs-lisp (use-package password-store :defer 15 :config (progn (setq password-store-password-length 16))) #+END_SRC * Buffers ** Ibuffer Ibuffer is quite nice for listing all buffers. #+BEGIN_SRC emacs-lisp (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))))) #+END_SRC ** Relative Buffer names #+BEGIN_SRC emacs-lisp (use-package relative-buffers :defer 15 :config (progn (global-relative-buffers-mode))) #+END_SRC ** Narrowing Enable it without prompting #+BEGIN_SRC emacs-lisp (put 'narrow-to-defun 'disabled nil) (put 'narrow-to-page 'disabled nil) (put 'narrow-to-region 'disabled nil) #+END_SRC ** ace-window I don’t often have many windows open at once, but when I do, =ace-window= is really nice to jump around them in the same way that =ace-jump= or =avy= work. #+BEGIN_SRC emacs-lisp (use-package ace-window :bind (("s-s" . ace-window)) :config (progn (setq aw-dispatch-always t aw-dispatch-alist '((?k aw-delete-window " Ace - Delete Window") (?K aw-delete-window) (?m aw-swap-window " Ace - Swap Window") (?f aw-flip-window) (?v aw-split-window-vert " Ace - Split Vert Window") (?b aw-split-window-horz " Ace - Split Horz Window") (?m delete-other-windows " Ace - Maximize Window") (?l delete-other-windows) (?, winner-undo) (?. winner-redo)) aw-keys '(?a ?r ?s ?t ?n ?e ?i ?o)))) #+END_SRC * Windows Scrolling is tricky. I use this setup to help me keep track of the point whilst I’m moving about. #+BEGIN_SRC emacs-lisp (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)) #+END_SRC ** winner Undo, for window-based commands. #+BEGIN_SRC emacs-lisp (use-package winner :config (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")) :init (progn (winner-mode 1))) #+END_SRC ** windmove Directional window movement #+BEGIN_SRC emacs-lisp (use-package windmove :bind (("S-" . windmove-left) ("S-" . windmove-right) ("S-" . windmove-up) ("S-" . windmove-down))) #+END_SRC * Completion Make built-in completion a bit more intelligent, by adding substring and initial-based completion and ignoring case. #+BEGIN_SRC emacs-lisp (setq completion-styles '(basic initials partial-completion substring) completion-ignore-case t tab-always-indent 'complete) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (use-package company :commands (company-mode) :diminish "Cmpl" :bind (("C-" . company-complete) ("TAB" . company-indent-or-complete-common)) :init (progn (add-hook 'prog-mode-hook #'company-mode) (setq company-backends '(company-bbdb company-web-html 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))) #+END_SRC #+BEGIN_SRC emacs-lisp (use-package company-web :after company) #+END_SRC #+BEGIN_SRC emacs-lisp (use-package company-nixos-options :if (eq system-type 'gnu/linux) :config (progn (add-to-list 'company-backends 'company-nixos-options))) #+END_SRC * Dates & Times ** Calendar Weeks start on Monday for me and I prefer ISO-style dates. #+BEGIN_SRC emacs-lisp (use-package calendar :defer 1 :config (progn (setq calendar-week-start-day 1) (calendar-set-date-style 'iso))) #+END_SRC Sometimes I want to insert a date or time into a buffer. #+BEGIN_SRC emacs-lisp (defun insert-date (prefix) "Insert the current date. With prefix-argument, 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 the current date and time." (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)))) #+END_SRC #+BEGIN_SRC emacs-lisp (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)) #+END_SRC * 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. #+BEGIN_SRC emacs-lisp (use-package dired :defer 3 :ensure nil :config (progn (bind-key "" #'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 '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))) #+END_SRC Don’t show uninteresting files in dired listings. #+BEGIN_SRC emacs-lisp (defun turn-on-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))) #+END_SRC #+BEGIN_SRC emacs-lisp (use-package dired+ :defer 5 :config (progn (diredp-toggle-find-file-reuse-dir 1) (unbind-key "C-h C-m" dired-mode-map))) #+END_SRC Expand subfolders like a tree inside the parent #+BEGIN_SRC emacs-lisp (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)))) #+END_SRC ** Dired-narrow One can already use dired with wildcards to browse a filtered directory listing, but it opens a new buffer. Dired-narrow is a slightly nicer interface: with a currently-open dired buffer, use =/= to start filtering, =RET= to complete the filter and =g= to refresh the buffer, removing the filter. #+BEGIN_SRC emacs-lisp (with-eval-after-load 'dired (use-package dired-narrow :bind (:map dired-mode-map ("/" . dired-narrow)))) #+END_SRC * 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. #+BEGIN_SRC emacs-lisp (use-package ehelp :bind-keymap ("C-h" . ehelp-map)) #+END_SRC ** counsel-dash Emacs’ documentation is great to read from inside Emacs. Counsel-dash helps to make documentation for other languages easier to access #+BEGIN_SRC emacs-lisp (defmacro ap/create-counsel-dash-hook (mode docsets) (let* ((mode-s (symbol-name mode)) (fun (intern (concat "counsel-dash-hook-" mode-s))) (hook (intern (concat mode-s "-mode-hook")))) `(progn (defun ,fun () (when (require 'counsel-dash nil :noerror) (seq-map #'counsel-dash-install-docset (seq-difference ',docsets (helm-dash-installed-docsets))) (setq-local counsel-dash-docsets ',docsets))) (add-hook (quote ,hook) (function ,fun))))) (use-package counsel-dash :defer 20 :defines counsel-dash-docsets :config (progn (setq counsel-dash-browser-func #'eww) (ap/create-counsel-dash-hook nginx ("Nginx")) (ap/create-counsel-dash-hook ansible ("Ansible")) (ap/create-counsel-dash-hook php ("PHP" "Symfony")) (ap/create-counsel-dash-hook twig ("Twig")) (ap/create-counsel-dash-hook js2 ("JavaScript" "NodeJS" "jQuery" "Express" "SailsJS" "Lo-Dash")) (ap/create-counsel-dash-hook markdown ("Markdown")) (ap/create-counsel-dash-hook saltstack ("SaltStack")) (ap/create-counsel-dash-hook clojure ("Clojure")) (ap/create-counsel-dash-hook sql ("PostgreSQL" "MySQL")))) #+END_SRC ** discover-my-major A nicer way to browse keybindings for major modes. #+BEGIN_SRC emacs-lisp (use-package discover-my-major :bind ("" . discover-my-major)) #+END_SRC ** which-key Popup keybindings following a prefix automatically. #+BEGIN_SRC emacs-lisp (use-package which-key :diminish which-key-mode :config (progn (which-key-mode 1) (which-key-setup-side-window-right-bottom))) #+END_SRC ** eldoc Documentation in the echo-area (where the minibuffer is displayed) is rather useful. #+BEGIN_SRC emacs-lisp (use-package eldoc :commands (eldoc-mode) :diminish eldoc-mode :config (progn (setq eldoc-idle-delay 0.1) (eldoc-add-command 'paredit-backward-delete 'paredit-close-round))) #+END_SRC * Mail ** Gnus At work, I use gnus for email. Some of the setup is specific to my workplace, so I keep it in a host-specific, GPG-encrypted file. #+BEGIN_SRC emacs-lisp (use-package gnus :config (progn (setq gnus-gcc-mark-as-read t mml-secure-openpgp-encrypt-to-self t send-mail-function #'smtpmail-send-it message-send-mail-function #'smtpmail-send-it))) (with-eval-after-load 'gnus-mime (define-key gnus-mime-button-map " " #'gnus-mime-view-part-externally)) (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")) #+END_SRC ** BBDB As I'm using Emacs for email, it makes sense to have contact information here as well. #+BEGIN_SRC emacs-lisp (use-package bbdb :config (progn (bbdb-initialize 'gnus 'mail 'message 'pgp) (bbdb-mua-auto-update-init 'gnus 'message) (setq bbdb-send-mail-style 'gnus bbdb-complete-mail-allow-cycling t bbdb-mua-auto-update t bbdb-mua-update-interactive-p '(query . create) bbdb-message-all-addresses t bbdb-offer-save t bbdb-offer-to-create 1))) #+END_SRC * Misc #+BEGIN_SRC emacs-lisp (defvar *init-file* (let ((init-file (or user-init-file (expand-file-name "init.el" user-emacs-directory)))) (expand-file-name "init.el" (file-name-directory (file-truename init-file)))) "Where the emacs init file really is, passing through symlinks.") (set-register ?e `(file . ,*init-file*)) (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 "")))) (use-package rect :ensure nil :init (defun copy-rectangle (start end) "Copy the region-rectangle." (interactive "r") (setq killed-rectangle (extract-rectangle start end)))) (defun shell-execute (to-current-buffer) (interactive "P") (let ((file-buffer (if (buffer-file-name) (file-name-nondirectory (buffer-file-name)) "")) (command (read-shell-command "Shell command: " nil nil nil))) (shell-command (replace-regexp-in-string "%" file-buffer command) to-current-buffer))) (defun process-exit-code (program &rest args) "Run PROGRAM with ARGS and return the exit code" (apply 'call-process program nil nil nil args)) (defun narrow-to-region-indirect (start end) "Restrict editing in this buffer to the current region, indirectly." (interactive "r") (deactivate-mark) (let ((buf (clone-indirect-buffer nil nil))) (with-current-buffer buf (narrow-to-region start end)) (switch-to-buffer buf))) (bind-key* "M-!" #'shell-execute) (bind-key* "C-x r M-w" #'copy-rectangle) #+END_SRC ** Auxillary Configuration #+BEGIN_SRC emacs-lisp (require 'pinentry) (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) (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) (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 () (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))))) (defun first-frame-hook (frame) (remove-hook 'after-make-frame-functions #'first-frame-hook) (run-at-time nil nil 'load-private-data)) (if (eq 1 (length (frame-list))) (add-hook 'after-init-hook #'load-private-data) (add-hook 'after-make-frame-functions #'first-frame-hook)) #+END_SRC * 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. #+BEGIN_SRC emacs-lisp (setq enable-recursive-minibuffers t) (minibuffer-depth-indicate-mode t) #+END_SRC This avoids some issue with the minibuffer and the point being behind the prompt. I don’t remember what exactly. #+BEGIN_SRC emacs-lisp (setq minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt)) #+END_SRC Occasionally, I exit emacs. I should probably reduce the frequency of this. #+BEGIN_SRC emacs-lisp (if (daemonp) (defalias 'exit-emacs #'delete-frame) (defalias 'exit-emacs #'save-buffers-kill-emacs)) #+END_SRC ** swiper/ivy Ivy is the new kid on the completion block. It seems to be a strong replacement for helm so far. #+BEGIN_SRC emacs-lisp (use-package swiper :bind (("C-s" . swiper) ("C-r" . swiper) ("C-x i" . ivy-imenu-goto) ("C-=" . swiper)) :diminish ivy-mode :demand t :config (progn (ivy-mode 1) (setq ivy-re-builders-alist '((internal-complete-buffer . ivy--regex-fuzzy) (t . ivy--regex-plus))) (defun ivy-imenu-get-candidates-from (alist &optional prefix) (cl-loop for elm in alist nconc (if (imenu--subalist-p elm) (ivy-imenu-get-candidates-from (cl-loop for (e . v) in (cdr elm) collect (cons e (if (integerp v) (copy-marker v) v))) (concat prefix (if prefix ".") (car elm))) (and (cdr elm) ; bug in imenu, should not be needed. (setcdr elm (copy-marker (cdr elm))) ; Same as [1]. (list (cons (concat prefix (if prefix ".") (car elm)) (copy-marker (cdr elm)))))))) (defun ivy-imenu-goto () "Go to buffer position" (interactive) (let ((imenu-auto-rescan t) items) (unless (featurep 'imenu) (require 'imenu nil t)) (setq items (imenu--make-index-alist t)) (ivy-read "imenu items:" (ivy-imenu-get-candidates-from (delete (assoc "*Rescan*" items) items)) :action (lambda (k) (goto-char k))))) (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 . "")))) #+END_SRC ** counsel #+BEGIN_SRC emacs-lisp (use-package counsel :config (progn (bind-key "M-x" #'counsel-M-x) (bind-key "" #'counsel-M-x) (bind-key "" #'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 "M-y" #'ivy-next-line ivy-minibuffer-map) (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)))))) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (use-package smex :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")))) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (use-package cmd-to-echo :commands (cmd-to-echo) :config (setq cmd-to-echo-add-output-to-process-buffers t)) #+END_SRC * Modes Setup some modes for systemd files #+BEGIN_SRC emacs-lisp (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)) #+END_SRC =direnv=’s files are basically shell scripts, it’s a nice way to set environment variables for projects. #+BEGIN_SRC emacs-lisp (add-to-list 'auto-mode-alist '("\\.envrc\\'" . sh-mode)) #+END_SRC Some modes that I don’t really customise much, mostly for configuration files. #+BEGIN_SRC emacs-lisp (use-package xrdb-mode :ensure nil :mode (("\\.Xdefaults\\'" . xrdb-mode) ("\\.Xresources\\'" . xrdb-mode))) (use-package haskell-mode :mode (("\\.hs\\'" . haskell-mode))) (use-package dockerfile-mode :mode (("Dockerfile\\'" . dockerfile-mode))) (use-package nix-mode :mode (("\\.nix\\'" . nix-mode))) (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 lua-mode :defer t) (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 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)) #+END_SRC ** ledger I use [[http://ledger-cli.org/][=ledger=]] to manage my finances. It has an Emacs mode, which works really nicely. #+BEGIN_SRC emacs-lisp (use-package ledger-mode :mode ("\\.ledger\\'" . ledger-mode) :init (progn (defun open-budget () (interactive) (projectile-switch-project-by-name "~/Sync/Default") (find-file (expand-file-name "ledger/my.ledger" (projectile-project-root))) (ledger-report "Budget (Cumulative)" nil))) :config (progn (setq ledger-use-iso-dates t ledger-post-use-completion-engine :built-in ledger-reconcile-default-commodity "€" ledger-clear-whole-transactions t ledger-narrow-on-reconcile t ledger-default-date-format "%Y-%m-%d" ledger-reports '(("Monthly Expenses" "ledger -f %(ledger-file) reg -M Expenses --real -l \"payee != 'Opening Balances'\"") ("Expenses:This Month" "ledger -f %(ledger-file) bal \\^Expenses -p \"this month\"") ("On-budget Balances" "ledger -f %(ledger-file) bal --current -R :Budget: Assets:Receivable Liabilities:Personal") ("All Account Balances" "ledger -f %(ledger-file) bal --current -R \\^Assets \\^Liabilities") ("Budget Values (Current Month)" "ledger -f %(ledger-file) bal -p \"this month\" --limit \"payee=~/budget/\" \\^Funds") ("Budget (Cumulative)" "ledger -f %(ledger-file) bal -E \\^Funds \\^Assets:Budget$") ("Budget Allocation" "ledger -f %(ledger-file) bal -p \"this month\" --limit \"payee=~/budget/\" \\^Funds --format \"\\ %-17((depth_spacer)+(partial_account))\\ %10(percent(market(display_total), market(parent.total)))\\ %16(market(display_total))\n%/\"") ("bal" "ledger -f %(ledger-file) bal") ("reg" "ledger -f %(ledger-file) reg") ("equity" "ledger -f %(ledger-file) equity") ("payee" "ledger -f %(ledger-file) reg @%(payee)") ("account" "ledger -f %(ledger-file) reg %(account)"))))) #+END_SRC ** Markdown #+BEGIN_SRC emacs-lisp (use-package markdown-mode :defer t :config (progn (add-hook 'markdown-mode-hook #'turn-on-auto-fill))) #+END_SRC ** Org Org is wünderbar. #+BEGIN_SRC emacs-lisp (use-package org :bind (("C-c C-a" . org-agenda-list) ("C-c a" . org-agenda) ("C-c l" . org-store-link)) :defer 8 :init (setq org-replace-disputed-keys t org-ellipsis "…") :config (progn (setq org-directory "~/Sync/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-export-have-math t org-blank-before-new-entry '((heading . t) (plain-list-item . auto)) org-fontify-done-headline t 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))) #+END_SRC **** 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. #+BEGIN_SRC emacs-lisp (use-package ob-core :defer t :ensure nil :config (progn (org-babel-do-load-languages 'org-babel-load-languages '((ledger . t) (sh . t))) (setq org-src-tab-acts-natively t org-edit-src-content-indentation 0 org-src-preserve-indentation t))) #+END_SRC **** org-journal I can use this to keep a journal. I should use it. #+BEGIN_SRC emacs-lisp (use-package org-journal :bind ("s-j" . org-journal-new-entry) :defer 20 :config (progn (setq org-journal-date-format "%A, %d %B %Y") (defun org-journal-display-entry-yesterday () "Show org-journal entry for yesterday" (interactive) (org-journal-read-or-display-entry (yesterday-time))))) #+END_SRC **** org-mobile #+BEGIN_SRC emacs-lisp (defun ap/org-mobile-pull (descriptor action file) (org-mobile-pull)) (use-package org-mobile :defer 30 :ensure nil :disabled t :config (progn (setq org-mobile-directory "~/Mobile/Org" org-mobile-inbox-for-pull "~/Mobile/Org/from-mobile.org") (defvar org-mobile-push-timer nil "Timer that `org-mobile-push-timer' used to reschedule itself, or nil.") (defun org-mobile-push-with-delay (secs) (when org-mobile-push-timer (cancel-timer org-mobile-push-timer)) (setq org-mobile-push-timer (run-with-idle-timer (* 1 secs) nil 'org-mobile-push))) (add-hook 'after-save-hook (lambda () (when (eq major-mode 'org-mode) (dolist (file (org-mobile-files-alist)) (if (string= (file-truename (expand-file-name (car file))) (file-truename (buffer-file-name))) (org-mobile-push-with-delay 30)))))) (run-at-time "00:05" 86400 '(lambda () (org-mobile-push-with-delay 1))) ;; refreshes agenda file each day (org-mobile-pull) ;; run org-mobile-pull at startup (defvar org-mobile-watcher nil) (when file-notify--library (let ((org-file (expand-file-name (concat (file-name-as-directory org-mobile-directory) org-mobile-capture-file)))) (setq org-mobile-watcher (file-notify-add-watch org-file '(change) #'ap/org-mobile-pull)))))) #+END_SRC **** org-caldav I’ve setup CalDAV on my server, it would be nice to use it directly from org-mode. Previously I had to wait for org-mobile to sync and write to the Android calendar, and then for DAVDroid to sync with the server. #+BEGIN_SRC emacs-lisp (use-package org-caldav :defer 30 :config (progn (setq org-caldav-url "https://calendar.alanpearce.uk/alan" org-caldav-calendar-id "caldav" org-caldav-inbox (concat org-directory "/agenda/caldav.org") org-caldav-files `(,(concat org-directory "/agenda/organiser.org")) org-icalendar-timezone "Europe/Berlin" org-icalendar-use-scheduled '(event-if-todo event-if-not-todo todo-start) org-icalendar-use-deadline '(event-if-todo event-if-not-todo todo-due) org-icalendar-alarm-time 60))) #+END_SRC **** org-page I would like to convert my website from using hugo to something else that I can work with nicely from inside Emacs. I wonder if org-page will do the trick. #+BEGIN_SRC emacs-lisp (use-package org-page :config (progn (setq op/site-domain "https://alanpearce.uk/" op/repository-directory "~/projects/alanpearce/" op/personal-github-link "https://github.com/alanpearce"))) #+END_SRC * Music Emacs actually supports playing music via mpd. #+BEGIN_SRC emacs-lisp (use-package mpc :defer t :config (progn (setq mpc-browser-tags '(Genre Albumartist|Composer|Performer Album|Playlist)))) #+END_SRC * Programming ** flycheck On-the-fly error checking in programming modes? Yes please. #+BEGIN_SRC emacs-lisp (use-package flycheck :diminish " ✓" :defer 5 :config (progn (global-flycheck-mode) (setq flycheck-check-syntax-automatically '(save new-line mode-enabled)) (if (executable-find "eslint_d") (setq flycheck-javascript-eslint-executable (executable-find "eslint_d"))))) #+END_SRC ** golang Go has a few packages to inter-operate with other emacs packages. #+BEGIN_SRC emacs-lisp (use-package company-go :commands company-go :config (progn (setq company-go-show-annotation t)) :init (progn (defun ap/company-go-setup () (set (make-local-variable 'company-backends) '(company-go))) (add-hook 'go-mode-hook #'ap/company-go-setup))) (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))) #+END_SRC ** ggtags A nice completion backend for programming modes. #+BEGIN_SRC emacs-lisp (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))) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (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)) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (defcustom lisp-mode-common-hook nil "Hook run when entering any Lisp mode." :type 'hook :group 'lisp) (defun ap/lisp-setup () (run-hooks 'lisp-mode-common-hook)) #+END_SRC **** Redshank Lisp syntax allows for really easy refactoring. Redshank gives some operations that aren’t part of paredit, like extracting variables into let bindings. #+BEGIN_SRC emacs-lisp (use-package redshank :diminish " Λ" :after (paredit) :config (progn (add-hook 'lisp-mode-common-hook #'turn-on-redshank-mode))) #+END_SRC *** Emacs Lisp Customise the modeline-display of =emacs-lisp-mode=. Then make sure it runs the common lisp hooks. #+BEGIN_SRC emacs-lisp (add-hook 'emacs-lisp-mode-hook #'ap/lisp-setup) (add-hook 'emacs-lisp-mode-hook #'eldoc-mode) #+END_SRC Go-to function for elisp. Except it works through the entire Emacs ecosystem. #+BEGIN_SRC emacs-lisp (use-package elisp-slime-nav :commands elisp-slime-nav-mode :diminish elisp-slime-nav-mode :init (progn (add-hook 'emacs-lisp-mode-hook #'elisp-slime-nav-mode))) #+END_SRC Interactive elisp #+BEGIN_SRC emacs-lisp (use-package ielm :defer t :ensure nil :config (progn (add-hook 'ielm-mode-hook (lambda () (run-hooks 'lisp-mode-common-hook))))) #+END_SRC *** Scheme & Lisp I don’t work with these as often as I would like #+BEGIN_SRC emacs-lisp (add-hook 'scheme-mode-hook #'ap/lisp-setup) (add-hook 'lisp-mode-hook #'ap/lisp-setup) (defun set-common-lisp-indentation () (set (make-local-variable 'lisp-indent-function) #'common-lisp-indent-function)) (add-hook 'lisp-mode-hook #'set-common-lisp-indentation) #+END_SRC **** hyperspec #+BEGIN_SRC emacs-lisp (use-package hyperspec :config (progn (setq common-lisp-hyperspec-root "file://opt/local/share/doc/lisp/HyperSpec-7-0/"))) #+END_SRC **** geiser A REPL thing for Scheme. Hopefully I’ll get to use it more in the future. #+BEGIN_SRC emacs-lisp (use-package geiser :commands (geiser-mode geiser run-geiser run-racket)) #+END_SRC **** slime A REPL thing (and more) for Lisp. #+BEGIN_SRC emacs-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 inferior-lisp-program (or (executable-find "sbcl") (executable-find "ccl64"))))) #+END_SRC *** Clojure #+BEGIN_SRC emacs-lisp (use-package clojure-mode :defer t :init (progn (add-hook 'cider-repl-mode-hook (lambda () (highlight-changes-mode -1))) (add-hook 'clojure-mode-hook #'ap/lisp-setup))) (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 (defun turn-on-clj-refactor-mode () (clj-refactor-mode 1)) (add-hook 'clojure-mode-hook #'turn-on-clj-refactor-mode))) #+END_SRC **** cider A REPL thing for Clojure #+BEGIN_SRC emacs-lisp (use-package cider :defer t :config (progn (setq nrepl-hide-special-buffers t) (unbind-key "C-c C-f" cider-mode-map) (add-hook 'cider-mode-hook #'eldoc-mode))) #+END_SRC ** Auto-compile Auto-compile emacs lisp when saving. #+BEGIN_SRC emacs-lisp (use-package auto-compile :defer t :init (add-hook 'emacs-lisp-mode-hook #'auto-compile-on-save-mode)) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (use-package cc-mode :defer 5 :init (progn (add-hook 'c-mode-common-hook #'electric-indent-mode)) :config (progn (setq c-default-style '((java-mode . "java") (awk-mode . "awk") (other . "k&r")) c-basic-offset 4) (c-set-offset 'case-label '+))) #+END_SRC ** quickrun It’s nice to be able to quickly evaluate some code. Although I don’t really seem to use it. #+BEGIN_SRC emacs-lisp (use-package quickrun :bind (("C-c C-e" . quickrun))) #+END_SRC ** Scala Let’s try using Scala. #+BEGIN_SRC emacs-lisp (use-package scala-mode :pin melpa-stable) #+END_SRC And add ensime, an IDE-style environment. #+BEGIN_SRC emacs-lisp (use-package ensime :pin melpa-stable) #+END_SRC ** 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. I don’t think there’s anything as good as paredit/redshank for refactoring in it though #+BEGIN_SRC emacs-lisp (use-package js2-mode :mode (("\\.js\\'" . js2-mode) ("\\.jsx\\'" . js2-jsx-mode)) :interpreter ("node" . js2-mode) :functions js2-next-error :config (progn (define-key js2-mode-map [menu-bar Javascript] nil) (defun js2--imenu-around (do-it name) "Don't create a menu from js2-mode" (if (and (not (string-equal name "IM-Javascript-IDE")) (fboundp #'do-it)) (do-it name))) (advice-add 'imenu-add-to-menubar :around #'js2--imenu-around) (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) (setq js2-basic-offset 2 js2-include-node-externs t))) #+END_SRC **** jade (not pug) 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~ #+BEGIN_SRC emacs-lisp (use-package jade :config (progn (add-hook 'js2-mode-hook #'jade-interaction-mode))) #+END_SRC *** coffee-mode #+BEGIN_SRC emacs-lisp (use-package coffee-mode :mode ("\\.coffee\\'" . coffee-mode) :config (progn (setq coffee-indent-like-python-mode t))) #+END_SRC *** tern Tern understands javascript. It adds really clever documented completions, besides other IDE-like things. #+BEGIN_SRC emacs-lisp (use-package tern :commands ap/enable-tern :if (executable-find "tern") :defer 5 :config (progn (setq tern-command (list (executable-find "tern"))) (defun ap/enable-tern () (tern-mode 1)) (add-hook 'js2-mode-hook #'ap/enable-tern) (add-hook 'web-mode-hook #'ap/enable-tern))) (with-eval-after-load 'tern (use-package company-tern)) #+END_SRC *** json-mode #+BEGIN_SRC emacs-lisp (use-package json-mode :mode (("\\.json\\'" . json-mode) ("\\.sailsrc\\'" . json-mode) ("composer\\.lock\\'" . json-mode) ("\\.tern-project\\'" . json-mode))) #+END_SRC *** 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. #+BEGIN_SRC emacs-lisp (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)) #+END_SRC *** sgml-mode This is for HTML, since old versions of HTML were derived from SGML. #+BEGIN_SRC emacs-lisp (use-package sgml-mode :defer t :config (setq sgml-basic-offset 2)) #+END_SRC *** emmet-mode Emmet is really nice to write HTML quickly. Especially with frameworks that require multiple nested elements to do anything useful. #+BEGIN_SRC emacs-lisp (use-package emmet-mode :commands (emmet-mode) :diminish (emmet-mode . " >") :init (progn (setq emmet-indentation 2) (add-hook 'web-mode-hook #'emmet-mode))) #+END_SRC *** 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. #+BEGIN_SRC emacs-lisp (use-package web-mode :mode (("/views/.*\\.php\\'" . web-mode) ("\\.html\\'" . web-mode) ("/templates/.*\\.php\\'" . web-mode) ("\\.ejs\\'" . 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) (sp-local-pair '(web-mode) "<%" "%>"))) #+END_SRC I derived a mode for twig, in order to use its =mode-hook=. #+BEGIN_SRC emacs-lisp (define-derived-mode twig-mode web-mode "Twig") (add-to-list 'auto-mode-alist '("\\.html\\.twig\\'" . twig-mode)) #+END_SRC * Spelling #+BEGIN_SRC emacs-lisp (use-package ispell :bind (("" . 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))))) #+END_SRC #+BEGIN_SRC emacs-lisp (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))) #+END_SRC * Scripting Make a shell-script buffer executable after saving it, if it has a shebang. #+BEGIN_SRC emacs-lisp (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) (use-package sh-script :mode (("\\.zsh\\'" . shell-script-mode) ("zshenv\\'" . shell-script-mode) ("zshrc\\'" . shell-script-mode)) :config (setq sh-shell-file "/usr/bin/env zsh" sh-indentation 2 sh-basic-offset 2)) #+END_SRC #+BEGIN_SRC emacs-lisp (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) #+END_SRC ** eshell I should try to get into the habit of using this more. It’s really nice, when I remember to use it. #+BEGIN_SRC emacs-lisp (use-package eshell :bind ("C-c s" . eshell) :config (progn (setq eshell-directory-name "~/.emacs.d/eshell" eshell-prompt-function (lambda () (concat (eshell/pwd) "\n$ "))) (add-hook 'eshell-load-hook (lambda () (bind-key "C-c C-l" #'counsel-esh-history eshell-mode-map))))) (use-package em-smart :ensure nil :commands eshell-smart-initialize :init (progn (add-hook 'eshell-load-hook #'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) (interactive "P") (let ((dir default-directory)) (eshell arg) (eshell/cd dir))) (bind-key "C-c S" #'eshell-goto-current-dir) #+END_SRC *** Shells #+BEGIN_SRC emacs-lisp (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) (interactive "p") (if (null (get-buffer-process (current-buffer))) (kill-buffer) (comint-delchar-or-maybe-eof arg))) #+END_SRC * Text editing Emacs has an editor within. #+BEGIN_SRC emacs-lisp (put 'upcase-region 'disabled nil) (put 'downcase-region 'disabled nil) (setq sentence-end-double-space t line-move-visual nil) #+END_SRC ** align =Align= is a useful command to line things up, once given some rules. The most important one for me is JSON property alignment. #+BEGIN_SRC emacs-lisp (use-package align :defer 10 :ensure nil :config (progn (add-to-list 'align-rules-list '(colon-key-value (regexp . ":\\(\\s-*\\)") (modes . '(js2-mode)))))) #+END_SRC ** Clipboard I like to use the clipboard more than the primary selection in X11. #+BEGIN_SRC emacs-lisp (setq x-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))) #+END_SRC *** Copy formatted code #+BEGIN_SRC emacs-lisp (bind-key* "C-c w" (define-prefix-command 'copy-as-map)) (use-package copy-as-format :bind (("C-c C-w" . copy-as-format) :map copy-as-map ("b" . copy-as-format-bitbucket) ("g" . copy-as-format-github) ("h" . copy-as-format-hipchat) ("w" . copy-as-format-html) ("j" . copy-as-format-jira) ("m" . copy-as-format-markdown) ("s" . copy-as-format-slack))) #+END_SRC ** ** Selection I’m quite used to deleting text by selecting it and typing. Emacs has a mode for that. #+BEGIN_SRC emacs-lisp (delete-selection-mode t) #+END_SRC Sub-word movement is really nice for camel- and Pascal-case #+BEGIN_SRC emacs-lisp (use-package subword :diminish subword-mode :init (global-subword-mode t)) #+END_SRC I find that =zap-up-to-char= normally makes more sense to me than =zap-to-char=. #+BEGIN_SRC emacs-lisp (use-package misc :ensure nil :bind (("M-z" . zap-up-to-char) ("M-Z" . zap-to-char))) #+END_SRC Expanding the region by semantic units was something I quite liked from Sublime Text. As always, there’s a mode for that. #+BEGIN_SRC emacs-lisp (use-package expand-region :bind ("C-M-SPC" . er/expand-region) :config (setq expand-region-fast-keys-enabled nil)) #+END_SRC ** avy Avy is a really nice way to move around files, like ace-jump-mode, but somehow I prefer it. #+BEGIN_SRC emacs-lisp (use-package avy :bind (("M-g g" . avy-goto-line) ("M-g M-g" . avy-goto-line) ("C-|" . 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 avy-keys '(?a ?r ?s ?t ?d ?h ?n ?e ?i ?\;)))) #+END_SRC *** ace-link Visit any link. Despite the name, this works with avy. #+BEGIN_SRC emacs-lisp (use-package ace-link :after avy :config (progn (ace-link-setup-default) (with-eval-after-load "gnus" (bind-key "M-o" #'ace-link-gnus gnus-summary-mode-map) (bind-key "M-o" #'ace-link-gnus gnus-article-mode-map)))) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (use-package goto-chg :bind ("C-c C-SPC" . goto-last-change)) #+END_SRC ** multiple-cursors I mentioned before that I’d used Sublime Text before. Multiple cursors was one of my favourite features, so I was really happy when I saw that multiple-cursors was released for Emacs. #+BEGIN_SRC emacs-lisp (use-package multiple-cursors :defer 1 :bind* (("C-." . mc/mark-next-like-this) ("C-," . mc/mark-previous-like-this) ("M-" . mc/mark-all-like-this-dwim) ("C-" . mc/mark-more-like-this-extended) ("C-S-L" . mc/edit-lines))) #+END_SRC ** paredit Balanced parentheses in lisps are nice, but all the refactoring and movement commands are much more interesting. #+BEGIN_SRC emacs-lisp (use-package paredit :diminish "()" :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))) #+END_SRC ** smartparens I like to use smartparens where paredit isn’t already useful. Somehow I didn’t find smartparens’ implementation of paredit style to be as nice as the real version #+BEGIN_SRC emacs-lisp (eval-when-compile (require 'smartparens nil :noerror)) (use-package smartparens-config :ensure smartparens :config (progn (sp-use-smartparens-bindings) (setq sp-highlight-pair-overlay nil) (fset 'wrap-with-paren "\C-](") ;; `sp-select-next-thing-exchange' (bind-key "C-(" #'wrap-with-paren smartparens-mode-map) (bind-key "C-)" #'sp-forward-slurp-sexp smartparens-mode-map) (bind-key "M-" #'backward-kill-word smartparens-mode-map) (bind-key "M-?" #'sp-convolute-sexp smartparens-mode-map) (bind-key "C-M-t" #'sp-transpose-sexp smartparens-mode-map) (bind-key "M-R" #'sp-raise-sexp smartparens-mode-map) (bind-key "M-S" #'sp-splice-sexp smartparens-mode-map) (bind-key "C-M-s" #'sp-split-sexp smartparens-mode-map) (bind-key "M-J" #'sp-join-sexp smartparens-mode-map) (bind-key "M-" #'sp-splice-sexp-killing-backward smartparens-mode-map) (bind-key "M-" #'sp-splice-sexp-killing-forward smartparens-mode-map) (bind-key "C-M-S-k" #'sp-kill-hybrid-sexp smartparens-mode-map) (bind-key "C-S-" #'sp-slurp-hybrid-sexp smartparens-mode-map) (sp-with-modes '(twig-mode) (sp-local-pair "{%" "%}") (sp-local-pair "{{" "}}")) (show-smartparens-global-mode t) (smartparens-global-strict-mode t) (add-hook 'lisp-mode-common-hook #'turn-off-smartparens-mode) (add-hook 'coffee-mode-hook #'turn-off-smartparens-mode))) #+END_SRC ** smart-scan Move between instances of a symbol #+BEGIN_SRC emacs-lisp (use-package smartscan :config (progn (global-smartscan-mode 1) (setq smartscan-symbol-selector "symbol"))) #+END_SRC ** move-text Transposing lines, made easier. #+BEGIN_SRC emacs-lisp (use-package move-text :config (move-text-default-bindings)) #+END_SRC ** undo-tree Emacs’ default handling of undo is a bit confusing. Undo-tree makes it much clearer. It’s especially helpful for protoyping and refactoring. #+BEGIN_SRC emacs-lisp (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))) :diminish undo-tree-mode) #+END_SRC ** replace #+BEGIN_SRC emacs-lisp (with-eval-after-load "replace.el" (setq case-replace nil)) #+END_SRC ** visual-regexp I don’t always remember exactly how Emacs’ regular expressions work, so this package is pretty useful because it highlights everything in the buffer for me. #+BEGIN_SRC emacs-lisp (use-package visual-regexp :bind (("C-c r" . vr/replace) ("C-c q" . vr/query-replace) ("C-c m" . vc/mc-mark))) #+END_SRC * Tangling Taken from [[https://github.com/larstvei/dot-emacs/blob/master/init.org][larstvei/dot-emacs]]. I changed it so that it would work with my current dotfiles repository structure and work asynchronously, thanks to [[https://github.com/jwiegley/emacs-async][jwiegley/emacs-async]]. We can use =C-c C-v t= to run =org-babel-tangle=, which extracts the code blocks from the current file into a source-specific file (in this case a =.el=-file). To avoid doing this each time a change is made we can add a function to the =after-save-hook= ensuring to always tangle and byte-compile the =org=-document after changes. #+BEGIN_SRC emacs-lisp (use-package async :commands (async-start) :defer 2) (defun tangle-if-init () "If the current buffer is 'init.org' the code-blocks are tangled, and the tangled file is compiled." (when (string-suffix-p "init.org" (buffer-file-name)) (tangle-init))) (defun tangle-init-sync () (interactive) (message "Tangling init") ;; Avoid running hooks when tangling. (let ((prog-mode-hook nil) (src (expand-file-name "init.org" user-emacs-directory)) (dest (expand-file-name "init.el" user-emacs-directory))) (require 'ob-tangle) (org-babel-tangle-file src dest) (if (byte-compile-file dest) (byte-compile-dest-file dest) (with-current-buffer byte-compile-log-buffer (buffer-string))))) (defun tangle-init () "Tangle init.org asynchronously." (interactive) (message "Tangling init") (async-start (symbol-function #'tangle-init-sync) (lambda (result) (message "Init tangling completed: %s" result)))) #+END_SRC # Local Variables: # eval: (when (fboundp #'tangle-if-init) (add-hook 'after-save-hook #'tangle-if-init)) # End: * End Start a server if possible. A daemon is already a server. #+BEGIN_SRC emacs-lisp (run-with-idle-timer 2 nil (lambda () (unless (daemonp) (require 'server) (unless (server-running-p server-name) (server-start))))) (setq gc-cons-threshold 800000 file-name-handler-alist file-name-handler-alist-backup) #+END_SRC