Skip to content

Files

Latest commit

e123eb3 · Mar 30, 2015

History

History
804 lines (739 loc) · 25.9 KB

mwestbom.org

File metadata and controls

804 lines (739 loc) · 25.9 KB

Michael Westbom’s Emacs configuration

Configuration

About this file

This is my configuration file. It can be loaded by Emacs via org-babel. The contents of my ~/.emacs/init.el simplify to this, which loads it:

(add-hook 'after-init-hook
          (lambda ()
            (org-babel-load-file
             (expand-file-name "mwestbom.org" user-emacs-directory))))

One can evaluate individual blocks of this file by putting (point) on them and calling org-edit-special, which is bound by default to C-c \'

Then M-x eval-buffer to evaluate them.

Package management

Sources

use-package

Now we’ll enable John Wiegley’s phenomenal use-package library:

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(require 'use-package)

General configuration

Customize

Going to move away from customize eventually, but until then, let’s use the customizations I’ve got:

(setq custom-file
      (expand-file-name "customizations.el" user-emacs-directory))
(load custom-file)

Apple keyboards

Swap super and meta for macs. This retains option being alt as in the rest of the OS.

(setq mac-command-modifier 'super
      mac-option-modifier 'meta)

No blinking.

Seriously.

(blink-cursor-mode 0)

Display

Toolbar

Emacs comes with a toolbar. It’s redundant.

(tool-bar-mode -1)

Golden ratio

Let’s add the golden ratio addon to allow for automatically resizing windows.

(use-package golden-ratio
  :ensure golden-ratio
  :commands golden-ratio)

Buffers

Uniquify

By default, files with the same name but in different folders aren’t well distinguished. Uniquify, built into Emacs, solves this.

Name style

By default, Uniquify names buffers like this:

  • post.js<1>
  • post.js<2>

Let’s name them like this:

  • app/models/post.js
  • app/controllers/post.js
(setq uniquify-buffer-name-style 'forward)

Help and discoverability.

Let’s enable guide-key. This tells you what possible bindings are available based on what you’ve already pressed.

(use-package guide-key-tip
  :ensure t
  :diminish guide-key-mode
  :init
  (progn
    (setq guide-key/guide-key-sequence `("C-x"
                                         "C-c"
                                         "C-h")
          guide-key/recursive-key-sequence-flag t
          guide-key/text-scale-amount 0
          guide-key-tip/enabled nil)
    (guide-key-mode 1)))

Whitespace

Clean up trailing whitespace stuff in terminals

(add-hook 'term-mode-hook
          (lambda ()
            (setq show-trailing-whitespace nil)))

(add-hook 'eshell-mode-hook
          (lambda ()
            (setq show-trailing-whitespace nil)))

Line numbers

Modeline

;; Add line/column numbers to modeline
(line-number-mode t)
(column-number-mode t)

Selectively enable linum-mode

linum-mode enables gutter line numbers. Disable it for specific modes.

From emacswiki

(require 'linum)

(defcustom linum-disabled-modes-list '(eshell-mode
                                       wl-summary-mode
                                       compilation-mode
                                       org-mode
                                       text-mode
                                       dired-mode
                                       doc-view-mode
                                       image-mode)
  "* List of modes disabled when global linum mode is on"
  :type '(repeat (sexp :tag "Major mode"))
  :tag " Major modes where linum is disabled"
  :group 'linum)

(defcustom linum-disable-starred-buffers 't
  "* Disable buffers that have stars in them like *Gnu Emacs*"
  :type 'boolean
  :group 'linum)

(defun linum-on ()
  "* When linum is running globally, disable line numbers in modes
defined in `linum-disabled-modes-list'. Changed by linum-off.
Also turns off numbering in starred modes like *scratch*."
  (unless (or (minibufferp)
              (member major-mode linum-disabled-modes-list)
              (string-match "*" (buffer-name))
              (> (buffer-size) 3000000)) ;; Don't number huge files
    (linum-mode 1)))
(provide 'linum-off)

Change “yes or no” to “y or n”

y is just fine, thank you.

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

Color scheme

Base16 railscast.

(defun mcw/load-theme ()
  (if (package-installed-p 'base16-theme)
      (load-theme 'base16-railscasts)
    (progn
      (package-install 'base16-theme)
      (mcw/load-theme))))

(mcw/load-theme)

Multiple cursors

(use-package multiple-cursors
  :ensure multiple-cursors
  :commands (mc/mark-next-like-this mc/mark-previous-like-this mc/mark-all-like-this)
  :init
  (progn
    (global-set-key (kbd "C->") 'mc/mark-next-like-this)
    (global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
    (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)))

Helm

Helm is, in my opinion, the best minibuffer completion thing. Let’s stick it just about everywhere.

Also replace the standard M-x with helm-M-x

Still further, we’ll replace C-x b (switch-to-buffer) with helm-mini, which is crazy smart

(use-package helm
  :ensure t
  :diminish helm-mode
  :init
  (progn
    (require 'helm-config)
    (global-set-key (kbd "M-x") 'helm-M-x)
    (global-set-key (kbd "M-y") 'helm-show-kill-ring)
    (global-set-key (kbd "C-x b") 'helm-mini)
    (helm-mode)))

Disable ido-mode

Don’t need ido-mode. Disable it.

(ido-mode -1)

helm-descbinds

helm-descbinds is pretty great. C-h b brings up a helm-powered list of available bindings in the current mode.

(use-package helm-descbinds
  :ensure helm-descbinds
  :commands helm-descbinds
  :config
  (helm-descbinds-mode))

Backups

Turn on a whole mess of backup/save stuff. I’ll probably cut this out eventually.

(setq
 backup-by-copying t
 backup-directory-alist '(("." . "~/.emacs.d/saves"))
 delete-old-versions -1
 version-control t)

(let
    ((autosave-dir (expand-file-name "autosave" user-emacs-directory)))
  (unless (file-exists-p autosave-dir)
    (make-directory autosave-dir))
  (setq auto-save-list-file-prefix (concat autosave-dir "/")
        auto-save-file-name-transforms `((".*" ,autosave-dir t))))

(setq gc-cons-threshold 200000000)

Modeline

The default modeline can get unwieldy, and go wider than the frame.

Add Bruce Connor’s smart-mode-line to make for a prettier and more manageable modeline

(use-package smart-mode-line
  :ensure smart-mode-line
  :init
  (progn
    (use-package smart-mode-line-powerline-theme
      :ensure smart-mode-line-powerline-theme))
  :config
  (progn
    (setq-default mode-line-format
                  '("%e"
                    mode-line-front-space
                    mode-line-mule-info
                    mode-line-client
                    mode-line-modified
                    mode-line-remote
                    mode-line-frame-identification
                    mode-line-buffer-identification
                    sml/pos-id-separator
                    mode-line-position
                    (vc-mode vc-mode)
                    sml/pre-modes-separator
                    mode-line-modes
                    mode-line-misc-info
                    mode-line-end-spaces))
    (sml/setup)))

Undo Tree

Undo tree is fabulous

(use-package undo-tree
  :ensure undo-tree
  :diminish undo-tree-mode
  :init
  (progn
    (global-undo-tree-mode)
    (setq undo-tree-auto-save-history t)))

Delete Selection

(delete-selection-mode 1)

Window management

Window splitting

Stole these from Sacha Chua

(defun vsplit-last-buffer ()
  (interactive)
  (split-window-vertically)
  (other-window 1 nil)
  (switch-to-next-buffer))

(defun hsplit-last-buffer ()
  (interactive)
  (split-window-horizontally)
  (other-window 1 nil)
  (switch-to-next-buffer))

(global-set-key (kbd "C-x 2") 'vsplit-last-buffer)
(global-set-key (kbd "C-x 3") 'hsplit-last-buffer)

Winner mode

Winner mode adds an undo history to window configurations.

(use-package winner
  :ensure winner
  :init (winner-mode 1))

Navigation

The Silver Searcher

Enable integration with Ag. This must happen before Projectile

(use-package helm-ag
  :ensure helm-ag)

Windmove

Windmove beats using C-x o to toggle through windows

Let’s switch the binding from Super to Meta though

(use-package windmove
   :init (progn
           (windmove-default-keybindings 'meta)))

Beginning of line

Instead of C-a moving to column 0, go to first non-whitespace character. THEN go to column 0. And back again.

(defun smarter-move-beginning-of-line (arg)
  "Move point back to indentation of beginning of line.

Move point to the first non-whitespace character on this line.
If point is already there, move to beginning of the line.
Effectively toggle between the first non-whitespace character and
the beginning of the line.

If ARG is not nil or 1, move forward ARG - 1 lines first.
If point reaches the beginning or end of the buffer, stop there."
  (interactive "^p")
  (setq arg (or arg 1))

  ;; Move lines first
  (when (/= arg 1)
    (let ((line-move-visual nil))
      (forward (1- arg))))

  (let ((orig-point (point)))
    (back-to-indentation)
    (when (= orig-point (point))
      (move-beginning-of-line 1))))

;; remap C-a to `smarter-move-beginning-of-line`
(global-set-key [remap move-beginning-of-line]
                'smarter-move-beginning-of-line)

Visual expand

Experiment with keybindings for visual expand

(use-package expand-region
  :ensure expand-region
  :bind ("C-=" . er/expand-region))

Pop to mark

Haven’t built this into muscle memory yet.

(bind-key "C-x p" 'pop-to-mark-command)
(setq set-mark-command-repeat-pop t)

Switch to previous buffer

Switch to last buffer. Absolutely essential.

(defun mcw/switch-to-previous-buffer ()
  "Switch to previously open buffer.
Repeated invocations toggle between the most recently open buffers."
  (interactive)
  (switch-to-buffer (other-buffer (current-buffer) 1)))

(bind-key "C-c b" 'mcw/switch-to-previous-buffer)

Projectile

Projectile is a fantastic tool.

(use-package projectile
  :ensure projectile
  :diminish projectile-mode
  :init
  (progn
    (setq projectile-keymap-prefix (kbd "C-c p"))
    (projectile-global-mode)))

Also enable helm-projectile, which teaches projectile to use helm.

(use-package helm-projectile
  :ensure helm-projectile
  :config
  (helm-projectile-on))

Org

Literate programming

Just use the same window for the source buffer.

(setq org-src-window-setup 'current-window)

Speed keys

(setq org-use-speed-commands t)

Blog

Let’s try to set up org-jekyll

(use-package org-jekyll
  :ensure org-jekyll)
(setq org-publish-mcw "~/code/mike-blog/publish")
(setq org-publish-mcw-blog "~/code/mike-blog/org")

(setq org-publish-project-alist
             `("mcw-org"
               :base-directory "~/code/mike-blog/org"
               :recursive t
               :base-extension "org"
               :publishing-directory ,org-publish-mcw
               :exclude "^blog"
               :jekyll-sanitize-permalinks t
               :publishing-function org-html-publish-to-html
               :section-numbers nil
               :headline-levels 4
               :table-of-contents t
               :auto-index nil
               :auto-preamble nil
               :body-only nil
               :auto-postamble nil))

(add-to-list 'org-publish-project-alist
             `("mcw-img"
               :base-directory "~/code/mike-blog/org"
               :recursive t
               :exclude "^publish"
               :base-extension "jpg\\|gif\\|png"
               :publishing-directory ,org-publish-mcw
               :publishing-function org-html-publish-attachment))

(add-to-list 'org-publish-project-alist
             '("mcw" :components ("mcw-org" "mcw-img")))

(add-to-list 'org-publish-project-alist
             '("mcw-blog"
               :base-directory "~/code/mike-blog/org"
               :recursive t
               :base-extension "org"
               :publishing-directory ,org-publish-mcw
               :blog-publishing-directory ,org-publish-mcw-blog
               :jekyll-sanitize-permalinks t
               :publishing-function org-html-publish-to-html
               :section-numbers nil
               :headline-levels 4
               :table-of-contents nil
               :auto-index nil
               :auto-preamble nil
               :body-only t
               :auto-postamble nil))

org-page

(use-package org-page
  :ensure org-page
  :config
  (progn
    (setq op/site-domain "file:///Users/mwestbom/code/org-blog/blog")
    (setq op/repository-directory "~/code/org-blog")))

Publishing

Section numbers

Don’t bother adding section numbers.

(setq org-export-with-section-numbers nil)
(setq org-html-include-timestamps nil)
(setq org-export-with-sub-superscripts nil)

Stylesheets

How to style stuffs for export purposes

(defun mcw/get-org-htmlize-css-string ()
  "Get CSS from org-html-htmlize-generate-css buffer"
  (save-current-buffer
    (org-html-htmlize-generate-css)
    (let ((css-tag (buffer-string)))
      (kill-buffer)
      css-tag)))

(setq org-html-htmlize-output-type 'css)
(setq org-src-fontify-natively t)

Publish config file

Publish my config file.

(defun mcw/org-share-emacs ()
  "Publish emacs config"
  (interactive)
  (setq org-html-doctype "html5")
  (setq org-html-html5-fancy t)
  (with-current-buffer (find-file "~/.emacs.d/mwestbom.org")
    (save-restriction
      (save-excursion
        (widen)
        (remove-hook 'prog-mode-hook 'rainbow-identifiers-mode)
        (org-html-export-to-html)
        (add-hook 'prog-mode-hook 'rainbow-identifiers-mode)))))

Programming

Git

Emacs has so many fantastic get-related tools.

Magit

Magit is 90% of why I moved over to it in the first place.

(use-package magit
  :commands magit-status
  :load-path "site-lisp/magit"
  :init (progn
          (use-package dash
            :ensure t)
          (bind-key "C-x g" 'magit-status))
  :config
  (progn
    (setq magit-diff-options '("-b"))))

Gist

Here’s a handy tool for working with gists. I don’t use it very often, but I enjoy it when I do.

(use-package gist
  :ensure gist
  :commands (gist-buffer gist-region gist-list))

git-timemachine

Lets you flip back and forth through a file’s VC history

(use-package git-timemachine
  :ensure git-timemachine)

git-messenger

Shows most recent commit message for line under mark

(use-package git-messenger
  :ensure t
  :bind (("C-x v p" . git-messenger:popup-message)))

Rainbows!

Rainbow identifiers

Lots and lots of colors…

(use-package rainbow-identifiers
  :ensure rainbow-delimiters
  :config (progn
            (add-hook 'prog-mode-hook 'rainbow-identifiers-mode)))

Rainbow Delimiters

Individually color delimiters, to differentiate levels of nesting.

(use-package rainbow-delimiters
  :ensure rainbow-delimiters
  :config (progn
            (add-hook 'prog-mode-hook 'rainbow-delimiters-mode)))

Yasnippet

Loads and loads of useful snippets. The ability to add more snippets

(use-package yasnippet
  :ensure yasnippet
  :config
  (progn
    (add-to-list 'yas-snippet-dirs "~/.emacs.d/site-lisp/yasnippet-snippets")
    (yas-global-mode 1)))

Autocomplete

Bring in company mode for autocomplete

(use-package company
  :ensure company
  :diminish company-mode
  :config
  (add-hook 'prog-mode-hook 'company-mode))

Flycheck

Enables support for linting in a bunch of different languages.

(use-package flycheck
  :ensure t
  :diminish flycheck-mode
  :init
  (global-flycheck-mode))

Smartparens

Enable automatic matching of paired syntax tokens. This is brilliant.

(defun mcw/web-mode-is-code-context (id action context)
  (when (and (eq action 'insert)
             (not (or (get-text-property (point) 'part-side)
                      (get-text-property (point) 'block-side))))
    t))


(use-package smartparens
  :ensure smartparens
  :diminish smartparens-mode
  :config
  (progn
    (require 'smartparens-config)
    (sp-local-pair 'web-mode "<" nil :when '(sp-web-mode-is-code-context))
    (smartparens-global-strict-mode)
    (smartparens-global-mode 1)))

Web mode

Web mode is pretty great about handling mixed-mode files like HTML pages with javascript, or handlebars template pages.

Enable it for handlebars files.

;; From faq at http://web-mode.org/ for smartparens
(defun mcw/web-mode-hook ()
  (setq web-mode-enable-auto-pairing nil))

(use-package web-mode
  :ensure t
  :mode ("\\.hbs\\'" . web-mode)
  :init
  (progn
    (add-to-list 'auto-mode-alist '("\\.jsx\\'" . web-mode))
    (add-hook 'web-mode-hook 'mcw/web-mode-hook)))

Clojure

Clojure mode

(use-package clojure-mode
  :commands clojure-mode
  :mode (("\\.clj\\'" . clojure-mode)
         ("\\.cljs\\'" . clojure-mode)))

Cider

(use-package cider
  :ensure cider
  :commands cider-jack-in
  :bind ("C-c M-j" . cider-jack-in))

Various language modes

Ruby

enh-ruby-mode

Replace standard ruby mode with enh-ruby-mode. I like its indentation engine better.

(use-package enh-ruby-mode
  :ensure t
  :diminish enh-ruby-mode
  :commands enh-ruby-mode
  :init
  (progn
    (setq enh-ruby-bounce-deep-indent t)
    (add-to-list 'auto-mode-alist '("\\.rb$" . enh-ruby-mode))
    (add-to-list 'interpreter-mode-alist '("ruby" . enh-ruby-mode))))
rspec mode

Run rspec from emacs. I love this so much.

Overwrite the default predicate method for rspec mode, because it doesn’t play nicely with rbenv

(use-package rspec-mode
  :ensure rspec-mode
  :diminish rspec-mode
  :commands rspec-mode
  :init
  (progn
    (add-hook 'enh-ruby-mode-hook 'rspec-mode))
  :config
  (progn
    (setq rspec-command-options "--fail-fast --format documentation")
    (defun rspec-spring-p ()
      (and rspec-use-spring-when-possible
           (let ((root (directory-file-name (rspec-project-root))))
             (or
              (file-exists-p (format "%s/tmp/spring/spring.pid" root))
              (file-exists-p (format "%s/spring/%s.pid" temporary-file-directory (md5 root)))
              (let ((path (or (getenv "XDG_RUNTIME_DIR") temporary-file-directory))
                    (ruby-version (getenv "RBENV_VERSION")))
                (file-exists-p (format "%s/spring/%s.pid" path (md5 (concat ruby-version root)))))))))
    (inf-ruby-switch-setup)))
rbenv
(use-package rbenv
  :ensure t
  :commands rbenv-use-global
  :init
  (progn
    (add-hook 'enh-ruby-mode-hook 'rbenv-use-global)))
projectile-rails

Add projectile rails for rails-specific completions, finders, commands

(use-package projectile-rails
  :ensure projectile-rails
  :commands projectile-rails-on
  :init
  (add-hook 'projectile-mode-hook 'projectile-rails-on))

Elixir

(use-package elixir-mode
  :ensure elixir-mode)
Alchemist

Add the alchemist package for mix-related stuffs

(use-package alchemist
  :ensure alchemist)

Markdown

Enable markdown mode

(use-package markdown-mode
  :ensure t
  :mode ("\\.md\\'" . markdown-mode))

Docker

(use-package dockerfile-mode
  :ensure t
  :mode ("Dockerfile\\'" . dockerfile-mode))

Javascript

js2-mode seems to have the best indentation/linting support.

(use-package js2-mode
  :commands js2-mode
  :ensure t
  :init
  (progn
    (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
    (add-to-list 'interpreter-mode-alist (cons "node" 'js2-mode))))

CSS

Less
(use-package less-css-mode
  :commands less-css-mode
  :ensure less-css-mode
  :mode ("\\.less\\'" . less-css-mode))

Yaml

(use-package yaml-mode
  :ensure yaml-mode
  :mode "\\.yml\\'")

Terminals and shells

Multi term

multi-term adds some useful features, like running multiple terminal emulators, and a dedicated term buffer.

(use-package multi-term
  :ensure multi-term
  :bind ("<f5>" . multi-term-dedicated-toggle))