Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1057 lines (933 sloc) 31.9 KB

Geoff van der Meer’s Emacs configuration


Using org-mode for emacs config feels like cheating. Thanks Michael for the inspiration!


Personal information

(setq user-full-name "Geoff van der Meer"
      user-mail-address "")

General settings


(setq debug-on-error t)

Turn of a range of things

(if (fboundp 'menu-bar-mode) (menu-bar-mode -1))
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))

(setq inhibit-startup-message t
      inhibit-startup-echo-area-message t)

Sentances end with a single space

(setq sentence-end-double-space nil)

Browser setup

(setq browse-url-browser-function 'browse-url-generic
      browse-url-generic-program "open")

Setup directories

Make it easy to reference the dotfiles.

(setq dotfiles-dir (file-name-directory
                    (or (buffer-file-name) load-file-name)))

Custom file

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

Enable package support

I set up packages, Melpa, and use-package bright and early so that I can make use of use-package’s bind-key macro.

When I first copy this set-up into a new machine, I still have to require package, add MELPA, initialize package, and grab use-package, and a couple of others from the package archives and the internet. This could be improved.

(require 'package)

(setq package-archives '(("ELPA" . "")
                         ("gnu" . "")
                         ("org" . "")
                         ("melpa" . "")
                         ("marmalade" . "")))
