#+TITLE: Emacs Configuration for Alan Pearce #+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 (setq inhibit-startup-echo-area-message "alan") (setq inhibit-startup-screen t) #+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 ** 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 * Packaging I still use a couple of [[file:elisp/][elisp files]] that don’t appear to be in any package archives. #+BEGIN_SRC emacs-lisp (add-to-list 'load-path (expand-file-name "elisp/" user-emacs-directory)) #+END_SRC ** TODO Move [[file:elisp/ap-functions.el][=ap-functions=]] into this file and delete above ** Cask For most packages, I use [[https://github.com/cask/cask][cask]] #+BEGIN_SRC emacs-lisp (add-to-list 'load-path (expand-file-name "~/.cask")) (require 'cask) (cask-initialize) #+END_SRC *** Cask commands Installing #+BEGIN_SRC sh :tangle no curl -fsSL https://raw.githubusercontent.com/cask/cask/master/go | python #+END_SRC Install all packages specified in the Caskfile #+BEGIN_SRC sh :tangle no :dir ~/.emacs.d/ cask install #+END_SRC List packages with new versions #+BEGIN_SRC sh :tangle no :dir ~/.emacs.d/ :results output cask outdated #+END_SRC Update old packages #+BEGIN_SRC sh :tangle no :dir ~/.emacs.d/ cask update #+END_SRC ** Req-package #+BEGIN_SRC emacs-lisp (setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/") ("marmalade" . "http://marmalade-repo.org/packages/") ("melpa" . "http://melpa.org/packages/") ("melpa-stable" . "http://stable.melpa.org/packages/") ("org" . "http://orgmode.org/elpa/"))) (package-initialize) (unless (package-installed-p 'req-package) (package-refresh-contents) (package-install 'req-package)) (require 'req-package) (setq use-package-verbose t) #+END_SRC ** Pallet I use [[https://github.com/rdallasgray/pallet][pallet]] to keep my [[file:Cask][Caskfile]] up-to-date with packages installed from inside Emacs. I don’t need it on startup, so I tell =req-package= to initialise it when Emacs is idle. #+BEGIN_SRC emacs-lisp (req-package pallet :defer 5 :config (pallet-mode 1)) #+END_SRC * Helpers I like to rename modeline lighters. This macro works for major modes. #+BEGIN_SRC emacs-lisp (defmacro rename-modeline (mode new-name) `(defadvice ,mode (after rename-modeline activate) (setq mode-name ,new-name))) #+END_SRC * Projects #+BEGIN_SRC emacs-lisp (defvar work-project-directory "~/work") (defvar home-project-directory "~/projects") #+END_SRC #+BEGIN_SRC emacs-lisp (defun switch-to-dotfiles () (interactive) (projectile-persp-switch-project (expand-file-name "dotfiles" home-project-directory))) #+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 (req-package projectile :bind (("C-c C-f" . projectile-find-file) ("s-x s-f" . projectile-find-file) ("C-x g" . projectile-vc) ("s-G" . projectile-vc)) :init (projectile-global-mode) :diminish projectile-mode :config (progn (defun ap/subfolder-projects (dir) (--map (file-relative-name it dir) (-filter (lambda (subdir) (--reduce-from (or acc (funcall it subdir)) nil projectile-project-root-files-functions)) (-filter #'file-directory-p (directory-files dir t "\\<"))))) (defun ap/-add-known-subfolder-projects (dir) (-map #'projectile-add-known-project (--map (concat (file-name-as-directory dir) it) (ap/subfolder-projects dir)))) (defun ap/add-known-subfolder-projects () (interactive) (ap/-add-known-subfolder-projects (read-directory-name "Add projects under: "))) (defun ap/open-subfolder-project (from-dir &optional arg) (let ((project-dir (projectile-completing-read "Open project: " (ap/subfolder-projects from-dir)))) (projectile-switch-project-by-name (expand-file-name project-dir from-dir) arg))) (defun ap/open-work-project (&optional arg) (interactive "P") (ap/open-subfolder-project work-project-directory arg)) (defun ap/open-home-project (&optional arg) (interactive "P") (ap/open-subfolder-project home-project-directory arg)) (setq projectile-switch-project-action #'projectile-dired projectile-remember-window-configs t projectile-completion-system 'ivy))) #+END_SRC ** projector Project-based shell buffers sounds like a good idea, but for some reason I haven’t found a use for it. #+BEGIN_SRC emacs-lisp (req-package projector :require projectile :bind (("s-z" . projector-open-project-shell))) #+END_SRC ** perspective This package makes buffer-switching inside of projects make sense, by filtering the candidates to those within the project. For it to work, it needs hooking into projectile and a key bound to switch between projects. #+BEGIN_SRC emacs-lisp (req-package perspective :bind (("s-p" . persp-switch)) :init (progn (persp-mode))) (req-package persp-projectile :require (projectile perspective)) #+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 (req-package vc :defer t :bind (("C-x v C" . vc-resolve-conflicts)) :config (progn (setq vc-follow-symlinks t))) #+END_SRC ** diff-hl It’s nice to be able to see at a glance which lines of a file have changed. This package colours the fringe #+BEGIN_SRC emacs-lisp (req-package diff-hl :init (progn (global-diff-hl-mode) (add-hook 'magit-refresh-file-buffer-hook #'diff-hl-update))) #+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 (req-package magit :defer 5 :commands (magit-status) :config (progn (rename-modeline magit-status-mode (char-to-string (-find #'char-displayable-p '(11942 5848 177)))) (setq magit-last-seen-setup-instructions "1.4.0" magit-completing-read-function #'magit-builtin-completing-read magit-wip-after-save-mode t magit-wip-after-apply-mode t magit-popup-use-prefix-argument 'default magit-push-always-verify nil magit-revert-buffers t) (add-to-list 'magit-no-confirm 'safe-with-wip)) :init (add-hook 'magit-mode-hook #'magit-load-config-extensions)) #+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)) (when scroll-bar-mode (scroll-bar-mode -1) (tooltip-mode -1) (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 When I’m using dash in emacs lisp, it’s nice to have proper font locking for it. #+BEGIN_SRC emacs-lisp (req-package dash :demand t :init (setq dash-enable-fontlock t) :config (progn (dash--enable-fontlock 'dash-enable-font-lock t))) #+END_SRC ** Colours I quite like solarized. I don’t think it’s perfect, but it supports a lot of modes. #+BEGIN_SRC emacs-lisp (req-package solarized-theme :config (progn (load-theme 'solarized-light t))) #+END_SRC Colourise colour names in certain types of buffer. I don’t use this in modes for webdev because [[web-mode]] includes that functionality. #+BEGIN_SRC emacs-lisp (req-package rainbow-mode :commands (rainbow-turn-on rainbow-turn-off) :config (progn (add-hook 'xmonad-mode-hook #'rainbow-turn-on))) #+END_SRC Highlighting quasi-quoted expressions in lisps is quite useful. #+BEGIN_SRC emacs-lisp (req-package highlight-stages :defer t :diminish highlight-stages-mode :init (progn (add-hook 'lisp-mode-common-hook #'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 variable-face font-size) (when mono-face (let ((default-font (concat mono-face "-" (number-to-string font-size)))) (add-to-list 'default-frame-alist `(font . ,default-font)) (set-face-font 'fixed-pitch default-font) (set-frame-font default-font t t))) (when variable-face (set-face-font 'variable-pitch (concat variable-face "-" (number-to-string (1+ font-size)))))) (cond ((eq window-system 'w32) (ap/set-fonts "Consolas" "Segoe UI" 10)) ((eq system-type 'darwin) (ap/set-fonts "Monaco" "Helvetica" 12)))) #+END_SRC Allow font-lock-mode to do background parsing. I’m not really sure if these settings are particularly useful #+BEGIN_SRC emacs-lisp (setq jit-lock-stealth-time 1 jit-lock-stealth-load 100 jit-lock-chunk-size 1000 jit-lock-defer-time 0.01 font-lock-maximum-decoration '((dired-mode . 1) (t . t))) #+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)) #+END_SRC ** autorevert #+BEGIN_SRC emacs-lisp (req-package autorevert :init (progn (global-auto-revert-mode 1) (setq auto-revert-verbose nil))) #+END_SRC ** Encoding #+BEGIN_SRC emacs-lisp (prefer-coding-system 'utf-8-auto-unix) (set-default-coding-systems 'utf-8-auto-unix) (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 rename-current-buffer-file () "Renames current buffer and file it is visiting." (interactive) (let ((name (buffer-name)) (filename (buffer-file-name))) (if (not (and filename (file-exists-p filename))) (error "Buffer '%s' is not visiting a file!" name) (let ((new-name (read-file-name "New name: " filename))) (if (get-buffer new-name) (error "A buffer named '%s' already exists!" new-name) (cond ((vc-backend filename) (vc-rename-file filename new-name)) (t (rename-file filename new-name t) (rename-buffer new-name) (set-visited-file-name new-name) (set-buffer-modified-p nil) (message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name))))))))) (defun delete-current-buffer-file () "Removes file connected to current buffer and kills buffer." (interactive) (let ((filename (buffer-file-name))) (if (not (and filename (file-exists-p filename))) (kill-this-buffer) (when (yes-or-no-p "Are you sure you want to remove this file? ") (delete-file filename) (kill-this-buffer) (message "File '%s' successfully removed" filename))))) (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 (equalp 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 (req-package ws-butler :if window-system :config (ws-butler-global-mode 1)) (if (daemonp) (add-hook #'before-make-frame-hook (lambda () (ws-butler-global-mode 1)))) #+END_SRC ** fasd Fasd is a nice shell plugin that remembers file and folder arguments, making it easy to re-visit them later. This package hooks into that. I don’t seem to use it much though. #+BEGIN_SRC emacs-lisp (req-package fasd :bind ("C-x C-/" . fasd-find-file) :init (progn (global-fasd-mode 1))) #+END_SRC ** recentf I only use this occasionally, but it’s nice for files outside of projects. #+BEGIN_SRC emacs-lisp (req-package recentf :init (progn (setq recentf-auto-cleanup 'never recentf-save-file (expand-file-name "recentf" user-emacs-directory)) (recentf-mode 1))) #+END_SRC ** saveplace It.. saves the position I visited a file at last. Might try turning it off to see if I notice it. #+BEGIN_SRC emacs-lisp (req-package saveplace :config (progn (setq-default save-place t) (setq save-place-file (expand-file-name ".saveplace" user-emacs-directory)))) #+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 (req-package tramp :defer t :config (progn (setq tramp-default-method (if (eq system-type 'windows-nt) "plinkx" "ssh") tramp-default-user-alist '(("\\`su\\(do\\)?\\'" nil "root")) tramp-backup-directory-alist backup-directory-alist 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)) (add-to-list 'tramp-default-proxies-alist '("router" nil nil)))) (req-package tramp-sh :require tramp :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 (req-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. Until then, I want 4-wide tabs, and make them real tabs! #+BEGIN_SRC emacs-lisp (setq-default tab-width 4 indent-tabs-mode t) (setq tab-stop-list ;; (mapcar (lambda (x) ;; (* 4 x)) ;; (number-sequence 1 (/ 120 4))) '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120)) #+END_SRC ** auto-indent-mode Don’t make me think, just indent it! Unless it’s a whitespace-sensitive language, of course. #+BEGIN_SRC emacs-lisp (req-package auto-indent-mode :config (progn (setq auto-indent-key-for-end-of-line-then-newline "" auto-indent-key-for-end-of-line-insert-char-then-newline "" auto-indent-blank-lines-on-move nil auto-indent-assign-indent-level 4 auto-indent-backward-delete-char-behavior nil auto-indent-delete-trailing-whitespace-on-save-file t auto-indent-mode-untabify-on-yank-or-paste nil auto-indent-start-org-indent nil auto-indent-known-indent-level-variables (remq 'lisp-body-indent auto-indent-known-indent-level-variables)) (add-to-list 'auto-indent-disabled-modes-list 'jinja2-mode) (add-to-list 'auto-indent-disabled-modes-list 'yaml-mode) (add-to-list 'auto-indent-disabled-modes-list 'saltstack-mode) (add-to-list 'auto-indent-disabled-modes-list 'nix-mode) (auto-indent-global-mode))) #+END_SRC *** TODO Check for auto-indentation of whitespace-sensitive languages. ** smart-tabs-mode Not related to [[smart-tab][=smart-tab=]], this mode indents with tabs and aligns with spaces. Perfect! #+BEGIN_SRC emacs-lisp (req-package smart-tabs-mode :commands (smart-tabs-mode smart-tabs-mode-enable smart-tabs-advice) :config (progn (smart-tabs-insinuate 'c 'javascript 'cperl 'python)) :init (progn (add-hook 'php-mode-hook (lambda () (smart-tabs-mode indent-tabs-mode))) (add-hook 'js2-mode-hook (lambda () (smart-tabs-mode indent-tabs-mode))))) #+END_SRC * Security ** password-store This is a frontend to the GPG-powered =pass= program. #+BEGIN_SRC emacs-lisp (req-package password-store :config (progn (setq password-store-password-length 16))) #+END_SRC * Buffers ** Ibuffer Ibuffer is quite nice for listing all buffers. I don’t use it very often though, as it doesn’t really work with perspectives. #+BEGIN_SRC emacs-lisp (req-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 ** Uniqify Sometimes projects have files with the same name. This gives them unique names, by adding enough path elements to make them unambiguous. #+BEGIN_SRC emacs-lisp (req-package uniquify :config (progn (setq uniquify-buffer-name-style 'forward uniquify-separator "/" uniquify-after-kill-buffer-p t uniquify-ignore-buffers-re "^\\*"))) #+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 ** Fancy Narrow Sometimes I like to be able to focus on one block of code at a time. Normally narrowing hides everything else completely, which I don’t like. This package just makes everything else lower-contrast. #+BEGIN_SRC emacs-lisp (req-package fancy-narrow :diminish fancy-narrow-mode :config (fancy-narrow-mode 1)) #+END_SRC ** ace-jump-buffer #+BEGIN_SRC emacs-lisp (use-package ace-jump-buffer :bind ("s-b" . ace-jump-buffer)) #+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 (req-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 100) (if (eq system-type 'darwin) (setq ns-pop-up-frames nil)) #+END_SRC A dedicated window always keeps the same buffer in view. #+BEGIN_SRC emacs-lisp (defun toggle-window-dedicated () "Toggle whether the current active window is dedicated or not" (interactive) (message "Window '%s' is %s" (current-buffer) (if (let ((window (get-buffer-window (current-buffer)))) (set-window-dedicated-p window (not (window-dedicated-p window)))) "dedicated" "normal"))) #+END_SRC ** popwin This works really nicely wiht helm. I should think about whether it might be useful elsewhere #+BEGIN_SRC emacs-lisp (req-package popwin :if (and (>= emacs-major-version 24) (> emacs-minor-version 3)) :config (progn (popwin-mode 1) (add-to-list 'popwin:special-display-config '("^*helm.+*$" :regexp t :height 20)))) #+END_SRC ** winner Undo, for window-based commands. #+BEGIN_SRC emacs-lisp (req-package winner :init (progn (winner-mode 1) (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")))) #+END_SRC ** windmove Directional window movement #+BEGIN_SRC emacs-lisp (req-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. ** TODO With =tab-always-indent=, do I need smart-tab anymore? #+BEGIN_SRC emacs-lisp (setq completion-styles '(basic initials partial-completion substring) completion-ignore-case t tab-always-indent 'complete) #+END_SRC *** Smart-tab Most editors use tab for both completion and indentation. Smart-tab tries to do the right thing depending on the location of the point and the line’s current indentation. #+BEGIN_SRC emacs-lisp (req-package smart-tab :commands (global-smart-tab-mode) :init (global-smart-tab-mode) :diminish smart-tab-mode :config (progn (nconc smart-tab-completion-functions-alist '((php-mode . php-complete-function))) (diminish 'smart-tab-mode ""))) #+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 (req-package company :commands (company-mode) :diminish "Cmpl" :bind (("C-" . company-complete)) :init (progn (add-hook 'prog-mode-hook #'company-mode) (setq company-backends '(company-tern (php-extras-company company-elisp company-bbdb company-nxml company-css company-eclim company-semantic company-clang company-xcode company-cmake company-capf company-gtags company-dabbrev-code company-etags company-keywords) company-oddmuse company-files company-dabbrev) 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-dabbrev-downcase nil))) #+END_SRC * Dates & Times ** Calendar Weeks start on Monday for me and I prefer ISO-style dates. #+BEGIN_SRC emacs-lisp (req-package calendar :defer t :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 * 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 (req-package dired :defer t :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" dired-bind-jump nil) (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 I work with a lot of git projects. Dired-k adds colours based upon the file’s git status. #+BEGIN_SRC emacs-lisp (req-package dired-k :require dired :init (progn (add-hook 'dired-initial-position-hook #'dired-k)) :config (progn (setq dired-k-human-readable t) (bind-key "g" #'dired-k dired-mode-map))) #+END_SRC Don’t show uninteresting files in dired listings. #+BEGIN_SRC emacs-lisp (req-package dired-x :require dired :config (progn (defun turn-on-dired-omit-mode () (interactive) (dired-omit-mode 1)) (add-hook 'dired-mode-hook #'turn-on-dired-omit-mode) (setq dired-omit-files "#\\|\\.$" dired-omit-verbose nil dired-find-subdir t))) #+END_SRC #+BEGIN_SRC emacs-lisp (req-package dired+ :require dired :config (progn (diredp-toggle-find-file-reuse-dir 1) (unbind-key "C-h C-m" dired-mode-map) (bind-key "." #'diredp-describe-file dired-mode-map))) #+END_SRC Expand subfolders like a tree inside the parent #+BEGIN_SRC emacs-lisp (req-package dired-subtree :defer t :require dired :config (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)) :init (progn (bind-key "i" #'dired-subtree-toggle dired-mode-map))) #+END_SRC * Documentation ** helm-dash Emacs’ documentation is great to read from inside Emacs. Helm-dash helps to make documentation for other languages easier to access #+BEGIN_SRC emacs-lisp (req-package helm-dash :defer t :init (progn (defmacro ap/create-helm-dash-hook (mode docsets) (let* ((mode-s (symbol-name mode)) (fun (intern (concat "helm-dash-hook-" mode-s))) (hook (intern (concat mode-s "-mode-hook")))) `(progn (defun ,fun () (when (require 'helm-dash nil :noerror) (-each (-difference ',docsets (helm-dash-installed-docsets)) #'helm-dash-install-docset) (setq-local helm-dash-docsets ',docsets))) (add-hook (quote ,hook) (function ,fun))))) (ap/create-helm-dash-hook nginx ("Nginx")) (ap/create-helm-dash-hook ansible ("Ansible")) (ap/create-helm-dash-hook php ("PHP" "Symfony")) (ap/create-helm-dash-hook twig ("Twig")) (ap/create-helm-dash-hook js2 ("JavaScript" "NodeJS" "jQuery" "Express")) (ap/create-helm-dash-hook markdown ("Markdown")) (ap/create-helm-dash-hook saltstack ("SaltStack")) (ap/create-helm-dash-hook clojure ("Clojure")) (ap/create-helm-dash-hook sql ("PostgreSQL" "MySQL")))) #+END_SRC ** which-func Use the modeline to show which function definition the point is in. #+BEGIN_SRC emacs-lisp (req-package which-func :init (which-function-mode) :config (setq which-func-modes t)) #+END_SRC ** discover-my-major A nicer way to browse keybindings for major modes. #+BEGIN_SRC emacs-lisp (req-package discover-my-major :bind ("C-h C-m" . discover-my-major)) #+END_SRC ** discover Makes some context menus for dired and other things, similarly to the way magit’s popups work. #+BEGIN_SRC emacs-lisp (req-package discover :config (global-discover-mode)) #+END_SRC ** eldoc Documentation in the echo-area (where the minibuffer is displayed) is rather useful. #+BEGIN_SRC emacs-lisp (req-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 * 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) (setq mac-option-modifier 'meta mac-right-option-modifier 'left mac-control-modifier 'control mac-right-control-modifier 'left mac-command-modifier 'super mac-right-command-modifier 'left mac-function-modifier 'hyper)) #+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) (set-register ?z `(file . ,(expand-file-name ".config/zsh/zshrc" "~"))) #+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*)) (req-package whitespace :defer t :config (setq whitespace-style '(face space tabs trailing newline empty tab-mark space-before-tab indentation indentation::space indentation::tabs))) (req-package ap-functions :commands (ap/remove-extra-cr) :bind (("C-x r M-w" . copy-rectangle) ("M-!" . shell-execute))) #+END_SRC #+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 ** helm I like to use =helm= for some completions, especially when there are lots of candidates. #+BEGIN_SRC emacs-lisp (req-package helm-config :demand t :ensure helm :config (progn (setq helm-idle-delay .1 helm-input-idle-delay 0) (when (fboundp #'helm-adaptive-mode) (helm-adaptive-mode 1)))) (req-package helm-files :defer t :config (progn (define-key helm-read-file-map (kbd "") #'helm-execute-persistent-action) (define-key helm-read-file-map (kbd "TAB") #'helm-execute-persistent-action) (define-key helm-read-file-map (kbd "C-i") #'helm-execute-persistent-action) (define-key helm-read-file-map (kbd "C-z") #'helm-select-action))) #+END_SRC ** swiper/ivy Ivy is the new kid on the completion block. I wonder if it can replace helm and ido. #+BEGIN_SRC emacs-lisp (req-package swiper :bind (("C-s" . swiper) ("C-r" . swiper) ("C-c C-r" . ivy-resume) ("C-x i" . imenu) ("C-=" . swiper)) :config (progn (setq ivy-use-virtual-buffers t ivy-re-builders-alist '((internal-complete-buffer . ivy--regex-fuzzy) (t . ivy--regex-plus))) (ivy-set-actions 'ivy-switch-buffer '(("k" (lambda (x) (kill-buffer x) (ivy--reset-state ivy-last)) "kill")))) :init (progn (ivy-mode 1))) #+END_SRC ** counsel #+BEGIN_SRC emacs-lisp (req-package counsel :bind (("M-x" . counsel-M-x) ("" . counsel-M-x) ("" . counsel-M-x) ("C-c M-x" . execute-extended-command) ("C-x C-f" . counsel-find-file) ("C-x b" . counsel-switch-to-projectile-buffer)) :config (progn (defun counsel-switch-to-projectile-buffer (arg) "Forward to `projectile-switch-to-buffer'." (interactive "P") (if (projectile-project-p) (ivy-read (format "Switch to buffer [%s]: " (projectile-project-name)) (projectile-project-buffer-names) :preselect (buffer-name (other-buffer (current-buffer))) :action #'ivy--switch-buffer-action :keymap ivy-switch-buffer-map) (call-interactively #'ivy-switch-buffer))))) #+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 (req-package smex :require ido :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")) (smex-initialize))) #+END_SRC * Modeline I modified the mode-line format to show me less information. Instead, I put some of it in the frame-line at the top. #+BEGIN_SRC emacs-lisp (column-number-mode t) (size-indication-mode t) (defun fill-line-format (line-format) (max 0 (- (window-width) (length (format-mode-line line-format))))) (defvar mode-line-size `((size-indication-mode ((-3 ,(propertize "%p" 'local-map mode-line-column-line-number-mode-map 'mouse-face 'mode-line-highlight ;; XXX needs better description 'help-echo "Size indication mode\n\ mouse-1: Display Line and Column Mode Menu")) " " (-4 "%I"))))) (setq-default mode-line-modes (let ((recursive-edit-help-echo "Recursive edit, type C-M-c to get out")) (list (propertize "%[" 'help-echo recursive-edit-help-echo) `(:propertize ("" mode-name) help-echo "Major mode\n\ mouse-1: Display major mode menu\n\ mouse-2: Show help for major mode\n\ mouse-3: Toggle minor modes" mouse-face mode-line-highlight local-map ,mode-line-major-mode-keymap) '("" mode-line-process) `(:propertize ("" minor-mode-alist) mouse-face mode-line-highlight help-echo "Minor mode\n\ mouse-1: Display minor mode menu\n\ mouse-2: Show help for minor mode\n\ mouse-3: Toggle minor modes" local-map ,mode-line-minor-mode-keymap) (propertize "%n" 'help-echo "mouse-2: Remove narrowing from buffer" 'mouse-face 'mode-line-highlight 'local-map (make-mode-line-mouse-map 'mouse-2 #'mode-line-widen)) (propertize "%]" 'help-echo recursive-edit-help-echo) " ")) mode-line-buffer-identification (list (propertize "%b" 'face 'mode-line-buffer-id)) mode-line-position `((line-number-mode ((column-number-mode ,(propertize "%l:%c" 'local-map mode-line-column-line-number-mode-map 'mouse-face 'mode-line-highlight 'help-echo "Line number and Column number\n\ mouse-1: Display Line and Column Mode Menu") (6 ,(propertize "L%l" 'local-map mode-line-column-line-number-mode-map 'mouse-face 'mode-line-highlight 'help-echo "Line Number\n\ mouse-1: Display Line and Column Mode Menu")))) ((column-number-mode (5 ,(propertize "C%c" 'local-map mode-line-column-line-number-mode-map 'mouse-face 'mode-line-highlight 'help-echo "Column number\n\ mouse-1: Display Line and Column Mode Menu")))))) mode-line-format `("%e" " " mode-line-modes mode-line-misc-info (vc-mode vc-mode) mode-line-end-spaces) header-line-format `("%e" mode-line-front-space mode-line-mule-info mode-line-client mode-line-modified mode-line-auto-compile mode-line-remote " " mode-line-position " " mode-line-size " ⎸ " mode-line-buffer-identification )) (setq frame-title-format '((:eval (if (and (fboundp #'projectile-project-p) (projectile-project-p)) (projectile-project-name))) ": " (:eval (if (buffer-file-name) (buffer-name) "%b")))) #+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 (req-package xrdb-mode :mode (("\\.Xdefaults\\'" . xrdb-mode) ("\\.Xresources\\'" . xrdb-mode))) (req-package haskell-mode :mode (("\\.hs\\'" . haskell-mode))) (req-package nix-mode :mode (("\\.nix\\'" . nix-mode)) :config (progn (add-hook 'nix-mode-hook (lambda () (setq-local indent-tabs-mode nil))))) (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)) (req-package nginx-mode :defer t :mode (("/nginx/servers/" . nginx-mode) ("/nginx/.*\\.d/" . nginx-mode)) :config (progn (setq nginx-indent-tabs-mode t))) (req-package lua-mode :defer t) (req-package ruby-mode :mode (("\\.rb\\'" . ruby-mode) ("\\.cap\\'" . ruby-mode))) (req-package go-mode :mode (("\\.go\\'" . go-mode))) (req-package jinja2-mode :mode (("\\.j2\\'" . jinja2-mode) ("\\.jinja\\'" . jinja2-mode))) (req-package scss-mode :defer t :config (progn (setq scss-compile-at-save nil))) (req-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 (req-package ledger-mode :mode ("\\.ledger\\'" . ledger-mode) :config (progn (defun setup-ledger-mode () (setq-local indent-tabs-mode nil)) (add-hook 'ledger-mode-hook #'setup-ledger-mode) (add-to-list 'smart-tab-disabled-major-modes 'ledger-mode) (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"))) #+END_SRC ** Markdown #+BEGIN_SRC emacs-lisp (req-package markdown-mode :defer t :config (progn (add-hook 'markdown-mode-hook #'turn-on-auto-fill))) #+END_SRC ** Org Org is wünderbar. *** TODO Check whether all this configuration is necessary or helpful. #+BEGIN_SRC emacs-lisp (req-package org :bind (("C-c C-a" . org-agenda-list) ("C-c a" . org-agenda) ("C-c l" . org-store-link)) :defer 10 :init (setq org-replace-disputed-keys t) :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-habit org-checklist) ;; Add time done to ‘done’ tasks org-log-done 'time ;; Allow refiling into any org file org-refile-targets '((org-agenda-files :maxlevel . 3)) org-list-allow-alphabetical t org-pretty-entities t org-table-duration-custom-format 'seconds org-src-fontify-natively t 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) (defadvice org-clock-in (after wicked activate) "Mark STARTED when clocked in" (save-excursion (catch 'exit (org-back-to-heading t) (if (looking-at org-outline-regexp) (goto-char (1- (match-end 0)))) (if (looking-at (concat " +" org-todo-regexp "\\( +\\|[ \t]*$\\)")) (org-todo "STARTED"))))) (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 (defun install-monitor (file secs) (run-with-timer 0 secs (lambda (f p) (unless (< p (second (time-since (elt (file-attributes f) 5)))) (org-mobile-pull))) file secs)) (install-monitor (file-truename (concat (file-name-as-directory org-mobile-directory) org-mobile-capture-file)) 5) ;; Do a pull every 5 minutes to circumvent problems with timestamping ;; (ie. dropbox bugs) (run-with-timer 0 (* 5 60) 'org-mobile-pull))) #+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 (req-package org-babel :require org :defer t :config (org-babel-do-load-languages 'org-babel-load-languages '((ledger . t) (sh . t)))) #+END_SRC **** org-journal I can use this to keep a journal. I should use it. #+BEGIN_SRC emacs-lisp (req-package org-journal :require org :defer t :config (progn (setq org-journal-date-format "%A, %d %B %Y"))) #+END_SRC **** org-mobile ***** TODO Setup org-mobile #+BEGIN_SRC emacs-lisp (req-package org-mobile :require org :defer t :config (progn (setq org-mobile-directory "~/Mobile/Org" org-mobile-inbox-for-pull "~/Mobile/Org/from-mobile.org"))) #+END_SRC * Programming ** cedet *** TODO Setup cedet and see whether it’s useful #+BEGIN_SRC emacs-lisp (req-package cedet :disabled t :config (progn (semantic-load-enable-code-helpers) (global-semantic-idle-completions-mode t) (global-semantic-highlight-func-mode t) (global-semantic-show-unmatched-syntax-mode t) (global-semantic-decoration-mode t))) #+END_SRC ** flycheck On-the-fly error checking in programming modes? Yes please. #+BEGIN_SRC emacs-lisp (req-package flycheck :diminish " ✓" :init (global-flycheck-mode)) #+END_SRC ** golang Go has a few packages to inter-operate with other emacs packages. #+BEGIN_SRC emacs-lisp (when (file-exists-p "src/code.google.com/p/go.tools/cmd/oracle/oracle.el") (req-package oracle :load-path ,(expand-file-name "src/code.google.com/p/go.tools/cmd/oracle/oracle.el" (getenv "GOPATH")) :init (progn (add-hook 'go-mode-hook #'go-oracle-mode)))) (req-package company-go :require go-mode :config (progn (setq company-go-show-annotation t) (defun ap/company-go-setup () (set (make-local-variable 'company-backends) '(company-go))) (add-hook 'go-mode-hook #'ap/company-go-setup))) (req-package go-eldoc :require go-mode :config (progn (add-hook 'go-mode-hook #'go-eldoc-setup))) (req-package go-projectile :require (go-mode go-eldoc projectile) :config (progn (setq go-projectile-switch-gopath 'maybe))) #+END_SRC ** ggtags A nice completion backend for programming modes. #+BEGIN_SRC emacs-lisp (req-package ggtags :commands turn-on-ggtags-mode :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 ** 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. Of course, no tabs in lisps. Even I understand that. #+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) (setq indent-tabs-mode nil)) #+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 (req-package redshank :diminish " Λ" :defer t :init (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 (rename-modeline emacs-lisp-mode "ξ") (add-to-list 'auto-mode-alist '("/Cask\\'" . emacs-lisp-mode)) (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 (req-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 (req-package ielm :defer t :config (progn (add-hook 'ielm-mode-hook (lambda () (run-hooks 'lisp-mode-common-hook))))) #+END_SRC I don’t only use this in elisp. It’s nice to do calculations in other buffers too: it’s faster than quickrun and the parens mean that I don’t have to worry about a selection. #+BEGIN_SRC emacs-lisp (defun eval-and-replace () "Replace the preceding sexp with its value." (interactive) (backward-kill-sexp) (condition-case nil (prin1 (eval (read (current-kill 0))) (current-buffer)) (error (message "Invalid expression") (insert (current-kill 0))))) (bind-key "C-c e" #'eval-and-replace) #+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 **** geiser A REPL thing for Scheme. Hopefully I’ll get to use it more in the future. #+BEGIN_SRC emacs-lisp (req-package geiser :commands (geiser-mode geiser run-geiser run-racket)) #+END_SRC **** slime A REPL thing (and more) for Lisp. #+BEGIN_SRC emacs-lisp (req-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)) (setq inferior-lisp-program (executable-find "sbcl")))) #+END_SRC *** Clojure #+BEGIN_SRC emacs-lisp (req-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))) (req-package clj-refactor :defer t :require clojure-mode :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 (req-package cider :require clojure-mode :defer t :config (progn (setq nrepl-hide-special-buffers t) (unbind-key "C-c C-f" cider-mode-map) (add-hook 'cider-mode-hook #'cider-turn-on-eldoc-mode))) #+END_SRC ** Auto-compile Auto-compile emacs lisp when saving. #+BEGIN_SRC emacs-lisp (req-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 (req-package cc-mode :defer t :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 (req-package quickrun :bind (("C-c C-e" . quickrun))) #+END_SRC ** Web development *** skewer-mode I don’t use this as often as I probably should. I should figure out why that is. #+BEGIN_SRC emacs-lisp (req-package skewer-mode :defer t :init (progn (add-hook 'js2-mode-hook #'skewer-mode) (add-hook 'html-mode-hook #'skewer-html-mode) (add-hook 'css-mode-hook #'skewer-css-mode))) #+END_SRC *** 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 (req-package js2-mode :mode ("\\.js\\'" . js2-mode) :config (progn (defun ap/javascript-setup () (autopair-mode -1) (auto-indent-mode -1)) (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) (add-hook 'js2-mode-hook #'ap/javascript-setup) (setq js2-basic-offset 4 js2-include-node-externs t))) (add-to-list 'auto-mode-alist '("composer\\.lock" . js-mode)) #+END_SRC *** tern Tern understands javascript. It adds really clever documented completions, besides other IDE-like things. #+BEGIN_SRC emacs-lisp (req-package tern :commands ap/enable-tern :config (progn (setq tern-command (list (executable-find "tern"))) (defun ap/enable-tern () (tern-mode 1)) (add-hook 'js2-mode-hook #'ap/enable-tern))) (req-package tern-company :require (tern company)) #+END_SRC *** json-mode #+BEGIN_SRC emacs-lisp (req-package json-mode :mode ("\\.json\\'" . 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 (req-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))) #+END_SRC *** sgml-mode This is for HTML, since old versions of HTML were derived from SGML. #+BEGIN_SRC emacs-lisp (req-package sgml-mode :defer t :config (setq sgml-basic-offset 4)) #+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 (req-package emmet-mode :commands (emmet-mode) :diminish (emmet-mode . " >") :init (progn (if (functionp 'web-mode) (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 (req-package web-mode :mode (("/views/.*\\.php\\'" . web-mode) ("/layouts/.*\\.html\\'" . web-mode) ("/templates/.*\\.php\\'" . web-mode) ("\\.ejs\\'" . web-mode)) :config (setq web-mode-code-indent-offset 4 web-mode-css-indent-offset 4 web-mode-markup-indent-offset 4 web-mode-style-padding 0 web-mode-script-padding 0 web-mode-comment-style 2 web-mode-enable-auto-pairing nil)) #+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 *** mmm-mode With =web-mode= being so good, I don’t really use this much. It’s good for embedded SQL though. #+BEGIN_SRC emacs-lisp (req-package mmm-auto :config (progn (mmm-add-classes '((php-sql :submode sql-mode :front "<<" . ispell-word)) :config (progn (setq ispell-program-name "aspell" ispell-dictionary "british"))) #+END_SRC *** TODO Set up some functions to switch between en-GB and de-DE * 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) (req-package sh-script :mode (("\\.zsh\\'" . shell-script-mode)) :config (setq sh-shell-file "/usr/bin/env zsh")) #+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 (req-package eshell :bind ("C-c s" . eshell) :config (progn (setq eshell-directory-name "~/.emacs.d/eshell") (add-hook 'eshell-load-hook (lambda () (bind-key "C-c C-l" #'helm-eshell-history eshell-mode-map))))) (req-package em-smart :require eshell :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 #+BEGIN_SRC emacs-lisp (req-package esh-buf-stack :require eshell :config (progn (bind-key "M-q" #'eshell-push-command eshell-mode-map)) :init (progn (setup-eshell-buf-stack))) #+END_SRC *** Shells #+BEGIN_SRC emacs-lisp (req-package shell :defer t :config (define-key shell-mode-map (kbd "C-d") 'comint-delchar-or-eof-or-kill-buffer)) (req-package comint :defer t :config (bind-key "C-c C-l" #'helm-comint-input-ring comint-mode-map)) (req-package multi-term :if (not (eq system-type 'windows-nt)) :bind ("C-`" . multi-term-dedicated-toggle)) (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 *** TODO Do I need multi-term? * 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 (req-package align :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) (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 ** 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 Isearch has a keybind for searching for the currently-selected word. I often want to use a symbol though, so this comes in handy. [[http://blog.jorgenschaefer.de/2012/11/emacs-search-for-symbol-at-point.html][Source]] #+BEGIN_SRC emacs-lisp (defun fc/isearch-yank-symbol () "Yank the symbol at point into the isearch minibuffer. C-w does something similar in isearch, but it only looks for the rest of the word. I want to look for the whole string. And symbol, not word, as I need this for programming the most." (interactive) (isearch-yank-string (save-excursion (when (and (not isearch-forward) isearch-other-end) (goto-char isearch-other-end)) (thing-at-point 'symbol)))) (bind-key "C-d" #'fc/isearch-yank-symbol isearch-mode-map) #+END_SRC Sub-word movement is really nice for camel- and Pascal-case #+BEGIN_SRC emacs-lisp (req-package subword :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 (req-package misc :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 (req-package expand-region :bind ("C-M-SPC" . er/expand-region)) #+END_SRC ** Typography I like using typographic symbols, but I don’t always remember (how) to type them. #+BEGIN_SRC emacs-lisp (req-package typopunct :config (progn (typopunct-change-language 'english t) (defconst typopunct-minus (decode-char 'ucs #x2212)) (defadvice typopunct-insert-typographical-dashes (around minus-or-pm activate) (cond ((or (eq (char-before) typopunct-em-dash) (looking-back "\\([[:blank:]]\\|^\\)\\^")) (delete-char -1) (insert typopunct-minus)) ((looking-back "[^[:blank:]]\\^") (insert typopunct-minus)) (t ad-do-it))) (defconst typopunct-ellipsis (decode-char 'ucs #x2026)) (defconst typopunct-middot (decode-char 'ucs #xB7)) ; or 2219 (defun typopunct-insert-ellipsis-or-middot (arg) "Change three consecutive dots to a typographical ellipsis mark." (interactive "p") (cond ((and (= 1 arg) (eq (char-before) ?^)) (delete-char -1) (insert typopunct-middot)) ((and (= 1 arg) (eq this-command last-command) (looking-back "\\.\\.")) (replace-match "") (insert typopunct-ellipsis)) (t (self-insert-command arg)))) (define-key typopunct-map "." 'typopunct-insert-ellipsis-or-middot) (defconst typopunct-times (decode-char 'ucs #xD7)) (defun typopunct-insert-times (arg) (interactive "p") (if (and (= 1 arg) (looking-back "\\([[:blank:]]\\|^\\)\\^")) (progn (delete-char -1) (insert typopunct-times)) (self-insert-command arg))) (define-key typopunct-map "x" 'typopunct-insert-times) (defadvice typopunct-insert-quotation-mark (around wrap-region activate) (let* ((lang (or (get-text-property (point) 'typopunct-language) typopunct-buffer-language)) (omark (if single (typopunct-opening-single-quotation-mark lang) (typopunct-opening-quotation-mark lang))) (qmark (if single (typopunct-closing-single-quotation-mark lang) (typopunct-closing-quotation-mark lang)))) (cond (mark-active (let ((skeleton-end-newline nil) (singleo (typopunct-opening-single-quotation-mark lang)) (singleq (typopunct-closing-single-quotation-mark lang))) (if (> (point) (mark)) (exchange-point-and-mark)) (save-excursion (while (re-search-forward (regexp-quote (string omark)) (mark) t) (replace-match (regexp-quote (string singleo)) nil nil))) (save-excursion (while (re-search-forward (regexp-quote (string qmark)) (mark) t) (replace-match (regexp-quote (string singleq)) nil nil))) (skeleton-insert (list nil omark '_ qmark) -1))) ((looking-at (regexp-opt (list (string omark) (string qmark)))) (forward-char 1)) (t ad-do-it))))) :init (progn (add-hook 'text-mode-hook #'typopunct-mode))) #+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 (req-package avy :bind* (("M-g g" . avy-goto-line) ("M-g M-g" . avy-goto-line) ("C-|" . avy-goto-line) ("C-c SPC" . avy-goto-char)) :config (progn (avy-setup-default) (setq avy-all-windows nil))) #+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 (req-package goto-chg :bind ("C-x 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 (req-package multiple-cursors :defer 1 :config (progn (bind-key "C-." #'mc/mark-next-like-this) (bind-key "C-," #'mc/mark-previous-like-this) (bind-key "M-" #'mc/mark-all-like-this-dwim) (bind-key "C-" #'mc/mark-more-like-this-extended) (bind-key "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 (req-package paredit :diminish "()" :commands (paredit-mode) :init (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 'minibuffer-setup-hook #'conditionally-enable-paredit-mode) (defun conditionally-enable-paredit-mode () "enable paredit-mode during eval-expression" (if (eq this-command 'eval-expression) (paredit-mode 1))))) #+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 (req-package smartparens-config :config (progn (sp-use-smartparens-bindings) (fset 'wrap-with-paren "\C-](") ;; `sp-select-next-thing-exchange' (bind-key "C-(" #'wrap-with-paren sp-keymap) (bind-key "C-)" #'sp-forward-slurp-sexp sp-keymap) (bind-key "M-" #'backward-kill-word sp-keymap) (bind-key "M-?" #'sp-convolute-sexp sp-keymap) (bind-key "C-M-t" #'sp-transpose-sexp sp-keymap) (bind-key "M-r" #'sp-raise-sexp sp-keymap) (bind-key "M-s" #'sp-splice-sexp sp-keymap) (bind-key "M-S" #'sp-split-sexp sp-keymap) (bind-key "M-J" #'sp-join-sexp sp-keymap) (bind-key "M-" #'sp-splice-sexp-killing-backward sp-keymap) (bind-key "M-" #'sp-splice-sexp-killing-forward sp-keymap) (bind-key "C-M-S-k" #'sp-kill-hybrid-sexp sp-keymap) (bind-key "C-S-" #'sp-slurp-hybrid-sexp sp-keymap) (sp-with-modes '(web-mode 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))) #+END_SRC ** move-text Transposing lines, made easier. #+BEGIN_SRC emacs-lisp (req-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 (req-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 ** 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 (req-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 (req-package async) (defun tangle-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)) (async-start `(lambda () ;; Avoid running hooks when tangling. (let ((prog-mode-hook nil) (dest (concat user-emacs-directory "init.el"))) (find-file ,(buffer-file-name)) (require 'ob-tangle) (org-babel-tangle nil dest) (byte-compile-file dest) dest)) (lambda (result) (message "Init tangling completed: %s" result))))) #+END_SRC # Local Variables: # eval: (when (fboundp #'tangle-init) (add-hook 'after-save-hook #'tangle-init)) # End: * End #+BEGIN_SRC emacs-lisp (req-package-finish) #+END_SRC Start a server if possible. A daemon is already a server. #+BEGIN_SRC emacs-lisp (unless (daemonp) (require 'server) (if (server-running-p server-name) (message "Server already appears to be running") (server-start))) #+END_SRC