As my editor of choice I run Emacs. One of the benefits of Emacs is that it’ll install basically anywhere.
This configuration is designed to run in shells as well as on desktops. There are some platform specific optimisations as well.
It’s built using Org mode’s tangling functionality.
My entire Emacs configuration is thus written in a literate programming style, and is contained entirely in this file.
The previous version can be found at bradleywright/emacs-d. This version has been refactored to use traditional Emacs loading techniques and macros for installing packages.
Just check it out straight to the right directory, and use Make to install it:
cd ~/Projects/emacs.d && make
- Left
option
key is remapped toM-
M-3
prints a literal#
(UK Mac keyboards being weird)- We use the Solarized theme
- Font is Inconsolata
- When the Solarized Dark iTerm2 theme is installed, we use the
solarized-dark
color theme - Cut/paste are made to write/read from the clipboard (via
pbcopy
andpbpaste
) - Mouse highlighting works via xTerm capabilities
- Re-map left
option
key toEsc
- Untick
Smart cursor color
The following libraries are included in non-attributable ways, i.e not via package install or via a Git submodule:
- Emacs Starter Kit was a very big early influence, and continues to be helpful.
Copyright 2010 Bradley Wright.
Files are licensed under the same license as Emacs (GPL) unless
otherwise specified. See the COPYING
file for more information.
Any external/third party works included in this work are licensed under their own licenses - refer to the submodules or packages for more information.
Functions and variables defined exclusively for my use are prefixed with my
initials and a slash bw/
to namespace them.
Emacs looks in load-path for Emacs lisp files. require
and other loading
constructs use this when looking for implicit names.
First we define a convenience function bw/add-to-load-path
that adds the
passed in directory to load-path
:
(defun bw/add-to-load-path (dir)
"Adds `dir' to load-path"
(add-to-list 'load-path dir))
and a convenience function for making a proper path out of two strings:
(defun bw/join-dirs (prefix suffix)
"Joins `prefix' and `suffix' into a directory"
(file-name-as-directory (concat prefix suffix)))
Define a base directory bw/dotfiles-dir
that’s relative to the currently
loading file (this file). This means if I deliberately start Emacs with a file
loaded:
emacs -q -l ~/src/emacs/init.el
then bw/dotfiles-dir
will be ~/src/emacs
.
(defconst bw/dotfiles-dir
(file-name-directory
(or (buffer-file-name) load-file-name))
"Base path for customised Emacs configuration")
This variable is important because all other directories I load things from are
relative to it, which means my Emacs config doesn’t need to live in
user-emacs-directory
.
Emacs has many packages which need to store state in files. Generally these are
in ~
or user-emacs-directory
- since my entire ~/.emacs.d
is versioned,
I’d rather all temporary files were stored in a known place, bw/tmp-local-dir
.
This directory is created if it doesn’t exist.
(make-directory
(setq bw/tmp-local-dir
(bw/join-dirs bw/dotfiles-dir ".tmp")) t)
Emacs automatically backs up files while you’re editing them. The default configuration isn’t great though.
First, set up some directories to keep backups:
(make-directory
(setq bw/tmp-backups-dir
(bw/join-dirs bw/tmp-local-dir "backups")) t)
(make-directory
(setq bw/tmp-autosaves-dir
(bw/join-dirs bw/tmp-local-dir "autosaves")) t)
Now use those directories for backups and autosave files:
(setq backup-directory-alist `((".*" . ,bw/tmp-backups-dir))
auto-save-file-name-transforms `((".*" ,bw/tmp-autosaves-dir)))
Always copy files when backing up to avoid breaking symlinks:
(setq backup-by-copying t)
Delete old versions automatically, and keep a limited number around:
(setq delete-old-versions t
kept-new-versions 2
kept-old-versions 2)
Finally, use version numbers in the filenames:
(setq version-control t)
Emacs has a client/server model for editing. The client is invoked via the
emacsclient
command. More information on configuration is available on the
EmacsWiki EmacsClient page.
We make sure the server is running, additionally guarded to check if the version of Emacs we’re using supports the server package:
(when (require 'server nil t)
(unless (server-running-p)
(server-start)))
Emacs comes with a collection of strange defaults. See Magnar Sveen’s sane-defaults.el
file for some commentary.
The default wrap width (known as filling) for Emacs is 70 characters. Modern conventions state that 80 characters is the standard:
(setq-default fill-column 80)
I don’t type double-space sentences, so make sure that Emacs doesn’t look for double-spaces after periods to fill paragraphs correctly:
(setq-default sentence-end-double-space nil)
Most UNIX tools work best when there’s a trailing newline on all files. Enable that option:
(setq require-final-newline t)
I don’t want to leave trailing whitespace in files I touch, so set up a hook that automatically deletes trailing whitespace after every line when saving a file:
(add-hook 'write-file-hooks 'delete-trailing-whitespace)
Emacs has lots of other options for managing superfluous whitespace.
I don’t use tabstops in files, and my default tab width is 4 characters.
It’s worth noting that Emacs can override either of those on a per-file/mode basis, so Makefiles, Ruby etc. will still get the correct indentation rules.
(setq-default
indent-tabs-mode nil
tab-width 4)
Electric indent mode was added in Emacs 24.1, and it enables automatic indentation when typing a newline. More about electric indent mode on Emacs Redux.
First we define convenience toggling functions we can use in a hook (or interactively):
(defun bw/turn-on-electric-indent-mode ()
"Turns on electric-indent-mode"
(interactive)
(electric-indent-mode 1))
(defun bw/turn-off-electric-indent-mode ()
"Turns off electric-indent-mode"
(interactive)
(electric-indent-mode -1))
then we enable it for the generic abstract programming mode prog-mode
,
introduced in Emacs 24.1 (more about prog-mode
on Emacs Redux):
(add-hook 'prog-mode-hook 'bw/turn-on-electric-indent-mode)
I want to have UTF-8 by default. Emacs unfortunately has a few settings that govern encoding, so we should set them all at once:
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
C-a
is mapped to beginning-of-line
by default, which moves point to position
0 on the current line. The irreal blog suggests a smarter alternative that moves
the point to the first non-whitespace character first, and then position 0, with
extra presses toggling the position:
(defadvice move-beginning-of-line (around smarter-bol activate)
;; Move to requested line if needed.
(let ((arg (or (ad-get-arg 0) 1)))
(when (/= arg 1)
(forward-line (1- arg))))
;; Move to indentation on first call, then to actual BOL on second.
(let ((pos (point)))
(back-to-indentation)
(when (= pos (point))
ad-do-it)))
This functionality uses the Emacs concept of advice, which is a way of modifying existing functions in-place without redefining the entire thing.
When changing focus to the minibuffer, stop allowing point to move over the prompt. Code taken from ergoemacs.
(setq minibuffer-prompt-properties (add-to-list 'minibuffer-prompt-properties 'minibuffer-avoid-prompt))
(setq minibuffer-prompt-properties (add-to-list 'minibuffer-prompt-properties 'point-entered))
C-
meansControl
in combination with another key, egC-x
meansCtrl x
M-
meansMeta
in combination with another key. This is usuallyAlt
, or⌘
on OS X (by default).Esc
also serves asMeta
if it’s not separately bound. On OS X I want to use left⌥
forMeta
, and leave right⌥
alone:
(when (and (eq system-type 'darwin) (display-graphic-p))
(setq ns-alternate-modifier 'meta)
(setq ns-right-alternate-modifier nil))
s-
means super key. On OS X I want this to be⌘
:
(when (and (eq system-type 'darwin) (display-graphic-p))
(setq ns-command-modifier 'super))
H-
means hyper key. On OS X I want this to bectrl
to prevent fat fingers:
(when (and (eq system-type 'darwin) (display-graphic-p))
(setq ns-function-modifier 'ctrl))
The below are some remappings I got from Steve Yegge’s Effective Emacs article. They’re designed to map some slightly difficult but very common mappings to things that are easier to type.
As per Yegge’s Item 2. This unmaps the difficult M-x
(usually Alt x
) to C-x
m
, and then add a fat-finger combination of C-x C-m
:
(global-unset-key (kbd "C-x m"))
(global-unset-key (kbd "M-x"))
(global-set-key (kbd "C-x m") 'execute-extended-command)
(global-set-key (kbd "C-x C-m") 'execute-extended-command)
As per Yegge’s Item 3. This copies readline’s C-w
command to
backward-kill-word
, remaps the command that used to live there
(kill-region
), and then enables a fat-finger version of the new kill=region
mapping:
(global-set-key (kbd "C-w") 'backward-kill-word)
(global-set-key (kbd "C-x C-k") 'kill-region)
(global-set-key (kbd "C-c C-k") 'kill-region)
Usually one must type C-x o
to switch between windows - make that quicker by
also mapping M-o
:
(global-set-key (kbd "M-o") 'other-window)
Burying a buffer (removing it from the current window and sending it to the bottom of the stack) is very common for dismissing buffers. Add a mapping for it:
(global-set-key (kbd "C-c y") 'bury-buffer)
Add a key combination to revert the current buffer (re-read the contents from disk):
(global-set-key (kbd "C-c r") 'revert-buffer)
Use ibuffer
instead of the feature-lacking list-buffers
:
(global-set-key (kbd "C-x C-b") 'ibuffer)
On OS X, make sure M-3 is remapped to hash:
(when (eq system-type 'darwin)
(fset 'insert-pound "#")
(define-key global-map "\M-3" #'insert-pound))
This trick I got from a blog post on launcher keymaps. I define my launcher
combo as C-x C-l
, which is normally downcase-region
- a command I use so
infrequently I didn’t even know there was a key binding for it.
Also use s-/
(Apple / on OSX).
(define-prefix-command 'bw/launcher-map)
(define-key ctl-x-map (kbd "C-l") 'bw/launcher-map)
(when (eq system-type 'darwin)
(define-key global-map (kbd "s-/") 'bw/launcher-map))
rather than remembering that it’s bw/launcher-map
, just make a function:
(defun bw/add-launcher (key function)
"Maps FUNCTION to KEY under the `bw/launcher-map' prefix"
(define-key bw/launcher-map key function))
To ensure that all scrollbars, toolbars etc. are turned off, we run this as early as possible.
(dolist (mode '(menu-bar-mode tool-bar-mode scroll-bar-mode))
(when (fboundp mode) (funcall mode -1)))
Turn off the startup screen, and always show *scratch*
.
;; inhibit startup screen
(setq inhibit-startup-screen t
;; Show *scratch* on start
initial-buffer-choice t)
I use Inconsolata as my default coding font. It’s set to render at 18pt:
(when
(display-graphic-p)
(when (find-font (font-spec :name "Inconsolata"))
(set-frame-font "Inconsolata-18" t t)))
Syntax highlighting in Emacs is called font locking. It’s enabled by
font-lock-mode
. This turned on by default in modern Emacs systems, but it’s
worth keeping around:
(global-font-lock-mode t)
Emacs also supports multiple levels of complexity for highlighting. Setting this
value to t
forces it to pick the maximum available (also the default):
(setq font-lock-maximum-decoration t)
Emacs doesn’t display line numbers by the code by default. For that you want Linum mode.
I want to display the current line number in the mode line, and also the current column number:
(line-number-mode 1)
(column-number-mode 1)
Emacs convention is to show help and other inline documentation in the message area. Show help there instead of using an OS tooltip:
(when (display-graphic-p)
(tooltip-mode -1))
Just don’t show them. Use native Emacs controls:
(when (display-graphic-p)
(setq use-dialog-box nil))
Make the window title display the full path of the file I’m currently editing:
(when (display-graphic-p)
(setq frame-title-format
'((:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b")))))
Aside: Emacs calls OS windows frames and divisions within frames windows. More information on frame titles.
On modern operating systems, a vertical bar is used as a cursor:
(when (display-graphic-p)
(setq-default cursor-type 'bar))
Make the cursor blink (interestingly in Emacs 24.4 the cursor automatically stops blinking after a period to conserve CPU).
Make the cursor blink every second:
(when (display-graphic-p)
(setq blink-cursor-interval 1.0)
(blink-cursor-mode 1))
Show the modifier combinations I just typed almost immediately:
(setq echo-keystrokes 0.1)
Don’t make me type yes
or no
to boolean interface questions:
(defalias 'yes-or-no-p 'y-or-n-p)
Don’t make a sound when ringing a bell - flash a visual bell instead:
(setq visible-bell t)
Override the ring-bell-function
to conditionally ring the bell only when it’s
not a valid quit case like hitting esc
or C-g
. Generally this means the bell
will only ring when there’s actually an error raised somehow:
(setq ring-bell-function
(lambda ()
"Only rings the bell if it's not a valid quit case, e.g
keyboard-quit"
(unless (memq this-command
'(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit))
(ding))))
By default Emacs resolves conflicting buffer names by appending a number to
them. For instance, if I open ~/src/thing/init.el
and
~/src/other-thing/init.el
they’ll be named init.el
and init.el<2>
respectively.
We can use Uniquify library to name them thing/init.el
and
other-thing/init.el
, which is much easier to make sense of.
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)
(defun bw/toggle-solarized ()
"Toggles Solarized tone"
(interactive)
(when
(or (custom-theme-enabled-p 'solarized-dark) (custom-theme-enabled-p 'solarized-light))
(cond ((custom-theme-enabled-p 'solarized-dark) (progn
(enable-theme 'solarized-light)
(disable-theme 'solarized-dark)))
((custom-theme-enabled-p 'solarized-light) (progn
(enable-theme 'solarized-dark)
(disable-theme 'solarized-light))))))
Make sure that out-of-Emacs clipboard gets into the kill ring:
(setq save-interprogram-paste-before-kill t)
Besides the keyboard configuration above, there are some other specific things I
do on OS X. On OS X system-type
is the symbol darwin
.
Typically OS X hosts are called things like hostname.localconfig
or
hostname.local
. Make Emacs report that without the extra suffix:
(when (eq system-type 'darwin)
(setq system-name (car (split-string system-name "\\."))))
ispell isn’t generally available on OS X. aspell is available via Homebrew, so let’s use that if we can find it:
(when (and (eq system-type 'darwin) (executable-find "aspell"))
(setq ispell-program-name (executable-find "aspell")))
OS X’s bundled version of ls
isn’t the GNU one, so it doesn’t support the
--dired
flag. Emacs caters for that use case:
(setq dired-use-ls-dired nil)
As of Emacs 24.4, Emacs natively supports proper sRGB values on OS X:
(setq ns-use-srgb-colorspace t)
If you’re not using Emacs 24.4 this variable setting will have no effect. See Homebrew’s Emacs recipe for details of how to get this behaviour in earlier Emacs versions.
Using this configuration, Emacs runs best in iTerm2.
On the desktop, Emacs integrates with the OS X clipboard, so kill
etc. copy to
the clipboard, and yank
copies from the clipboard.
Obviously this doesn’t work in the terminal, so we need to use the
interprogram-(cut|paste)-function
variables to copy/paste. Most of this code
gotten from this blog comment.
(when (and (not (display-graphic-p)) (eq system-type 'darwin))
(defun bw/copy-from-osx ()
"Copies the current clipboard content using the `pbcopy` command"
(shell-command-to-string "pbpaste"))
(defun bw/paste-to-osx (text &optional push)
"Copies the top of the kill ring stack to the OSX clipboard"
(let ((process-connection-type nil))
(let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
(process-send-string proc text)
(process-send-eof proc))))
(setq interprogram-cut-function 'bw/paste-to-osx)
(setq interprogram-paste-function 'bw/copy-from-osx))
On Emacs 24.4 and above, Lion-style fullscreen display is supported. Bind it to
⌘-<return>
.
(when (and (eq system-type 'darwin) (fboundp 'toggle-frame-fullscreen))
(global-set-key (kbd "s-<return>") 'toggle-frame-fullscreen))
On the Yosemite beta, ns-use-native-fullscreen
is nil
.
(when (eq system-type 'darwin)
(setq ns-use-native-fullscreen t))
Like Iterm2:
(when (eq system-type 'darwin)
(global-set-key (kbd "S-s-<return>") 'delete-other-windows))
Renames the major-mode lighter in the modeline. Lifted from What the emacs.d.
(defmacro rename-modeline (package-name mode new-name)
`(eval-after-load ,package-name
'(defadvice ,mode (after rename-modeline activate)
(setq mode-name ,new-name))))
If I’m on OS X, I can fetch passwords etc. from my Keychain. This is much more secure than storing them in configuration on disk:
(defun bw/chomp (str)
"Chomp leading and tailing whitespace from `str'."
(while (string-match "\\`\n \\|^\\s- \\|\\s- $\\|\n \\'" str)
(setq str (replace-match "" t t str))) str)
(defun bw/get-keychain-password (account-name)
"Get `account-name' keychain password from OS X Keychain"
(interactive "sAccount name: ")
(when (executable-find "security")
(bw/chomp
(shell-command-to-string
(concat
"security find-generic-password -wa "
account-name)))))
When I’m in an emacsclient, I probably just want the client to die rather than the entire server. And, when I kill my server, I want Emacs to confirm this with me:
(defun bw/kill-emacs ()
"If this buffer is a client, just kill it, otherwise confirm
the quit."
(interactive)
(if server-buffer-clients
(server-edit)
(if (= (length (frame-list)) 1)
(cond ((y-or-n-p "Quit Emacs? ")
(save-buffers-kill-terminal)))
(save-buffers-kill-terminal))))
Enable this, and override the default command Emacs assigns to kill itself:
(define-key (current-global-map) [remap save-buffers-kill-terminal] 'bw/kill-emacs)
Emacs comes with hundreds of major and minor modes to do many many things. These are the ones I commonly use and have configured.
First let’s define a convenient macro that wraps typical eval-after-load
in
such a way that we don’t need to use progn
to contain the callback logic. This
macro was gotten from Steve Purcell’s emacs.d repo:
(defmacro after-load (feature &rest body)
"After FEATURE is loaded, evaluate BODY."
(declare (indent defun))
`(eval-after-load ,feature
'(progn ,@body)))
occur-mode is a search minor-mode that shows a buffer with all matching results in a popup buffer.
Use the occur-dwim
(do what I mean) function from (or emacs:
(defun occur-dwim ()
"Call `occur' with a sane default."
(interactive)
(push (if (region-active-p)
(buffer-substring-no-properties
(region-beginning)
(region-end))
(let ((sym (thing-at-point 'symbol)))
(when (stringp sym)
(regexp-quote sym))))
regexp-history)
(call-interactively 'occur))
Bind it to a launcher.
(bw/add-launcher "o" 'occur-dwim)
org-mode is a plain text system for organising information and notes.
Don’t auto-fold my documents:
(setq org-startup-folded nil)
When editing nested source code, always accept Emacs Lisp:
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)))
and automatically apply syntax highlighting:
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
When using imenu, make sure I can follow the outline to the full available depth:
(setq org-imenu-depth 6)
ido is a mode for narrowing candidates as you type. It has excellent integration with buffer switching and finding files. Mastering Emacs has a good guide to Ido.
First we enable ido-mode
globally and enable ido-everywhere
, which enables
Ido for buffer and file reading:
(after-load 'ido
(ido-mode t)
(ido-everywhere t))
Force Ido to ignore Dropbox cruft:
(after-load 'ido
(add-to-list 'ido-ignore-files "Icon\n"))
Configure Ido (see comments for more information):
(after-load 'ido
(setq
;; Speed up ido by using less candidates
ido-max-prospects 10
;; Match arbitrary points in strings
ido-enable-prefix nil
;; Match across entire string
ido-enable-flex-matching t
;; Create a new buffer if there's no match candidate
ido-create-new-buffer 'always
;; Don't try and guess if the string under point is a file
ido-use-filename-at-point nil
;; case-insensitive matching
ido-case-fold t
;; don't store old files as virtual buffers
ido-use-virtual-buffers nil))
Store ido
temporary directory cache elsewhere:
(setq ido-save-directory-list-file (expand-file-name ".ido.last" bw/tmp-local-dir))
Finally load Ido:
(require 'ido)
Emacs has robust bookmarking functionality. It uses a file to persit the list of bookmarks, so make sure that file is in my custom temporary directory:
(after-load 'bookmark
(setq bookmark-default-file (expand-file-name ".emacs.bmk" bw/tmp-local-dir)))
eldoc-mode is a minor mode that displays context-sensitive help when editing
Emacs lisp (eg information about arity of functions). Enable that for
emacs-lisp-mode
:
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
As of 24.2, Emacs ships with a robust Python mode. However, when navigating
SnakeCase
words (eg class names), forward-word
etc don’t work correctly.
We can work around that using subword-mode:
(add-hook 'python-mode-hook (lambda () (subword-mode 1)))
Google’s Bazel project uses BUILD
files that closely resemble Python:
(add-to-list 'auto-mode-alist '("BUILD\\'" . python-mode))
As of 24.4, Emacs comes with a much better Ruby mode. However it doesn’t come
with subword-mode
enabled by default:
(after-load 'ruby-mode
(add-hook 'ruby-mode-hook (lambda () (subword-mode 1))))
Add Puppetfile
files to ruby-mode:
(add-to-list 'auto-mode-alist '("[pP]uppetfile\\'" . ruby-mode))
Hippie expand is a more feature complete completion engine than the default
dabbrev engine. The main feature I use over dabbrev
is that it supports a wide
range of backends for finding completions - dabbrev
only looks at currently
open buffers.
First we customise the types of things it looks for:
(setq hippie-expand-try-functions-list
'(try-expand-dabbrev
try-expand-dabbrev-all-buffers
try-expand-dabbrev-from-kill
try-complete-file-name-partially
try-complete-file-name
try-expand-all-abbrevs
try-expand-list
try-expand-line
try-complete-lisp-symbol-partially
try-complete-lisp-symbol))
Then we override dabbrev-expand
’s keybinding to use hippie-expand
instead
(normally this is M-/
):
(define-key (current-global-map) [remap dabbrev-expand] 'hippie-expand)
tramp-mode
is a package that provides remote file editing, eg find-file
/user@host:file
. This allows one to edit files on other servers using your
local Emacs (rather than the Vim user’s equivalent of editing the file on the
server).
All of the below are wrapped in an after-load
construct because tramp-mode
isn’t loaded by default on older versions of Emacs.
First we set the default mode to be ssh
(it’s normally scp
). There are two
reasons for this choice:
ssh
takes a port number as an argument, whereasscp
doesn’t- It’s apparently faster for smaller files
(after-load 'tramp
(setq tramp-default-method "ssh"))
We also want to alter the list of allowed proxies (tramp uses a whitelist for
patterns that it can remotely access) so I can edit remote files as sudo, eg
find-file /sudo:example.com/etc/something-owned-by-root
.
I got this code from the Multi-hops section of the tramp manual.
(after-load 'tramp
(add-to-list 'tramp-default-proxies-alist
'(nil "\\`root\\'" "/ssh:%h:")))
Also make sure we can edit local files as sudo - this is normally disallowed for security reasons:
(after-load 'tramp
(add-to-list 'tramp-default-proxies-alist
'((regexp-quote (system-name)) nil nil)))
More on the last two incantations at emacs-fu’s guide to editing files owned by root.
eshell is a shell-like command interpreter built with Emacs lisp. It integrates well with Emacs, and can be a convenient way to get a shell without invoking bash or similar (provided you don’t want any interactive commands).
There’s a great guide to mastering eshell on Mastering Emacs.
eshell has a directory where it stores bookmarks and other temporary cruft - move that out of the way:
(setq eshell-directory-name (bw/join-dirs bw/tmp-local-dir "eshell"))
When using the ssh
command (or vagrant ssh
, which is really the same thing),
we’ll want to jump into something that’s an actual terminal emulator like
ansi-term
(eshell won’t be able to deal with the login on the remote machine):
(after-load 'esh-opt
(require 'em-term)
(add-to-list 'eshell-visual-commands "ssh")
(when (fboundp 'eshell-visual-subcommands)
(add-to-list 'eshell-visual-subcommands '("vagrant" "ssh"))))
Define a keybinding to get an eshell
buffer anywhere:
(global-set-key (kbd "C-c C-t e") 'eshell)
ansi-term is a terminal emulator written in Emacs Lisp. It’s more like a traditional terminal emulator than eshell.
Force ansi-term to be UTF-8 after it launches:
(defadvice ansi-term (after bw/advise-ansi-term-coding-system activate)
(set-buffer-process-coding-system 'utf-8-unix 'utf-8-unix))
When exiting a terminal buffer (either with exit
or EOF
), automatically kill
the buffer:
(defadvice term-sentinel (around bw/advice-term-sentinel (proc msg) activate)
(if (memq (process-status proc) '(signal exit))
(let ((buffer (process-buffer proc)))
ad-do-it
(kill-buffer buffer))
ad-do-it))
Always pick my default shell, rather than prompting me (from: @echosa’s improving ansi-term):
(defadvice ansi-term (before use-default-shell activate)
(interactive (list (getenv "SHELL"))))
Make sure that yank
always works in ansi-term:
(defun bw/ensure-term-paste (&optional string)
(interactive)
(process-send-string
(get-buffer-process (current-buffer))
(if string string (current-kill 0))))
(add-hook 'term-mode-hook (lambda ()
(define-key term-raw-map [remap yank] #'bw/ensure-term-paste)))
recentf stores a list of recently opened files.
Never clean up the list:
(after-load 'recentf
(setq recentf-auto-cleanup 'never))
The list of files contains any files Emacs has read, not just files I’ve explicitly opened. Clean that list to exclude Emacs metafiles, package cruft etc.
TODO: refactor to use recentf-keep
: http://www.emacswiki.org/emacs/RecentFiles#toc18
(after-load 'recentf
(setq recentf-exclude '("[/\\]\\.elpa/" "[/\\]\\.ido\\.last\\'" "[/\\]\\.git/" ".*\\.gz\\'" ".*-autoloads\\.el\\'" "[/\\]archive-contents\\'" "[/\\]\\.loaddefs\\.el\\'" "url/cookies" ".*\\emacs.bmk\\'")))
Save the most recent 100 items (this is manily to keep the list low for ido):
(after-load 'recentf
(setq recentf-max-saved-items 100))
Customise the place recentf
persists its list of items:
(after-load 'recentf
(setq recentf-save-file (expand-file-name ".recentf" bw/tmp-local-dir)))
Strip $HOME
from the front of recentf
candidate files:
(after-load 'recentf
(add-to-list 'recentf-filename-handlers 'abbreviate-file-name))
I want easy access to my recent files, so define a function that lets me use ido
to search over them. Bind this to C-x C-r
(C-c C-r
is used in modes like
=org=mode):
(after-load 'recentf
(after-load 'ido
(defun bw/recentf-ido-find-file ()
"Find a recent file using ido."
(interactive)
(let ((file (ido-completing-read "Recently: " recentf-list nil t)))
(when file
(find-file file))))
(bw/add-launcher "r" 'bw/recentf-ido-find-file)))
Now enable recentf
:
(after-load 'recentf
(recentf-mode 1))
(require 'recentf)
ediff is a full-featured visual diff and merge tool, built into Emacs.
Make sure that the window split is always side-by-side:
(setq ediff-split-window-function 'split-window-horizontally)
Ignore whitespace changes:
(setq ediff-diff-options "-w")
Only ever use one set of windows in one frame:
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
Emacs has a built-in package manager.
Rather than using Git submodules or similar my Emacs configuration is set up to automatically download and install any required packages at load time. This makes my configuration fully portable.
First set up convenience function (borrowed from Steve Purcell’s emacs config) that installs a package if it’s not already installed:
(defun require-package (package &optional min-version no-refresh)
"Install given PACKAGE, optionally requiring MIN-VERSION.
If NO-REFRESH is non-nil, the available package lists will not be
re-downloaded in order to locate PACKAGE."
(if (package-installed-p package min-version)
t
(if (or (assoc package package-archive-contents) no-refresh)
(package-install package)
(progn
(package-refresh-contents)
(require-package package min-version t)))))
The default value for package-user-dir
is ~/.emacs.d/elpa
- since these are
third-party packages that are dynamically installed I’d prefer them to be in a
hidden directory.
Packages are also byte compiled upon installation, so namespace the install directory to the version of Emacs I’m using.
Final result should be something like ~/.emacs.d/.elpa/24.3.93.1/
.
(after-load 'package
(setq package-user-dir
(bw/join-dirs (bw/join-dirs bw/dotfiles-dir ".elpa") emacs-version)))
By default Emacs only installs files from ELPA. Some of these packages are old or out of date, and they don’t track GitHub repositories.
I want to also add:
- MELPA (tracks GitHub repositories, is much more comprehensive)
- MELPA stable (like MELPA, but pinned to specific versions)
(after-load 'package
(setq package-archives
'(("gnu" . "http://elpa.gnu.org/packages/")
("melpa" . "http://melpa.org/packages/")
("melpa-stable" . "http://stable.melpa.org/packages/"))))
If we’re using Emacs 25.1 or greater, configure the relative priority of those archives:
(after-load 'package
(setq package-archive-priorities
'(("melpa-stable" . 20)
("gnu" . 10)
("melpa" . 0))))
Some packages need to be pinned to ensure they come from the right place:
(setq package-pinned-packages '((php-mode . "melpa")
(ivy . "melpa")
(swiper . "melpa")
(go-mode . "melpa")
(solarized-theme . "melpa")
(smartparens . "melpa")
(projectile . "melpa")
(editorconfig . "melpa")
(magit . "melpa-stable")
(rjsx-mode . "melpa")))
Finally we initialise the package manager:
(package-initialize)
diminish removes or abbreviates the minor mode indicators that can clutter up one’s modeline.
(require-package 'diminish)
Diminish subword-mode
, eldoc-mode
, and auto-revert-mode
:
(after-load 'diminish
(after-load 'subword
(diminish 'subword-mode))
(after-load 'eldoc
(diminish 'eldoc-mode))
(after-load 'autorevert
(diminish 'auto-revert-mode)))
paradox is an advanced package.el frontend with GitHub integration.
(require-package 'paradox)
Force paradox
into a fullframe:
(after-load 'fullframe
(fullframe paradox-list-packages paradox-quit-and-close nil))
Automatically ‘star’ packages on GitHub after I install them (so I can easily
follow changes to them). Note that this requires a Personal Access Token with
public_repo
permission, added to the MacOS Keychain with an account name of
paradox-github-token
:
(let ((github-token (bw/get-keychain-password "paradox-github-token")))
(setq paradox-automatically-star github-token)
(setq paradox-github-token github-token))
Add launch command:
(bw/add-launcher "p" 'paradox-list-packages)
Paradox now supports an asynchronous mode which requires the async
package:
(require-package 'async)
(setq paradox-execute-asynchronously t)
OS X doesn’t use the environment variables available in a shell in a GUI environment (more here).
Since Emacs runs shell commands regularly it’s important that the same PATH
is
available to my editor as Homebrew etc. set and use.
exec-path-from-shell is a package that copies across PATH
and other variables
to the Emacs environment.
I only want this to be installed and enabled on OS X.
(when (and (eq system-type 'darwin) (display-graphic-p))
(require-package 'exec-path-from-shell)
(setq exec-path-from-shell-check-startup-files nil)
(setq exec-path-from-shell-variables '("PATH" "MANPATH" "SHELL"))
(exec-path-from-shell-initialize))
smex is an advanced completion mode for execute-extended-command
(usually
known as M-x
).
(require-package 'smex)
Replace execute-extended-command
’s keyboard shortcuts:
(define-key (current-global-map) [remap execute-extended-command] 'smex)
Make sure we stop the annoying “click this menubar” advice in the buffer:
(setq-default smex-key-advice-ignore-menu-bar t)
Move smex
’s cache file out of the home directory:
(setq smex-save-file (expand-file-name ".smex-items" bw/tmp-local-dir))
fullframe is a minor mode which allows certain buffers to take over the full frame using advice.
(require-package 'fullframe)
Magit is an Emacs interface to Git. It’s very feature-rich and I find it intuitive.
magit-status
is the main command to launch Magit. It’s autoloaded
so I don’t
need to load Magit first.
(global-set-key (kbd "C-c g") 'magit-status)
(bw/add-launcher "g" 'magit-status)
magit-grep
isn’t autoloaded
, so I need to explicitly load it before binding
it:
(autoload 'magit-grep "magit" "Grep for files" t)
(global-set-key (kbd "C-c f") 'magit-grep)
Since I use Magit I don’t need to use Emacs’s native vc-mode:
(delete 'Git vc-handled-backends)
When performing a completing-read within Magit, I’d like to use IDO:
(setq magit-completing-read-function 'magit-ido-completing-read)
Open the magit-status
buffer in the same window as the current buffer:
(setq magit-display-buffer-function 'magit-display-buffer-fullframe-status-v1)
Highlight individual word and letter changes when showing hunk diff overlays:
(setq magit-diff-refine-hunk t)
Don’t tell me when Magit reverts buffers:
(setq magit-revert-buffers 'silent)
When Magit takes a while to call out to Git, pop the process buffer after 10 seconds so I can look for issues:
(setq magit-process-popup-time 10)
Always show the verbose
diff in commit windows:
(setq magit-commit-arguments '("--verbose"))
Always set the upstream when pushing:
(setq magit-push-arguments '("--set-upstream"))
Finally we can install Magit:
(require-package 'magit)
When launching magit-blame-mode
, we want to switch into emacs-mode
:
(defadvice magit-blame-mode (after switch-to-emacs-mode-if-evil activate)
(when evil-mode
(if magit-blame-mode
(evil-emacs-state 1)
(evil-normal-state 1))))
gitignore-mode is a major mode for editing gitignore
files:
(require-package 'gitignore-mode)
gitconfig-mode is a major more for editing gitconfig
files:
(require-package 'gitconfig-mode)
ido-ubiquitous mode enables ido in many more places than the default ido setup:
(require-package 'ido-completing-read )
(ido-ubiquitous-mode 1)
ido-vertical mode renders the ido prompt vertically instead of horizontally. I find this easier to read.
(require-package 'ido-vertical-mode)
(ido-vertical-mode) ;; autoloaded
Because it’s displayed vertically and I want to save screen real estate, I want to reduce the maximum number of candidates ido displays:
(setq ido-max-prospects 5)
Make C-n
and C-p
work in vertical mode:
(setq ido-vertical-define-keys 'C-n-and-C-p-only)
flx-ido is an advanced flex-matching algorithm that’s significantly faster and more accurate than the built-in method.
(require-package 'flx-ido)
The flx-ido
documentation suggests upping the threshold at which GC occurs
within Emacs so that flx
can cache its candidate lists for longer:
(setq gc-cons-threshold 20000000)
Finally we cause flx-ido-mode
to take over ido:
(flx-ido-mode 1)
avy allows one to jump around the buffer to named characters (it’s easier to watch the video on that link than explain).
(require-package 'avy)
Bind it:
(global-set-key (kbd "C-c SPC") 'avy-goto-word-or-subword-1)
(global-set-key (kbd "C-c j") 'avy-goto-word-or-subword-1)
(global-set-key (kbd "C-<return>") 'avy-goto-line)
(bw/add-launcher "j" 'avy-goto-word-or-subword-1)
(bw/add-launcher "J" 'avy-goto-line)
popwin is a popup window manager that helps make the behaviour of compilation buffers, search buffers etc. a bit more sane.
(require-package 'popwin)
As well as the defaults, I want ag, magit, flycheck and occur to ‘pop’. I don’t want to auto-select the Magit process buffer as it’s for information only.
(after-load 'popwin
(add-to-list 'popwin:special-display-config `"*ag search*")
(add-to-list 'popwin:special-display-config `("*magit-process*" :noselect t))
(add-to-list 'popwin:special-display-config `"*Flycheck errors*")
(add-to-list 'popwin:special-display-config `"*Occur*")
(add-to-list 'popwin:special-display-config `("*Compile-Log*" :noselect t))
(add-to-list 'popwin:special-display-config `("*Paradox Report*" :noselect t))
(add-to-list 'popwin:special-display-config `("\\*godoc" :regexp t)))
Load popwin and configure keyboard shortcuts:
(require 'popwin)
(popwin-mode 1)
(global-set-key (kbd "C-c P") 'popwin:popup-last-buffer)
(when (eq system-type 'darwin)
(global-set-key (kbd "s-P") 'popwin:popup-last-buffer))
ag is an Emacs frontend to the ag command, a grep-like code-searching tool. It’s installed via Homebrew on my Mac.
(require-package 'ag)
Set up some key bindings:
(global-set-key (kbd "C-c f") 'ag-project)
(global-set-key (kbd "C-c a") 'ag)
(when (eq system-type 'darwin)
(global-set-key (kbd "s-F") 'ag-project)
(global-set-key (kbd "s-A") 'ag))
(bw/add-launcher "a" 'ag-project)
(bw/add-launcher "A" 'ag)
Make sure that we re-use the ag
buffers - without this my buffer list is full
of buffers named after the project root.
(setq ag-reuse-buffers t)
Highlight search results using isearch
highlight faces (otherwise it just
copies them from the shell):
(setq ag-highlight-search t)
(add-hook 'ag-mode-hook
(lambda ()
(copy-face 'lazy-highlight 'ag-match-face)))
wgrep-ag allows me to edit ag
results directly from the buffer.
(require-package 'wgrep-ag)
Always save the buffers on exit:
(setq wgrep-auto-save-buffer t)
projectile is a minor mode for performing commands over a single ‘project’ or grouping of files.
Install and initialise projectile from the main repo:
(require-package 'projectile)
(projectile-global-mode)
I want my keyboard shortcuts to be the same in Projectile as in non-Projectile buffers, so do some remapping:
(after-load 'projectile
(define-key projectile-mode-map [remap magit-find-file-completing-read] 'projectile-find-file)
(define-key projectile-mode-map [remap ag-project] 'projectile-ag))
Since I use ag
, always use that instead of grep
:
(after-load 'projectile
(define-key projectile-mode-map [remap projectile-grep] 'projectile-ag))
Also define a convenience keyboard shortcut to switch between buffers from the same project:
(after-load 'projectile
(global-set-key (kbd "s-b") 'projectile-switch-to-buffer)
(global-set-key (kbd "C-x 4 s-b") 'projectile-switch-to-buffer-other-window)
(bw/add-launcher "s" 'projectile-switch-project))
Provide some advice to projectile-current-project-files
so it uses the
magit-find-file
library when we’re in a Git repository - using Magit’s process
manager is significantly faster than Projectile’s own Git interaction, which
creates a new shell process each time. Since magit-find-file
might be loaded
at any time, just make sure this advice runs after everything has finished:
(add-hook 'after-init-hook
(lambda ()
(when (fboundp 'magit-find-file-completing-read)
(defadvice projectile-current-project-files (around bw/use-magit-find-file activate)
"If magit-find-file-completing-read is available use that to
call the files instead of Projectile's native caller - this is
much much faster"
(autoload 'magit-find-file-files "magit-find-file")
(autoload 'magit-git-repo-p "magit-git")
(if (magit-git-repo-p (projectile-project-root))
(setq ad-return-value (magit-find-file-files))
ad-do-it)))))
I use the solarized dark theme in my editor. I use bbatsoz’s variant as it is more up to date and has better compatibility with most Emacs packages.
solarized-theme doesn’t seem to follow package versioning, so just pull the latest.
Install and configure solarized-theme:
(require-package 'solarized-theme)
(setq x-underline-at-descent-line t)
(setq solarized-use-variable-pitch nil)
(load-theme 'solarized-dark t t)
(load-theme 'solarized-light t t)
(add-hook 'after-init-hook (lambda ()
(enable-theme 'solarized-dark)))
magit-find-file is a package that uses Magit’s process buffers to emulate
SublimeText’s Command p
functionality within Git repositories.
(require-package 'magit-find-file)
Set up keybindings for it, particularly the SublimeText equivalent:
(global-set-key (kbd "C-c t") 'magit-find-file-completing-read)
(global-set-key (kbd "M-p") 'magit-find-file-completing-read)
(when (eq system-type 'darwin)
(global-set-key (kbd "s-p") 'magit-find-file-completing-read))
(bw/add-launcher "t" 'magit-find-file-completing-read)
evil is a very full-featured Vim emulator for Emacs.
(require-package 'evil)
evil-leader is a way of using Vim’s leader key concept in Emacs. Since Emacs already supports nested key bindings, this is really just for convenience.
Install evil-leader
, and enable it globally:
(require-package 'evil-leader)
(global-evil-leader-mode 1)
and set it to ,
(the default is \
):
(evil-leader/set-leader ",")
Now set up all the evil-leader
powered shortcuts I want:
(evil-leader/set-key
"b" 'ido-switch-buffer
"d" 'dired-jump
"k" 'kill-this-buffer
"K" 'kill-buffer
"l" 'linum-mode
"o" 'occur
"O" 'browse-url
"P" 'popwin:popup-last-buffer
"w" 'save-buffer
"x" 'smex
"y" 'bury-buffer)
Now we automatically copy across everything from bw/launcher-map
to ensure I
easily retain muscle memory:
(dolist (entry (cdr bw/launcher-map))
(evil-leader/set-key
(key-description (vector (car entry))) (cdr entry)))
Set up some defaults for evil.
Firstly, stop Evil from making the cursor color invisible sometimes:
(after-load 'evil
(setq evil-default-cursor t))
Make sure that sideways motion keys (h
, l
etc.) wrap around to the
next/previous lines:
(after-load 'evil
(setq evil-cross-lines t))
When starting Evil, start in normal
mode:
(after-load 'evil
(setq evil-default-state 'normal))
Include the first and last character when moving to the start or end of lines:
(after-load 'evil
(setq evil-want-visual-char-semi-exclusive t))
When exiting insert
mode, don’t move the cursor:
(after-load 'evil
(setq evil-move-cursor-back nil))
Use ido-find-file
when using the :e
ex-command - but only after typing a
space (e
by itself will still reload):
(define-key evil-ex-map "e " 'ido-find-file)
diminish abbrev-mode
, which is bundled with evil:
(after-load 'diminish
(diminish 'abbrev-mode))
Also diminish undo-tree-mode, a mode which allows one to visualise their undo/redo history. This mode is bundled with evil:
(after-load 'undo-tree
(diminish 'undo-tree-mode))
Finally, invoke evil-mode
using my launcher:
(bw/add-launcher "e" 'evil-mode)
Evil has some annoying defaults that I don’t want to unlearn.
C-e
is normally evil-copy-from-below
in insert
mode - I’d rather it was
end-of-line
:
(define-key evil-insert-state-map "\C-e" 'end-of-line)
C-g
is the default ‘exit everything’ key in Emacs - make it do the same thing
in Evil (these mappings have been manually copied from evil-maps.el):
(define-key evil-normal-state-map "\C-g" 'evil-force-normal-state)
(define-key evil-visual-state-map "\C-g" 'evil-exit-visual-state)
(define-key evil-insert-state-map "\C-g" 'evil-normal-state)
(define-key evil-replace-state-map "\C-g" 'evil-normal-state)
(define-key evil-ex-completion-map "\C-g" 'abort-recursive-edit)
On OS X, evil copies every single visual state move to the kill ring, which in turns copies it to my system clipboard. I don’t want that to happen.
This has been filed as a bug against evil, and most of the code has come from this StackOverflow question:
(defadvice evil-visual-update-x-selection (around clobber-x-select-text activate)
(unless (featurep 'ns)
ad-do-it))
evil supports a default starting state for different major modes. I often want
evil to start in emacs-mode
, for example:
(dolist (mode-map '((ag-mode . emacs)
(cider-repl-mode . emacs)
(comint-mode . emacs)
(eshell-mode . emacs)
(fundamental-mode . emacs)
(git-commit-mode . insert)
(git-rebase-mode . emacs)
(help-mode . emacs)
(paradox-menu-mode . emacs)
(term-mode . emacs)
(ag-mode . emacs)))
(evil-set-initial-state `,(car mode-map) `,(cdr mode-map)))
smartparens is a paredit like minor-mode for many more things than just Lisp.
show-smartparens-mode
is a replacement mode for show-paren-mode
.
(require-package 'smartparens)
(require 'smartparens-config)
(show-smartparens-global-mode 1)
company-mode is a modern and modular completion framework (the other one Emacs
people use is autocomplete. I chose company
because it’s well-maintained and
has better code for integrating with).
I don’t want company
to auto-start - it should only pop when I ask for it:
(after-load 'company
(setq company-idle-delay nil))
I want it to attempt a completion immediately after a .
character - without
this I need a few characters before it’ll show candidates:
(after-load 'company
(setq company-minimum-prefix-length 0))
Show candidates immediately rather than waiting:
(after-load 'company
(setq company-echo-delay 0))
Make the lighter shorter:
(after-load 'company
(after-load 'diminish
(diminish 'company-mode "com")))
Define a function to enable company-mode and overwrite hippie’s key binding for the local buffer only (this means I can use the same key binding for completion no matter which minor mode I’m using):
(defun bw/enable-company-mode ()
"Enables company-mode and overloads hippie-expand's binding"
(company-mode 1)
(define-key (current-local-map) [remap dabbrev-expand] 'company-complete))
Add this function to any modes derived from prog-mode
:
(after-load 'company
(add-hook 'prog-mode-hook 'bw/enable-company-mode))
If I’m using evil, I’ll need to create a new function which acts like a lambda (and ignores arguments):
(defun bw/company-complete-lambda (arg)
"Ignores passed in arg like a lambda and runs company-complete"
(company-complete))
And then bind that to the functions evil uses to complete:
(after-load 'evil
(setq
evil-complete-next-func 'bw/company-complete-lambda
evil-complete-previous-func 'bw/company-complete-lambda))
(require-package 'company)
(require 'company)
flycheck is a modern, more easily customisable version of flymake. It’s used to perform on-the-fly syntax checking and linting.
(require-package 'flycheck)
(after-load 'flycheck
(setq
;; don't show anything in the left fringe
flycheck-indication-mode nil))
(require 'flycheck)
I use js2-mode for editing JavaScript. js2-mode is a JavaScript major mode that includes a full syntax parser written in Emacs Lisp.
(require-package 'js2-mode)
(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
js2-mode
isn’t auto-loaded for *.js
files, as Emacs ships with a default
JavaScript major mode, so I need the final line to make sure I use the right
mode.
The default lighter for js2-mode Javascript-IDE
, which is too long. Rename it:
(rename-modeline "js2-mode" js2-mode "JS2")
JavaScript classes are typically written in CamelCase
, so enabled
subword-mode
:
(add-hook 'js2-mode-hook (lambda () (subword-mode 1)))
Highlight everything:
(after-load 'js2-mode
(setq js2-highlight-level 3))
Always indent by 4 spaces:
(after-load 'js2-mode
(setq js2-basic-offset 3))
Make the closing bracket position indent itself idiomatically:
(after-load 'js2-mode
(setq js2-consistent-level-indent-inner-bracket-p t))
Allow for multi-line var
declaration indenting:
(after-load 'js2-mode
(setq js2-pretty-multiline-decl-indentation-p t))
I use jslint on the command line (via node.js) to provide syntax checking/linting, and this is integrated with flycheck.
This repository includes an npm manifest that installs a local copy of JSLint.
Add the node_modules
binary path to my exec path.
(after-load 'flycheck
(add-to-list 'exec-path (concat bw/dotfiles-dir "node_modules/.bin/")))
Define a custom checker that supports the output of the --terse
flag to
JSLint, and enable it only for js2-mode.
(after-load 'flycheck
(flycheck-define-checker javascript-jslint-reporter
"JSLint based checker"
:command ("jslint" "--terse" source)
:error-patterns
((warning line-start (1 nonl) ":" line ":" column ":" blank (message) line-end))
:modes js2-mode))
Finally, enable my custom checker when js2-mode is enabled. This also dynamically disables js2-mode’s built-in linting functionality so it doesn’t clash.
(after-load 'flycheck
(defun bw/turn-on-flycheck-mode-js2 ()
"Turn on and define JS2 mode checker"
(set (make-local-variable 'js2-highlight-external-variables) nil)
(set (make-local-variable 'js2-strict-missing-semi-warning) nil)
(flycheck-select-checker 'javascript-jslint-reporter)
(flycheck-mode 1))
(add-hook 'js2-mode-hook 'bw/turn-on-flycheck-mode-js2))
Install rjsx-mode:
(package-install 'rjsx-mode)
Go is an open source language created by Google.
go-mode is a major mode for editing .go
files. It has excellent integration
with the Go compiler and toolchain.
Install go-mode from latest:
(require-package 'go-mode)
Make sure we run gofmt before saving any Go files:
(after-load 'go-mode
(add-hook 'before-save-hook 'gofmt-before-save))
Make sure we capture the GOPATH
environment variable on OS X:
(when (eq system-type 'darwin)
(after-load 'exec-path-from-shell
(exec-path-from-shell-copy-env "GOPATH")))
Make sure that if we’re using goenv
or gom
we can detect that with
projectile:
(after-load 'projectile
(add-to-list 'projectile-project-root-files ".go-version")
(add-to-list 'projectile-project-root-files "Gomfile"))
Because I use eldoc
, which shows the function signatures in the message area,
I never actually use godef-describe
(it’s the same info). Instead, let’s allow
me to jump to the godoc
info for the symbol at point.
(after-load 'go-mode
(define-key go-mode-map [remap godef-describe] 'godoc-at-point))
flycheck has excellent golang integration, so enable it:
(after-load 'go-mode
(after-load 'flycheck
(add-hook 'go-mode-hook 'flycheck-mode-on-safe)))
Because Go is a compiled language, we can inspect functions statically and provide documentation in the editor using eldoc:
(require-package 'go-eldoc)
(after-load 'go-mode
(add-hook 'go-mode-hook 'go-eldoc-setup))
Because of libraries like gocode, Go has very good completion. I use company for
completion, so let’s integrate with that. Note this requires gocode
to be
installed on the system before it’ll work.
First I define a hook lambda that deletes all other company backends - gocode is so accurate that I don’t need any other suggestions:
(defun bw/setup-company-go ()
"Hook for running on company-go"
(set (make-local-variable 'company-backends) '(company-go)))
Now add the hook:
(after-load 'company-go
(add-hook 'go-mode-hook 'bw/setup-company-go))
and install and load company-go
:
(after-load 'go-mode
(after-load 'company
(require-package 'company-go)
(require 'company-go)))
puppet-mode is a major mode for editing .pp
files.
(require-package 'puppet-mode)
markdown-mode is a major mode for editing Markdown files.
(require-package 'markdown-mode)
There’s no official Markdown file extension, so support all the unofficial ones:
(add-to-list 'auto-mode-alist '("\\.md$" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.markdown$" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.ft$" . markdown-mode)) ;; FoldingText
paredit is a minor mode for editing S-expressions in a balanced way. It’s a very good way to edit Lisp, Clojure etc. files. More on EmacsWiki.
(require-package 'paredit)
Enable it for Emacs Lisp files:
(add-hook 'emacs-lisp-mode-hook 'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook 'enable-paredit-mode)
Conditionally enable it in the minibuffer when entering an expression:
(defun bw/conditionally-enable-paredit-mode ()
(if (eq this-command 'eval-expression)
(enable-paredit-mode)))
(add-hook 'minibuffer-setup-hook 'bw/conditionally-enable-paredit-mode)
CIDER (Clojure IDE and REPL) is the best way to develop Clojure in Emacs.
(require-package 'cider)
Automatically enable eldoc-mode and paredit in CIDER buffers:
(after-load 'cider-mode
(add-hook 'cider-mode-hook 'cider-turn-on-eldoc-mode)
(add-hook 'cider-mode-hook 'enable-paredit-mode)
(add-hook 'cider-repl-mode-hook 'enable-paredit-mode))
Finally enable the CIDER minor mode in Clojure buffers:
(after-load 'clojure-mode
(add-hook 'clojure-mode-hook 'clojure-enable-cider))
web-mode is a major mode for editing templates and HTML. It supports a very broad range of template languages and is highly configurable.
(require-package 'web-mode)
Jinja templates are mostly like Django templates, so just force them to behave like that:
(after-load 'web-mode
(setq web-mode-engines-alist
'(("\\.jinja\\'" . "django"))))
Enable web-mode by default for several common file extensions:
(dolist (alist '(("\\.html$'" . web-mode)
("\\.html\\.erb$" . web-mode)
("\\.mustache$" . web-mode)
("\\.jinja$" . web-mode)
("\\.twig$" . web-mode)))
(add-to-list 'auto-mode-alist alist))
idomenu offers ido completion over imenu candidates. It allows me to navigate through classes etc. using completion for methods.
(require-package 'idomenu)
Add it to my launcher:
(bw/add-launcher "i" 'idomenu)
Automatically rescan the current file so imenu
is up to date:
(setq imenu-auto-rescan t)
know-your-http-well is a documentation set for HTTP, linked out to all the various RFCs and specifications.
(require-package 'know-your-http-well)
(require 'know-your-http-well)
Regrettably I need to occasionally edit YAML.
(require-package 'yaml-mode)
which-key displays key bindings based on your incomplete command entered so far.
(require-package 'which-key)
(which-key-mode 1)
diminish which-key-mode
:
(diminish 'which-key-mode)
browse-kill-ring allows one to browse the kill ring history when yanking.
(require-package 'browse-kill-ring)
remap yank-pop
:
(define-key (current-global-map) [remap yank-pop] 'browse-kill-ring)
make browse-kill-ring
act like yank-pop
by overwriting the previous yank:
(after-load 'browse-kill-ring
(setq browse-kill-ring-replace-yank t))
projectile-rails provides some convenience functions and hooks to make working with Ruby on Rails projects easier:
(require-package 'projectile-rails)
and make sure it’s loaded during projectile’s loading phase:
(add-hook 'projectile-mode-hook 'projectile-rails-on)
swiper adds inline preview to an isearch like incremental search.
Install swiper from latest code (and also Ivy, as otherwise I get an old version):
(require-package 'swiper)
Remap isearch
to swiper:
(define-key (current-global-map) [remap isearch-forward-regexp] 'swiper)
(define-key (current-global-map) [remap isearch-backward-regexp] 'swiper)
Add some advice to recenter
the window when exiting from swiper (gotten from
Pragmatic Emacs):
(defun bw/recenter (&rest args)
"recenter display after"
(recenter))
(advice-add 'swiper :after #'bw/recenter)
anzu provides enhancements to isearch
and related tasks, particularly
providing counts and better replacement visualisation.
(require-package 'anzu)
Enable anzu globally:
(global-anzu-mode 1)
Use anzu’s better query-replace
:
(define-key (current-global-map) [remap query-replace] 'anzu-query-replace)
Hide anzu’s lighter:
(after-load 'diminish
(diminish 'anzu-mode))
Install smart-mode-line, a better mode-line that has a bunch of nice functionality.
(require-package 'smart-mode-line)
Let the currently set theme override sml/theme
- since solarized-theme is
installed, this provides the theme:
(setq sml/theme nil)
Finally, init smart-mode-line:
(sml/setup)
If projectile is installed, diminish it:
(after-load 'diminish
(diminish 'projectile-mode))
sane-term is a simple wrapper around ansi-term that allows cycling between
ansi-term
buffers (instead of ansi-term
’s default, which is to create a new
buffer):
(package-install 'sane-term)
Add a launcher:
(bw/add-launcher "n" 'sane-term)
Use a modern php-mode.
Pin a more modern version than the 2015 version that comes with Emacs, and install php-mode:
(package-install 'php-mode)
Use flycheck to check PHP syntax:
(after-load 'php-mode
(after-load 'flycheck
(add-hook 'php-mode-hook 'flycheck-mode-on-safe)))
So I can configure my Emacs per computer/user, I attempted to automatically load some configuration.
First set up a directory to hold the files:
(setq bw/local-dotfiles-dir (bw/join-dirs bw/dotfiles-dir "local"))
Now try to load a file named after the current user:
(load (concat bw/local-dotfiles-dir user-login-name ".el") t)
and try to load a file named after the local system:
(load (concat bw/local-dotfiles-dir system-name ".el") t)
Finally, try loading a default file:
(load (concat bw/local-dotfiles-dir "local-overrides.el") t)
Make sure anything saved using customize
goes into a consistent (and ignored)
place:
(load (setq custom-file (concat bw/dotfiles-dir "custom.el")) t)
(note that this works because setq
returns the value it’s set to)