(setq load-prefer-newer t)
(require 'use-package) ;; currently you have to evaluate everything up to here, and grab use-package manually :/


(use-package paradox
  :ensure t
  (setq paradox-execute-asynchronously t))


Reduce mode line clutter:

(use-package diminish
  :ensure t
  (defmacro rename-modeline (package-name mode new-name)
    `(eval-after-load ,package-name
       '(defadvice ,mode (after rename-modeline activate)
          (setq mode-name ,new-name)))))




 '((emacs-lisp . t)
   (R . t)
   (ruby . t)
   (sh . t)
   (python . t)
   (js . t)))

YouTube links

Example: yt:A3JAlWM8qRM

(defvar yt-iframe-format
  ;; You may want to change your width and height.
  (concat "<iframe width=\"440\""
          " height=\"335\""
          " src=\"\""
          " frameborder=\"0\""
          " allowfullscreen>%s</iframe>"))

 (lambda (handle)
    (concat ""
 (lambda (path desc backend)
   (cl-case backend
     (html (format yt-iframe-format
                   path (or desc "")))
     (latex (format "\href{%s}{%s}"
                    path (or desc "video"))))))


Making ispell work in org-mode

(defun endless/org-ispell ()
  "Configure `ispell-skip-region-alist' for `org-mode'."
  (make-local-variable 'ispell-skip-region-alist)
  (add-to-list 'ispell-skip-region-alist '(org-property-drawer-re))
  (add-to-list 'ispell-skip-region-alist '("~" "~"))
  (add-to-list 'ispell-skip-region-alist '("=" "="))
  (add-to-list 'ispell-skip-region-alist '("^#\\+BEGIN_SRC" . "^#\\+END_SRC")))
(add-hook 'org-mode-hook #'endless/org-ispell)

Mac Settings

(when (eq system-type 'darwin)
  (set-default-font "-*-Menlo-normal-normal-normal-*-14-*-*-*-m-0-iso10646-1")
  ;; initial window
  (setq initial-frame-alist '((width . 120) (height . 50)))
  ;; defaults subsequent windows
  (setq default-frame-alist '((width . 120) (height . 50)))

  (load-theme 'tango-dark)

Scratch file


(setq initial-scratch-message "")
(setq initial-major-mode 'lisp-interaction-mode)

Highlight trailing whitespace

(setq-default show-trailing-whitespace t)
(global-set-key "\C-c\C-w" 'whitespace-cleanup)

Search for occurance of symbol at point

C-s does normal search, C-u C-s will search for the current symbol that the cursor is on.


(defun endless/isearch-symbol-with-prefix (p)
  "Like isearch, unless prefix argument is provided.
With a prefix argument P, isearch for the symbol at point."
  (interactive "P")
  (let ((current-prefix-arg nil))
     (if p #'isearch-forward-symbol-at-point

(global-set-key [remap isearch-forward]

Auto fill

Always fill at 78 chars.

(add-hook 'text-mode-hook #'turn-on-auto-fill)
(setq-default fill-column 78)

File encoding

Set default file encoding to utf-8 (

(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)



And on Mac, install: brew install coreutils

(if (eq system-type 'darwin)
 (setq insert-directory-program (executable-find "gls"))

Tramp mode

(setq tramp-default-method "scpx")

Change prompts

Make yes or no prompts be y or n prompts.

(fset 'yes-or-no-p 'y-or-n-p)

Backup files

Auto Save files to temp dir:

(setq backup-directory-alist
      `((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
      `((".*" ,temporary-file-directory t)))

Make backups of files, even when they’re in version control.

(setq vc-make-backup-files t)

Mode line


More compact position display.

(setq-default mode-line-position
              '((-3 "%p") (size-indication-mode ("/" (-4 "%I")))
                " "
                 ("%l" (column-number-mode ":%c")))))

Mode line formating for projectile.

(defvar gmwils-projectile-mode-line
    (:eval (when (ignore-errors (projectile-project-root))
             (concat " " (projectile-project-name))))
    face font-lock-constant-face)
  "Mode line format for Projectile.")
(put 'gmwils-projectile-mode-line 'risky-local-variable t)

Shorter version control (VC) mode line.

(defvar gmwils-vc-mode-line
  '(" " (:propertize
         ;; Strip the backend name from the VC status information
         (:eval (let ((backend (symbol-name (vc-backend (buffer-file-name)))))
                  (substring vc-mode (+ (length backend) 2))))
         face font-lock-variable-name-face))
  "Mode line format for VC Mode.")
(put 'gmwils-vc-mode-line 'risky-local-variable t)

Set the actual mode line.

(setq-default mode-line-format
              '("%e" mode-line-front-space
                " " mode-line-position
                (flycheck-mode flycheck-mode-line) ; Flycheck status
                " "
                " "

(display-battery-mode 1)
(setq battery-mode-line-format "%p%%") ; Default: "[%b%p%%]"

(diminish 'isearch-mode)


Smart tab

(use-package smart-tab
 :ensure t
 :diminish smart-tab-mode
 (global-smart-tab-mode 1))

String Inflection

Change case styles:

(use-package string-inflection
 :ensure t)

(global-unset-key (kbd "C-q"))
;; C-q C-u is the key bindings similar to Vz Editor.
(global-set-key (kbd "C-q C-u") 'my-string-inflection-cycle-auto)

(defun my-string-inflection-cycle-auto ()
  "switching by major-mode"
   ;; for emacs-lisp-mode
   ((eq major-mode 'emacs-lisp-mode)
   ;; for java
   ((eq major-mode 'java-mode)
    ;; default

Avy - jump within buffers


(use-package avy
 :ensure t
 (("\C-cj" . avy-goto-word-or-subword-1)
  ("\C-c:" . avy-goto-word-or-subword-1)
  ("\C-cw" . ace-window)))

YAS snippet

Setup Yasnippet -

(use-package yasnippet
 :ensure t
 :diminish yas-minor-mode
 (yas-global-mode 1))

Save place

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


(use-package markdown-mode
 :ensure t)


Setup full screen magit-status:

(use-package magit
 :ensure t
 (defadvice magit-status (around magit-fullscreen activate)
   (window-configuration-to-register :magit-fullscreen)

 (defun magit-quit-session ()
   "Restores the previous window configuration and kills the magit buffer"
   (jump-to-register :magit-fullscreen))



Emacs statistics mode.

(use-package ess
 :ensure t
 (setq ess-ask-for-ess-directory nil)
 (require 'ess-site))

Projectile mode

(use-package projectile
 :ensure t
 :diminish projectile-mode
 :bind ("M-p" . projectile-find-file)
 (setq projectile-enable-caching t))

Asciidoc mode

(use-package adoc-mode
 :ensure t
 (add-to-list 'auto-mode-alist '("\\.doc$" . adoc-mode))
 (add-to-list 'auto-mode-alist '("\\.asciidoc$" . adoc-mode)))

IDO mode

IDO lets you interactively do things with files and buffers.

(setq ido-enable-flex-matching t
      ido-everywhere t
      ido-use-faces nil ;; disable ido faces to see flx highlights.
      ido-create-new-buffer 'always)

;; suppress  "reference to free variable problems"
(setq ido-cur-item nil
      ido-context-switch-command nil
      ido-cur-list nil
      ido-default-item nil)

(ido-mode 1)

(use-package ido-ubiquitous
  :ensure t
  (ido-ubiquitous-mode 1))
(use-package flx-ido
  :ensure t
  (setq flx-ido-threshold 1000)
  (flx-ido-mode 1))


(use-package protobuf-mode
 :ensure t)


Deft setup -

(use-package deft
 :ensure t
  deft-extension "org"
  deft-directory "~/Notes/"
  deft-text-mode 'org-mode))


(use-package color-theme
 :ensure t)

; TODO - (require 'color-theme-ir-black)


(use-package paredit
 :ensure t
(defun conditionally-enable-paredit-mode ()
  "Enable `paredit-mode' in the minibuffer, during `eval-expression'."
  (if (eq this-command 'eval-expression)
      (paredit-mode 1)))
(add-hook 'minibuffer-setup-hook 'conditionally-enable-paredit-mode))


(use-package dash-at-point
 :ensure t
 :bind (("\C-cd" . dash-at-point)))


(require 'dired-x)

;; Hive / Hadoop
(add-to-list 'auto-mode-alist '("\\.hql$" . sql-mode))

Virtual env mode for Python


General settings

Default to unified diffs

(setq diff-switches "-u -w")

File associations

(add-to-list 'auto-mode-alist '("\\.css$" . css-mode))
(add-to-list 'auto-mode-alist '("\\.ya?ml$" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.rb$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.js\\(on\\)?$" . js-mode))
(add-to-list 'auto-mode-alist '("\\.xml$" . nxml-mode))
(add-to-list 'auto-mode-alist '("\\.md$" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.markdown$" . markdown-mode))


(use-package flycheck
  :ensure t


(eval-after-load 'grep
  '(when (boundp 'grep-find-ignored-files)
    (add-to-list 'grep-find-ignored-files "target")
    (add-to-list 'grep-find-ignored-files "*.class")))

Highlight parens

(show-paren-mode 1)

Open compressed files

(auto-compression-mode t)

Seed the random number generator

(random t)


Ensure we’re using UTF8 as a default

(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(prefer-coding-system 'utf-8)

Extra settings

(set-default 'indent-tabs-mode nil)
(set-default 'indicate-empty-lines t)
(set-default 'imenu-auto-rescan t)


C family

(use-package google-c-style
  :ensure t
  (add-hook 'c-mode-common-hook 'google-set-c-style)
  (add-hook 'c-mode-common-hook 'google-make-newline-indent)
  (add-hook 'java-mode-hook 'google-set-c-style)
  (add-hook 'java-mode-hook 'google-make-newline-indent))

(defun flymake-cpplint-init ()
  (list "cpplint" (list (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace))))


Wiki: Tutorial:

(use-package haskell-mode
 :ensure t)

(add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)

;; Setup cabal
(let ((my-cabal-path (expand-file-name "~/.cabal/bin")))
  (setenv "PATH" (concat my-cabal-path ":" (getenv "PATH")))
  (add-to-list 'exec-path my-cabal-path))
(custom-set-variables '(haskell-tags-on-save t))

  '(haskell-process-suggest-remove-import-lines t)
  '(haskell-process-auto-import-loaded-modules t)
  '(haskell-process-log t))

(eval-after-load 'haskell-mode
     (define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-or-reload)
     (define-key haskell-mode-map (kbd "C-c `") 'haskell-interactive-bring)
     (define-key haskell-mode-map (kbd "C-c C-t") 'haskell-process-do-type)
     (define-key haskell-mode-map (kbd "C-c C-i") 'haskell-process-do-info)
     (define-key haskell-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build)
     (define-key haskell-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear)
     (define-key haskell-mode-map (kbd "C-c c") 'haskell-process-cabal)
     (define-key haskell-mode-map (kbd "SPC") 'haskell-mode-contextual-space)

(eval-after-load 'haskell-cabal
     (define-key haskell-cabal-mode-map (kbd "C-c `") 'haskell-interactive-bring)
     (define-key haskell-cabal-mode-map (kbd "C-c C-z") 'haskell-interactive-switch)
     (define-key haskell-cabal-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear)
     (define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build)
     (define-key haskell-cabal-mode-map (kbd "C-c c") 'haskell-process-cabal)))

(custom-set-variables '(haskell-process-type 'cabal-repl))

(eval-after-load 'haskell-mode
  '(define-key haskell-mode-map (kbd "C-c C-o") 'haskell-compile))
(eval-after-load 'haskell-cabal
  '(define-key haskell-cabal-mode-map (kbd "C-c C-o") 'haskell-compile))


(autoload 'js2-mode "js2-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

(use-package json-mode
 :ensure t)

;; Fix the crappy indentation of js2-mode
(defun my-js2-indent-function ()
    (let* ((inhibit-point-motion-hooks t)
           (parse-status (save-excursion (syntax-ppss (point-at-bol))))
           (offset (- (current-column) (current-indentation)))
           (indentation (espresso--proper-indentation parse-status))


        ;; consecutive declarations in a var statement are nice if
        ;; properly aligned, i.e:
        ;; var foo = "bar",
        ;;     bar = "foo";
        (setq node (js2-node-at-point))
        (when (and node
                   (= js2-NAME (js2-node-type node))
                   (= js2-VAR (js2-node-type (js2-node-parent node))))
          (setq indentation (+ 4 indentation))))

      (indent-line-to indentation)
      (when (> offset 0) (forward-char offset)))))

(defun my-indent-sexp ()
      (let* ((inhibit-point-motion-hooks t)
             (parse-status (syntax-ppss (point)))
             (beg (nth 1 parse-status))
             (end-marker (make-marker))
             (end (progn (goto-char beg) (forward-list) (point)))
             (ovl (make-overlay beg end)))
        (set-marker end-marker end)
        (overlay-put ovl 'face 'highlight)
        (goto-char beg)
        (while (< (point) (marker-position end-marker))
          ;; don't reindent blank lines so we don't set the "buffer
          ;; modified" property for nothing
          (unless (looking-at "\\s-*$")
        (run-with-timer 0.5 nil '(lambda(ovl)
                                   (delete-overlay ovl)) ovl)))))

(defun my-js2-mode-hook ()
  (require 'espresso)
  ;; (setq espresso-indent-level javascript-indent
  ;;       indent-tabs-mode nil
  ;;       c-basic-offset javascript-indent)
  (c-toggle-auto-state 0)
  (c-toggle-hungry-state 1)
  (set (make-local-variable 'indent-line-function) 'my-js2-indent-function)
  (define-key js2-mode-map [(meta control |)] 'cperl-lineup)
  (define-key js2-mode-map [(meta control \;)]
       (insert "/* -----[ ")
         (insert " ]----- */"))
  (define-key js2-mode-map [(return)] 'newline-and-indent)
  (define-key js2-mode-map [(backspace)] 'c-electric-backspace)
  (define-key js2-mode-map [(control d)] 'c-electric-delete-forward)
  (define-key js2-mode-map [(control meta q)] 'my-indent-sexp)
  (if (featurep 'js2-highlight-vars)

(add-hook 'js2-mode-hook 'my-js2-mode-hook)


(define-key read-expression-map (kbd "TAB") 'lisp-complete-symbol)
(define-key lisp-mode-shared-map (kbd "C-c l") "lambda")
(define-key lisp-mode-shared-map (kbd "RET") 'reindent-then-newline-and-indent)
(define-key lisp-mode-shared-map (kbd "C-\\") 'lisp-complete-symbol)
(define-key lisp-mode-shared-map (kbd "C-c v") 'eval-buffer)

;;; Enhance Lisp Modes

(eval-after-load 'paredit
  ;; need a binding that works in the terminal
  '(define-key paredit-mode-map (kbd "M-)") 'paredit-forward-slurp-sexp))

(defun turn-on-paredit ()
  (paredit-mode t))

(dolist (x '(scheme emacs-lisp lisp clojure))
  (when window-system
     (intern (concat (symbol-name x) "-mode"))
     '(("(\\|)" . 'esk-paren-face))))
   (intern (concat (symbol-name x) "-mode-hook")) 'turn-on-paredit))

(eval-after-load 'clojure-mode
    'clojure-mode `(("(\\(fn\\>\\)"
                     (0 (progn (compose-region (match-beginning 1)
                                               (match-end 1) "ƒ")

(setq inferior-lisp-program "browser-repl")


Turn on eldoc -

(autoload 'turn-on-eldoc-mode "eldoc" nil t)
(diminish 'eldoc-mode)
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)


(setq auto-mode-alist (cons '("\\.php$" . php-mode) auto-mode-alist))
(autoload 'php-mode "php-mode" "PHP editing mode." t)


(use-package python-mode
 :ensure t

(setq auto-mode-alist (cons '("\\.py$" . python-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.tac$" . python-mode) auto-mode-alist))
(setq interpreter-mode-alist (cons '("python" . python-mode)
(autoload 'python-mode "python-mode" "Python editing mode." t)


(eval-after-load 'ruby-mode
     ;; work around possible elpa bug
     (ignore-errors (require 'ruby-compilation))
     (setq ruby-use-encoding-map nil)
     (define-key ruby-mode-map (kbd "RET") 'reindent-then-newline-and-indent)
     (define-key ruby-mode-map (kbd "C-M-h") 'backward-kill-word)
     (define-key ruby-mode-map (kbd "C-c l") "lambda")))

;; Rake files are ruby, too, as are gemspecs, rackup files, etc.
(add-to-list 'auto-mode-alist '("\\.rake$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.gemspec$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.ru$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Gemfile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Capfile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Vagrantfile$" . ruby-mode))

Web mode

(use-package web-mode
  :ensure web-mode
  :init (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
    (setq web-mode-markup-indent-offset 2)
    (setq web-mode-enable-auto-pairing t)
    (setq web-mode-enable-current-element-highlight t)
    (setq web-mode-ac-sources-alist
          '(("css" . (ac-source-css-property))
            ("html" . (ac-source-words-in-buffer ac-source-abbrev)))

Custom functions

Auto commenting


(defun gmwils/comment-line (n)
  "Comment or uncomment current line and leave point after it.
   With positive prefix, apply to N lines including current one.
   With negative prefix, apply to -N lines above."
  (interactive "p")
  (let ((range (list (line-beginning-position)
                     (goto-char (line-end-position n)))))
     (apply #'min range)
     (apply #'max range)))
  (forward-line 1)

(defun gmwils/comment-line-or-region (n)
  "Comment or uncomment current line and leave point after it.
With positive prefix, apply to N lines including current one.
With negative prefix, apply to -N lines above.
If region is active, apply to active region instead."
  (interactive "p")
  (if (use-region-p)
       (region-beginning) (region-end))
    (let ((range
           (list (line-beginning-position)
                 (goto-char (line-end-position n)))))
       (apply #'min range)
       (apply #'max range)))
    (forward-line 1)
(global-set-key (kbd "C-x /") #'gmwils/comment-line-or-region)

Alternate vesion, lifted from the textmate package.

;;; allow-line-as-region-for-function adds an "-or-line" version of
;;; the given comment function which (un)comments the current line is
;;; the mark is not active.  This code comes from Aquamac's osxkeys.el
;;; and is licensed under the GPL
(defmacro allow-line-as-region-for-function (orig-function)
`(defun ,(intern (concat (symbol-name orig-function) "-or-line"))
   ,(format "Like `%s', but acts on the current line if mark is not active."
   (if mark-active
       (call-interactively (function ,orig-function))
       ;; define a region (temporarily) -- so any C-u prefixes etc. are preserved.
       (set-mark (point))
       (call-interactively (function ,orig-function))))))

(defun textmate-define-comment-line ()
  "Add or-line (un)comment function if not already defined"
  (unless (fboundp 'comment-or-uncomment-region-or-line)
    (allow-line-as-region-for-function comment-or-uncomment-region)))

(global-set-key (kbd "C-X /") 'comment-or-uncomment-region-or-line)

Copy filename to clipboard

(defun copy-file-name-to-clipboard ()
  "Copy the current buffer file name to the clipboard."
  (let ((filename (if (equal major-mode 'dired-mode)
    (when filename
      (kill-new filename)
      (message "Copied buffer file name '%s' to the clipboard." filename))))

Open browser with URL

(defun browse-url-default-macosx-browser (url &optional new-window)
  (interactive (browse-url-interactive-arg "URL: "))
  (if (and new-window (>= emacs-major-version 23))
       (format (concat "tell application \"Safari\" to make document with properties {URL:\"%s\"}\n"
                       "tell application \"Safari\" to activate") url))
    (start-process (concat "open " url) nil "open" url)))

Run test

A function to run the unit test assocated with the current file.

  • TODO(gmwils): Run cucumber if editing features
  • TODO(gmwils): use different test runners based on extension (eg. rspec, py, etc)
  • TODO(gmwils): if file is ROOT/a/b/file, then try ROOT/test/a/b/test_file
(defun string/ends-with (s ending)
  "return non-nil if string S ends with ENDING."
  (let ((elength (length ending)))
            (string= (substring s (- 0 elength)) ending)))

(defun find-test-file (f)
  "find the equivalent test file in the current project"
  (let ((test-dir (concat (textmate-find-project-root) "/test/"))
        (filename (file-name-nondirectory (file-name-sans-extension f)))
        (ext (file-name-extension f)))
    (concat test-dir filename "_test." ext)))

(defun test-file-p (f)
  "return non-nil if file is a test file"
  (string/ends-with (file-name-sans-extension f) "test"))

(defun test-file-name (f)
  "return a test file or nil if none found."
  (if (or (eq f nil) (test-file-p f))
      (find-test-file f)))

(defun run-test-from-file (f)
  "given a file, run tests on it"
  (let ((base-dir (textmate-find-project-root))
        (virtenv (file-name-nondirectory (getenv "VIRTUAL_ENV"))))
    (if (and (not (eq f nil)) (file-readable-p f))
        (shell-command (concat "("
                               "cd " base-dir "; "
                               "source ~/.virtualenvs/" virtenv "/bin/activate; "
                               "PYTHONPATH=\"" base-dir ";$PYTHONPATH\" py.test " f ")"))
        (message "Unable to run test for file %s" f))))

(defun run-test ()
  "run tests based on the current buffer"
  (run-test-from-file (test-file-name (buffer-file-name))))

(global-set-key (kbd "C-t") 'run-test)

Unfill paragraph

(defun unfill-paragraph ()
  "Takes a multi-line paragraph and makes it into a single line of text."
  (let ((fill-column (point-max)))
    (fill-paragraph nil)))
(define-key global-map "\M-Q" 'unfill-paragraph)

Rename current file


(defun rename-file-and-buffer ()
  "Rename the current buffer and file it is visiting."
  (let ((filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (message "Buffer is not visiting a file!")
      (let ((new-name (read-file-name "New name: " filename)))
         ((vc-backend filename) (vc-rename-file filename new-name))
          (rename-file filename new-name t)
          (set-visited-file-name new-name t t)))))))

(global-set-key (kbd "C-x C-r") 'rename-file-and-buffer)

Correct DOuble CAPS


(defun dcaps-to-scaps ()
  "Convert word in DOuble CApitals to Single Capitals."
  (and (= ?w (char-syntax (char-before)))
         (and (if (called-interactively-p)
                  (skip-syntax-backward "w")
                (= -3 (skip-syntax-backward "w")))
              (let (case-fold-search)
                (looking-at "\\b[[:upper:]]\\{2\\}[[:lower:]]"))
              (capitalize-word 1)))))

(add-hook 'post-self-insert-hook #'dcaps-to-scaps nil 'local)

(define-minor-mode dubcaps-mode
  "Toggle `dubcaps-mode'. Converts words in DOuble CApitals to
Single Capitals as you type."
  :init-value nil
  :lighter (" DC")
  (if dubcaps-mode
      (add-hook 'post-self-insert-hook #'dcaps-to-scaps nil 'local)
    (remove-hook 'post-self-insert-hook #'dcaps-to-scaps 'local)))

(add-hook 'text-mode-hook #'dubcaps-mode)

Key bindings

Key bindings that aren’t included elsewhere.

  ;; Font size
  (define-key global-map (kbd "C-+") 'text-scale-increase)
  (define-key global-map (kbd "C--") 'text-scale-decrease)

  ;; Use regex searches by default.
  (global-set-key (kbd "C-s") 'isearch-forward-regexp)
  (global-set-key (kbd "\C-r") 'isearch-backward-regexp)
  (global-set-key (kbd "C-M-s") 'isearch-forward)
  (global-set-key (kbd "C-M-r") 'isearch-backward)

  ;; M-S-6 is awkward
  (global-set-key (kbd "C-c q") 'join-line)
  (global-set-key (kbd "M-j")
            (lambda ()
                  (join-line -1)))

  ;; Cycle between windows -
  (global-set-key (kbd "C-o") 'other-window)
  (defun prev-window ()
    (other-window -1))
  (global-set-key "\M-o" 'prev-window)

  ;; Help should search more than just commands
  (global-set-key (kbd "C-h a") 'apropos)

  (global-set-key (kbd "C-x m") 'magit-status)
  (global-set-key (kbd "M-s")   'fixup-whitespace)

  ;; Toggle auto-fill
  (global-set-key (kbd "C-c q") 'auto-fill-mode)