Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jmdeldin/.emacs.d

Personal .emacs.d directory.
https://github.com/jmdeldin/.emacs.d

Last synced: about 1 month ago
JSON representation

Personal .emacs.d directory.

Awesome Lists containing this project

README

        

#+TITLE: Jon-Michael Deldin's Emacs Configuration
#+STARTUP: align hidestars indent
#+STYLE: html { font: 14px Helvetica, sans-serif } body { width: 85%; margin: 2% auto;} pre, code { font-family: Monaco, Consolas, 'Bitstream Vera Sans', monospace; }

I started using Emacs in the fall of 2010 after a few years of Vim. I
use GNU Emacs 25.1+ on Ubuntu for Org-Mode, Ruby, LaTeX, sh, and a host
of miscellaneous other languages.

#+BEGIN_SRC emacs-lisp
(load "server")
(unless (server-running-p) (server-start))
#+END_SRC

* Installation
You can clone directly as =$HOME/.emacs.d=:

#+BEGIN_SRC sh
git clone git://github.com/jmdeldin/.emacs.d.git ~/.emacs.d/
#+END_SRC

* Notes
** Improvements
*** TODO add org-mode/orgstruct to magit
*** TODO evaluate company-mode
** Keys
| Key | Description |
|-------------+-------------------------------------------------|
| C-q TAB | Insert literal tab |
| M-y | Traverse kill-ring (after C-y) |
| C-u C-SPC | Jump to last mark |
| M-n | (In =cua-mode=) Increment digit |
| C-M \ | Indent according to major mode |
| C-c C-s | Start IRB |
| C-c C-r | Send region to IRB (C-c C-s first) |
| C-x v = | Diff against HEAD |
| C-u C-x v = | Diff against other branch |
| C-x v u | Discard changes |
| C-x v ~ | Checkout another rev |
| C-x v l | View commit log |
| C-Shift BS | Kill whole line |
| C-c ' | Edit code block (org-babel) |
| C-x r m | Bookmark the current loc in a file |
| C-x r b | Jump to bookmark |
| C-x r l | List bookmarks |
| C-x C-n | Narrow region |
| C-x C-w | Widen region |
| C-x r w | Save window configuration |
| C-x r j | Restore configuration |
| M-& | Execute shell command asynchronously |
| C-x r t | Removes the content in a rectangle (mark first) |
| M-0 .. M-9 | Prefix argument |
| M-- M-c | Capitalize last word (M-dash for back) |
| M-e | Forward sentence |
| M-a | Backward sentence |
| C-M-f | Move forward by a balanced expr (e.g., ",', []) |
| C-M-b | Move backward by a balanced expr |
| M-m | back-to-indentation (^ in Vim) |
| M-r | move the point w/o scrolling |
| M-g M-g | goto-line |
| M-o M-s | Center text |
| C-x r N | Number lines |

** Searching
| Key | Description |
|---------+-------------------------------------------|
| M-p | previous search term |
| M-n | next search term |
| M-c | toggle case-sensitivity |
| C-s C-w | search with the word at point (* inv Vim) |

** Ido-mode
These keys work inside the Ido minibuffer (C-x C-f).

| Key | Description |
|-----------+-------------------------------------------------------|
| C-d | Open a dired buffer in the current directory |
| C-a | Toggles showing ignored files |
| C-c | Toggles case-sensitivity |
| C-s & C-r | Move to the next/prev match |
| C-SPC | Restrict to an expr (C-x C-b .org C-SPC for just org) |

** Functions and modes
| Function | Description |
|------------------------+---------------------------------------|
| follow-mode | Browse splits like they're one window |
| ielm-mode | Elisp REPL |
| hexl-mode | Hex viewer |
| bury-buffer | Send buffer to end of list |
| highlight-changes-mode | Show newly changed text in red |
| info-apropos | full-text search of info |

** org-mode
| Command | Decription |
|-------------+--------------------------------------------|
| C-c C-n | next heading |
| C-c C-p | previous heading |
| C-c C-f | next heading (same level) |
| C-c C-b | previous heading (same level) |
| C-c C-u | back to a higher heading |
| C-c / | Sparse tree |
| M-S-RET | Insert new item with checkbox |
| M-S-UP/DOWN | Move items including subitems up/down |
| C-c - | Cycle list level through different bullets |

** Dired
| Command | Description |
|---------+--------------------|
| % u | uppercase filename |
| % l | lowercase filename |
| % R | regex rename |

* Initialization
** Load custom helper functions
#+BEGIN_SRC emacs-lisp
;; dependency issue - these defuns should not bother with install crap
(load-file (concat user-emacs-directory "site-lisp/defuns.el"))
#+END_SRC

** Set =custom-file=
On clean installs, some packages will try to append custom vars to
init.el, breaking installation. The =custom-file= must be set before
trying to install packages.
#+BEGIN_SRC emacs-lisp
(setq custom-file (concat user-emacs-directory "local/emacs-custom.el"))
(load custom-file 'noerror)
#+END_SRC

** Set up repositories
#+BEGIN_SRC emacs-lisp
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
("melpa-stable" . "https://stable.melpa.org/packages/")
("melpa-unstable" . "https://melpa.org/packages/")))
#+END_SRC

** Define required packages
We can declare the origin of our packages with the
=package-pinned-packages= variable:
#+BEGIN_SRC emacs-lisp
(setq package-pinned-packages '((use-package . "melpa-unstable")
(diminish . "melpa-unstable")))

(setq use-package-verbose t)
#+END_SRC

** Install packages
#+BEGIN_SRC emacs-lisp
(setq jm/packages (mapcar 'car package-pinned-packages))

(jm/install-all-packages jm/packages)
(setq use-package-verbose t)
#+END_SRC

** Load =use-package=
#+BEGIN_SRC emacs-lisp
(eval-when-compile
(require 'use-package))
(require 'diminish)
(require 'bind-key)
#+END_SRC

** Utility packages
#+BEGIN_SRC emacs-lisp
(use-package tiny
:pin melpa-unstable
:ensure t
:defer t)

(use-package s
:pin melpa-stable
:ensure t
:defer t)
#+END_SRC

** Server
Only load the server if it isn't running:
#+BEGIN_SRC emacs-lisp
(load "server")
(unless (server-running-p)
(server-start))
#+END_SRC

* Garbage
This section is dedicated to all of the turd files Emacs leaves all over
your machine.

** Lockfiles
Disable lockfiles -- there's only one user on this machine. This prevents
[[https://github.com/guard/guard][guard]] from re-running specs everytime the file is edited (but not saved).
#+BEGIN_SRC emacs-lisp
(setq create-lockfiles nil)
#+END_SRC

** Backups
Place backups in =~/.emacs.d/local/backups=:
#+BEGIN_SRC emacs-lisp
(setq backup-by-copying t)
(setq backup-directory-alist
(list (cons "." (jm/local-path "backups"))))
(setq delete-old-versions t)
(setq kept-new-versions 6)
(setq kept-old-versions 2)
(setq version-control t)
#+END_SRC

** Auto-saves
Keep auto-save files together. Test with =M-x do-auto-save=.
#+BEGIN_SRC emacs-lisp
(let ((new-dir (jm/local-path "auto-saves/")))
(setq auto-save-list-file-prefix new-dir)
(setq auto-save-file-name-transforms
`((".*" ,new-dir t))))
#+END_SRC

** Bookmarks
Use =~/.emacs.d/local/.emacs.bmk= for bookmarks:
#+BEGIN_SRC emacs-lisp
(setq bookmark-default-file (jm/local-path "bookmarks"))
#+END_SRC

* Communication
** ERC
Prevent auto-joining =#erc=
#+BEGIN_SRC emacs-lisp
(setq erc-autojoin-channels-alist '())
#+END_SRC

Spell-check ERC:
#+BEGIN_SRC emacs-lisp
(with-eval-after-load 'erc
(erc-spelling-mode 1))
#+END_SRC

Ignore noise:
#+BEGIN_SRC emacs-lisp
(setq erc-network-hide-list '("JOIN" "PART" "QUIT" "NICK" "MODE"))
(setq erc-track-exclude-server-buffer t)
#+END_SRC

Highlight nick:
#+BEGIN_SRC emacs-lisp
(setq erc-current-nick-highlight-type 'nick)
#+END_SRC

** mu4e

#+BEGIN_SRC emacs-lisp
;; Once =mu= is installed, run =mu init --my-address="[email protected]"
;; --my-address="[email protected]"= and =mu index=
;;
;; sudo apt install mu4e gnutls-bin
(use-package mu4e
:bind ("" . mu4e)
:init
(defun jm/email (user domain)
"Builds an email address to dodge some spam bot harvesting
for public config."
(combine-and-quote-strings (list user domain) "@"))

(defun jm/match-mu4e-context (email msg)
(when msg
(mu4e-message-contact-field-matches msg :to email)))
:config
(add-hook 'message-send-hook
(lambda ()
(unless (yes-or-no-p "Are you sure you want to send this?")
(signal 'quit nil))))

;; when viewing a message, hit `a V' to view message in browser
(add-to-list 'mu4e-view-actions
'("ViewInBrowser" . mu4e-action-view-in-browser) t)

(setq mu4e-get-mail-command "offlineimap")
(setq send-mail-function 'smtpmail-send-it)
(setq message-send-mail-function 'smtpmail-send-it)

;; enable inline images:
(setq mu4e-view-show-images t)
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types))

(setq mu4e-compose-dont-reply-to-self t)
(setq message-kill-buffer-on-exit t)

(setq mu4e-context-policy 'ask-if-none)
(setq mu4e-compose-context-policy 'ask-if-none)

;; the backquote is needed to evaluate the alist values
(setq mu4e-contexts `(
(make-mu4e-context
:name "Personal"
:match-func (lambda (msg)
(when msg
(string-prefix-p "/Personal" (mu4e-message-field msg :maildir))))
:vars `( (user-mail-address . ,(jm/email "jm" "deldin.us"))
(smtpmail-smtp-user . ,(jm/email "jm" "deldin.us"))
(smtpmail-smtp-server . "smtp.fastmail.com")
(smtpmail-smtp-service . 587)
(smtpmail-stream-type . starttls)
(mu4e-drafts-folder . "/Personal/Drafts")
(mu4e-sent-folder . "/Personal/Sent")
(mu4e-trash-folder . "/Personal/Trash")
)))))
#+END_SRC

* News
Elfeed is a really nice RSS reader for Emacs that's easy to use and
fast.

#+BEGIN_SRC emacs-lisp
(use-package elfeed
:pin melpa-unstable
:ensure t
:preface
(defun jm/elfeed ()
"Download feed updates before using elfeed."
(interactive)
(elfeed-update)
(elfeed))
:bind ("" . jm/elfeed)
:config
(setq elfeed-db-directory (concat user-emacs-directory "local/elfeed")))
#+END_SRC

** Feeds
#+BEGIN_SRC emacs-lisp
(setq elfeed-feeds
'(
("http://nullprogram.com/feed/" emacs)
("http://planet.emacsen.org/atom.xml" emacs)
("http://sachachua.com/blog/feed/" emacs)
("https://www.masteringemacs.org/feed" emacs)
("https://www.matthewkirk.com/news?format=rss" friends)
("http://nelsonware.com/feed.xml" friends)
("https://goto10line.net/feed/" friends)
("https://www.lyonwj.com/atom.xml" friends)
("http://www.jmdeldin.com/atom.xml" personal)
("https://jvns.ca/atom.xml" programming)
("https://toolguyd.com/feed/" tools)
("https://slickdeals.net/newsearch.php?src=SearchBarV2&q=tools&searcharea=deals&searchin=first&rss=1" tools)
("https://slickdeals.net/newsearch.php?src=SearchBarV2&q=knipex&searcharea=deals&searchin=first&rss=1" tools)
("https://slickdeals.net/newsearch.php?src=SearchBarV2&q=eneloop&searcharea=deals&searchin=first&rss=1" tools)
("https://blog.lostartpress.com/feed/" woodworking)
("https://www.reddit.com/r/everett.xml" news)))
#+END_SRC

* Text Editing
Default to 72 column width for plain text
#+BEGIN_SRC emacs-lisp
(add-hook 'text-mode-hook
'(lambda ()
(set-fill-column 72)))
#+END_SRC

Match parens and quotes
#+BEGIN_SRC emacs-lisp
(electric-pair-mode t)
#+END_SRC

Enable on-the-fly reindentation
#+BEGIN_SRC emacs-lisp
(electric-indent-mode t)
#+END_SRC

Insert a newline around special characters
#+BEGIN_SRC emacs-lisp
(electric-layout-mode t)
#+END_SRC

Use single spaces between sentences for =fill-paragraph= (=M-q=)
#+BEGIN_SRC emacs-lisp
(setq sentence-end-double-space nil)
#+END_SRC

Use Unicode everywhere, as per [[https://www.masteringemacs.org/article/working-coding-systems-unicode-emacs][Mastering Emacs' post]]:

#+BEGIN_SRC emacs-lisp
(set-language-environment "UTF-8")
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(setq-default buffer-file-coding-system 'utf-8)

;; clipboard as UTF-8
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
#+END_SRC

Changing a region's case is useful
#+BEGIN_SRC emacs-lisp
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
#+END_SRC

Remember last edit position
#+BEGIN_SRC emacs-lisp
(require 'saveplace)
(setq-default save-place t)
(setq save-place-file (jm/local-path "places"))
#+END_SRC

** Snippets
#+BEGIN_SRC emacs-lisp
(use-package yasnippet
:pin melpa-stable
:ensure t
:config
(yas-global-mode t))

(use-package yasnippet-snippets
:pin melpa-stable
:ensure t)
#+END_SRC
** Auto-Complete Mode
#+BEGIN_SRC emacs-lisp
(use-package auto-complete-config
:ensure auto-complete
:pin melpa-stable
:defer 2
:diminish auto-complete-mode
:config
(ac-config-default)
(ac-flyspell-workaround)
(setq ac-ignore-case nil)
(setq ac-comphist-file (jm/local-path "ac-comphist.dat")))
#+END_SRC

** Spelling
Use =aspell= instead of =ispell=, use =list= for faster region checking, and
use a faster suggestion mode.

#+BEGIN_SRC emacs-lisp
(setq ispell-program-name "aspell")
(setq ispell-list-command "list")
(setq ispell-extra-args '("--sug-mode=ultra"))
#+END_SRC

Turn it on for some modes:
#+BEGIN_SRC emacs-lisp
(mapcar (lambda (mode)
(add-hook mode (lambda () (flyspell-mode t))))
'(org-mode-hook markdown-mode mu4e-compose-mode-hook text-mode))
(add-hook 'git-commit-mode-hook 'turn-on-flyspell)
#+END_SRC

** Whitespace
Wrap lines at column 78
#+BEGIN_SRC emacs-lisp
(setq-default fill-column 78)
#+END_SRC

Highlight right-margin when whitespace-mode is on
#+BEGIN_SRC emacs-lisp
(setq whitespace-line-column fill-column)
#+END_SRC

Highlight empty lines
#+BEGIN_SRC emacs-lisp
(setq-default indicate-empty-lines t)
#+END_SRC

Hard-wrap lines all the time
#+BEGIN_SRC emacs-lisp
(add-hook 'text-mode-hook 'turn-on-auto-fill)
#+END_SRC

Use spaces, not tabs (C-q C-i to insert a hard-tab)
#+BEGIN_SRC emacs-lisp
(setq-default indent-tabs-mode nil)
#+END_SRC

2-space tabs
#+BEGIN_SRC emacs-lisp
(setq-default tab-width 2)
#+END_SRC

Insert tabs when appropriate
#+BEGIN_SRC emacs-lisp
(setq indent-line-function 'insert-tab)
#+END_SRC

Insert a newline at the EOF
#+BEGIN_SRC emacs-lisp
(setq-default require-final-newline t)
#+END_SRC

Delete trailing whitespace on save
#+BEGIN_SRC emacs-lisp
(add-hook 'before-save-hook 'delete-trailing-whitespace)
#+END_SRC

** Highlight Stuff
#+BEGIN_SRC emacs-lisp
(use-package highlight-indent-guides
:ensure t
:pin melpa-unstable
:config
(setq highlight-indent-guides-method 'fill)
(mapcar (lambda (hook) (add-hook hook 'highlight-indent-guides-mode))
'(prog-mode-hook yaml-mode-hook)))
#+END_SRC

* UI
Hide the {menu,tool,scroll}bars
#+BEGIN_SRC emacs-lisp
(if window-system
(progn
(scroll-bar-mode -1)
(tool-bar-mode -1)))
(menu-bar-mode -1)
#+END_SRC

Hide the startup messages
#+BEGIN_SRC emacs-lisp
(setq inhibit-startup-message t)
(setq inhibit-startup-echo-area-message t)
#+END_SRC

"y or n" instead of "yes or no"
#+BEGIN_SRC emacs-lisp
(fset 'yes-or-no-p 'y-or-n-p)
#+END_SRC

Show line & column number in the mode line
#+BEGIN_SRC emacs-lisp
(column-number-mode t)
#+END_SRC

Show file size
#+BEGIN_SRC emacs-lisp
(size-indication-mode t)
#+END_SRC

Highlight parens
#+BEGIN_SRC emacs-lisp
(show-paren-mode t)
(setq show-paren-delay 0.0)
#+END_SRC

Highlight current line
#+BEGIN_SRC emacs-lisp
(global-hl-line-mode 1)
#+END_SRC

Use =ibuffer= instead of =list-buffers=
#+BEGIN_SRC emacs-lisp
(defalias 'list-buffers 'ibuffer)
#+END_SRC

No bells
#+BEGIN_SRC emacs-lisp
(setq ring-bell-function 'ignore)
#+END_SRC

** Window Management
Restore window configuration with =C-c LEFT=
#+BEGIN_SRC emacs-lisp
(winner-mode)
#+END_SRC

Enable windmove -- default binding is shift
#+BEGIN_SRC emacs-lisp
(windmove-default-keybindings)
(setq windmove-wrap-around t)
#+END_SRC

Make windmove work in org-mode:
#+BEGIN_SRC emacs-lisp
(add-hook 'org-shiftup-final-hook 'windmove-up)
(add-hook 'org-shiftleft-final-hook 'windmove-left)
(add-hook 'org-shiftdown-final-hook 'windmove-down)
(add-hook 'org-shiftright-final-hook 'windmove-right)
#+END_SRC

** Minibuffer
*** IDO
Interactively-do-things is the greatest Emacs extension.

#+BEGIN_SRC emacs-lisp
(setq ido-enable-flex-matching t)
(setq ido-everywhere t)
(setq ido-show-dot-for-dired t)
(setq ido-save-directory-list-file (jm/local-path "ido.last"))
(setq ido-use-virtual-buffers t)
(ido-mode 1)
#+END_SRC

*** Uniquify
Use part of the directory to distinguish between identically-named files:
#+BEGIN_SRC emacs-lisp
(use-package uniquify
:config
(setq uniquify-buffer-name-style 'forward))
#+END_SRC

*** Minibuffer History
Save minibuffer history:
#+BEGIN_SRC emacs-lisp
(savehist-mode 1)
(setq savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
(setq savehist-file (jm/local-path "savehist"))
#+END_SRC

*** Recent Files
Enable recent files:
#+BEGIN_SRC emacs-lisp
(use-package recentf
:defer 1
:config
(setq recentf-save-file (jm/local-path "recentf"))
(setq recentf-max-saved-items 1000)
(recentf-mode 1))
#+END_SRC

*** SMEX
=M-x= -- ido-like completion for functions:

#+BEGIN_SRC emacs-lisp
(use-package smex
:pin melpa-stable
:ensure t
:bind ("M-x" . smex)
:config
(setq smex-save-file (jm/local-path "smex-items")))
#+END_SRC

** Mouse
Enable mouse support in a terminal (from [[http://stackoverflow.com/a/8859057/73492][StackOverflow]]):

#+BEGIN_SRC emacs-lisp
(unless window-system
(require 'mouse)
(xterm-mouse-mode t)
(global-set-key [mouse-4] '(lambda ()
(interactive)
(scroll-down 1)))
(global-set-key [mouse-5] '(lambda ()
(interactive)
(scroll-up 1)))
(defun track-mouse (e))
(setq mouse-sel-mode t))
#+END_SRC

** Keybindings
*** Evil
Arguably the best Vim ever, but sometimes, I still want Emacs keys.

#+BEGIN_SRC emacs-lisp
(use-package undo-tree
:ensure t
:init
(global-undo-tree-mode)
(setq undo-tree-history-directory-alist (list (cons "." (jm/local-path "backups")))))

(use-package evil
:pin melpa-unstable
:ensure t
:demand t
:diminish undo-tree-mode
:bind (
:map evil-insert-state-map
("C-a" . beginning-of-line)
("C-e" . end-of-line)
("C-d" . delete-forward-char)
("C-k" . kill-line)
("C-p" . evil-previous-line)
("C-p" . evil-previous-line)
("C-n" . evil-next-line)
("C-z" . suspend-emacs)
:map evil-normal-state-map
("C-n" . evil-next-line)
("C-p" . evil-previous-line)
("C-z" . suspend-emacs))
:config
;; disable evil in some buffers:
(mapc (lambda (mode) (evil-set-initial-state mode 'emacs))
'(elfeed-show-mode elfeed-search-mode Info-mode-hook ledger-report-mode))
(evil-set-undo-system 'undo-tree)

(evil-mode t))

;; Jump between tags with %
(use-package evil-matchit
:pin melpa-stable
:ensure t
:defer 1
:config (global-evil-matchit-mode t))

;; increment/decrement numbers like Vim (just not with C-a/C-x)
(use-package evil-numbers
:pin melpa-stable
:ensure t
:bind (("C-c +" . evil-numbers/inc-at-pt)
("C-c -" . evil-numbers/dec-at-pt)))

(use-package evil-surround
:pin melpa-stable
:ensure t
:defer 1
:config
(global-evil-surround-mode 1)
)
#+END_SRC

*** Editing
=M-/= -- use a more powerful expansion
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "M-/") 'hippie-expand)
#+END_SRC

=C-c C-r= -- Revert buffer
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-c C-r") 'revert-buffer)
#+END_SRC

Swap =C-j= and =RET=
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "RET") 'reindent-then-newline-and-indent)
(global-set-key (kbd "C-j") 'newline)
#+END_SRC

=C-c C-d= -- Remove trailing whitespace
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-c C-d") 'delete-trailing-whitespace)
#+END_SRC

=C-w= -- delete the previous word (like most shells)
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-w") 'backward-kill-word)
#+END_SRC

C-x C-k -- kill region (since we just unbound it with C-w)
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-x C-k") 'kill-region)
#+END_SRC

=C-x C-j= -- join line
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-x C-j") 'join-line)
#+END_SRC

=C-c w= -- toggle whitespace mode
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-c w") 'whitespace-mode)
#+END_SRC

better commenting (replaces the original comment-dwim)
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "M-;") 'comment-or-uncomment-region)
#+END_SRC

=C-x m= -- recompile
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-x m") 'recompile)
#+END_SRC

=C-x x= -- =jm/shell=
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-x x") 'jm/shell)
#+END_SRC

=M-#= -- =jm/reload-init=
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "M-#") 'jm/reload-init)
#+END_SRC

=F12= -- calculate and insert result in buffer
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "") (lambda ()
(interactive)
(quick-calc t)))
#+END_SRC

*** Windows
=M-s/M-S= -- switch windows
#+BEGIN_SRC emacs-lisp
(use-package ace-window
:bind (("M-s" . ace-window))
:ensure t
:pin melpa-stable)
#+END_SRC

*** Mac
Make the Cmd and Opt keys work for =M-x=
#+BEGIN_SRC emacs-lisp
(when system-type "darwin"
(setq-default mac-command-modifier 'super)
(setq-default mac-option-modifier 'meta))
#+END_SRC

** Clutter
VC mode does not need to show more than the branch. The following code
[[http://emacs.stackexchange.com/a/10957][from Malabrba]] does just that:
#+BEGIN_SRC emacs-lisp
(setcdr (assq 'vc-mode mode-line-format)
'((:eval (replace-regexp-in-string "^ Git" " " vc-mode))))
#+END_SRC

** Themes
For dumb terminals:
#+BEGIN_SRC emacs-lisp
(if (and (not window-system) (string= (getenv "TERM") "dumb"))
(progn
(set-face-background 'hl-line "#666")
(set-face-foreground 'hl-line "#fff")))
#+END_SRC

For GUIs:

#+BEGIN_SRC emacs-lisp
(defvar jm/font-size
150
"Default font size. #pixels height * 10.")

(defun font/old-man ()
"Increase the font size of all buffers."
(interactive)
(font/default (+ 100 jm/font-size)))

(defun font/standing-desk ()
"Drop the font size down for my external monitor."
(interactive)
(font/default 110))

(defun font/default (size)
"Scale things back down. Optionally invoke with C-u SIZE to set
the global size. Remember that the font size is pixels*10, e.g.,
150 == 15 px."
(interactive "P")
(set-face-attribute 'default nil :height (if size size jm/font-size)))

(if (and window-system (eq system-type 'gnu/linux))
(let ((jm/font "Source Code Pro-13"))
(set-face-attribute 'default nil :font jm/font)
(set-frame-font jm/font)))
#+END_SRC

* Languages
** C
The only way to program.
#+BEGIN_SRC emacs-lisp
(setq c-default-style "k&r")
#+END_SRC

Use four spaces for tabs.
#+BEGIN_SRC emacs-lisp
(setq-default c-basic-offset 4)
#+END_SRC

Many-windows mode makes Emacs into a more traditional IDE for GDB. See
=C-h f gdb= for details. *NOTE:* This doesn't work on OS 10.8 (non-stop
mode isn't supported).

#+BEGIN_SRC emacs-lisp
(setq gdb-many-windows t)
#+END_SRC

** Clojure
#+BEGIN_SRC emacs-lisp
(use-package cider
:pin melpa-stable
:ensure t
:mode ("\\.clj\\'" . clojure-mode))
#+END_SRC

** CSS
Turn on =rainbow-mode= for colored hex values
#+BEGIN_SRC emacs-lisp
(use-package rainbow-mode
:pin gnu
:ensure t
:defer t
:init
(add-hook 'prog-mode-hook 'rainbow-mode))
#+END_SRC

Associate less and scss:
#+BEGIN_SRC emacs-lisp
(associate-file-type '(".less" ".scss" ".sass") 'css-mode)
#+END_SRC

Prevent SCSS from compiling at save time:
#+BEGIN_SRC emacs-lisp
(setq scss-compile-at-save nil)
#+END_SRC

Two spaces:
#+BEGIN_SRC emacs-lisp
(setq css-indent-offset 2)
#+END_SRC

** Graphviz
#+BEGIN_SRC emacs-lisp
(use-package graphviz-dot-mode
:pin melpa-stable
:ensure t
:mode ("\\.gv\\'" "\\.dot\\'"))
#+END_SRC

** Go
#+BEGIN_SRC emacs-lisp
(use-package go-mode
:pin melpa-stable
:ensure t
:mode "\\.go\\'")
#+END_SRC

** JavaScript
2 space indent:

#+BEGIN_SRC emacs-lisp
(setq js-indent-level 2)
(setq js2-basic-offset 2)
(setq js2-bounce-indent-p t)
#+END_SRC

Show errors immediately:
#+BEGIN_SRC emacs-lisp
(setq flycheck-display-errors-delay 0)
#+END_SRC

*** JSON

#+BEGIN_SRC emacs-lisp
(use-package json-mode
:pin melpa-stable
:ensure t
:mode (".babelrc" "\\.json\\'"))
#+END_SRC

*** React

#+BEGIN_SRC emacs-lisp
(use-package rjsx-mode
:pin melpa-unstable
:ensure t
:mode (("\\.jsx" . rjsx-mode))
:bind (:map rjsx-mode-map ("<" . nil)))
#+END_SRC

** LaTeX
Produce PDFs instead of DVIs
#+BEGIN_SRC emacs-lisp
(setq TeX-PDF-mode t)
#+END_SRC

** Lisp
#+BEGIN_SRC emacs-lisp
(define-key lisp-mode-shared-map (kbd "C-c e") 'eval-buffer)

; probably not needed with 25+ 4
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
#+END_SRC

** Markdown
#+BEGIN_SRC emacs-lisp
(use-package markdown-mode
:pin melpa-stable
:ensure t
:mode ("\\.md\\'" "\\.markdown\\'"))
#+END_SRC

** Nginx
#+BEGIN_SRC emacs-lisp
(use-package nginx-mode
:pin melpa-stable
:ensure t
:mode "nginx.conf")
#+END_SRC

** ERB
Support editing mixed mode files, like ERB templates.

#+BEGIN_SRC emacs-lisp
(use-package mmm-auto
:ensure mmm-mode
:pin melpa-stable
:mode ((".rhtml" . html-erb-mode)
(".html.erb" . html-erb-mode)
(".erb" . html-erb-mode))
:config
(setq mmm-global-mode 'auto)
(setq mmm-submode-decoration-level 2)
(setq mmm-parse-when-idle t))
#+END_SRC

** Org-Mode
#+BEGIN_SRC emacs-lisp
(use-package org
:pin gnu
:ensure t
:mode ("\\.org" . org-mode)
:bind (
("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c c" . org-capture)
("C-c b" . org-iswitchb)
("C-c C-x h" . org-html-export-to-html)
;; for terminals -- TAB does not work
("C-x t" . org-cycle))
:config
(org-babel-do-load-languages
'org-babel-load-languages (mapcar (lambda (l) (cons l t))
'(C calc emacs-lisp gnuplot latex ledger perl python ruby screen shell))))

;; for org-html export
(use-package htmlize
:pin melpa-stable
:ensure t
:defer t)
#+END_SRC

Include the org-habit module for the agenda:
#+BEGIN_SRC emacs-lisp
(setq org-modules (quote (org-habit)))
#+END_SRC

Use Org-Mode for the =*scratch*= buffer:
#+begin_src emacs-lisp
(setq initial-major-mode 'org-mode)
(setq initial-scratch-message nil)
#+end_src

*** Paths
This configuration assumes org files live in the =~/org= directory. You can
customize it by setting these variables in =../local/local.el=:
#+BEGIN_SRC emacs-lisp
(setq org-directory "~/org")
(setq org-default-notes-file "~/org/capture.org")
(setq org-journal-file "~/org/journal.org.gpg")
(setq org-work-journal-file "~/org/work.org")
(setq org-log-file "~/org/log.org")
(setq org-notes-file "~/org/notes.org")
(setq org-archive-location "archive/%s_archive::")
(setq org-agenda-files (filter (lambda (fn)
(not (string-match (rx "#") fn)))
(file-expand-wildcards org-directory)))
#+END_SRC

*** Capture Templates
Hit =C-c c= to trigger these:

#+BEGIN_SRC emacs-lisp
(defun jm/find-org-headline (&optional heading)
"Prompts for and finds a heading.

Adapted from URL `http://emacs.stackexchange.com/a/5931'."
(let* ((target (save-excursion
(org-refile-get-location heading nil t t)))
(file (nth 1 target))
(pos (nth 3 target)))
(with-current-buffer (find-file-noselect org-notes-file)
(goto-char pos)
(org-end-of-subtree)
(org-return))))

(setq org-capture-templates
'(("t" "TODO" entry (file+headline org-default-notes-file "Tasks")
"* TODO %^{Task} %^g \n%U \n%?")
("w" "Work Journal" entry (file+datetree org-work-journal-file)
"* %^{Title}\n%U \n%?\n")
("j" "Journal" entry (file+datetree org-journal-file)
"* %^{Title}\n%U \n%?\n")
("n" "Notes" entry (file+function org-notes-file jm/find-org-headline)
"* %^{Title}\n%U \n%?"
:empty-lines 1)
("d" "Appointment" entry (file+headline org-default-notes-file "Tasks")
"* TODO %^{Description} %^g\n%?\nSCHEDULED: %t\n%i\n%a")
("l" "Log" entry (file+datetree+prompt org-log-file)
"* %^{Task} %^g\n%?" :clock-in t :clock-resume t)
))
#+END_SRC

*** Skeleton
#+BEGIN_SRC emacs-lisp
(define-skeleton orgmode-skeleton
"Inserts orgmode defaults into the current buffer."
"Title: "
"#+TITLE: " str | (file-name-nondirectory buffer-file-name) \n
"#+DESCRIPTION: " (skeleton-read "Description: ") \n
"#+STARTUP: align hidestars indent lognotedone" \n
\n _)
#+END_SRC

*** Babel
Highlight src blocks
#+BEGIN_SRC emacs-lisp
(setq org-src-fontify-natively t)
#+END_SRC

#+BEGIN_SRC emacs-lisp
(defun jm/org-confirm-babel-evaluate (lang body)
"Don't ask to confirm evaluating a ledger block."
(not (string= lang "ledger")))
(setq org-confirm-babel-evaluate 'jm/org-confirm-babel-evaluate)
#+END_SRC

*** Diary/Agenda
Hide some holidays:
#+BEGIN_SRC emacs-lisp
(setq holiday-bahai-holidays nil)
(setq holiday-hebrew-holidays nil)
(setq holiday-islamic-holidays nil)
#+END_SRC

Show the agenda from the current day:
#+BEGIN_SRC emacs-lisp
(setq org-agenda-start-on-weekday nil)
#+END_SRC

Show all habits
#+BEGIN_SRC emacs-lisp
(setq org-habit-show-habits-only-for-today nil)
#+END_SRC

Set the location for showing the sunrise/sunset in the agenda:
#+BEGIN_SRC emacs-lisp
(setq calendar-latitude 47.9790)
(setq calendar-longitude -122.2021)
(setq calendar-location-name "Everett, WA")
#+END_SRC

*** Exporting
Remove "Valid XHTML" link
#+BEGIN_SRC emacs-lisp
(setq org-export-html-validation-link nil)
#+END_SRC

Minted latex export
#+BEGIN_SRC emacs-lisp
(setq org-export-latex-minted-options
'(("fontsize" "\\scriptsize")))
#+END_SRC

** Perl
Use the more modern =cperl-mode=
#+BEGIN_SRC emacs-lisp
(defalias 'perl-mode 'cperl-mode)
#+END_SRC

Use =cperl-mode= for =.t= tests
#+BEGIN_SRC emacs-lisp
(associate-file-type '(".t") 'cperl-mode)
#+END_SRC

Use four-space indents
#+BEGIN_SRC emacs-lisp
(setq cperl-indent-level 4)
#+END_SRC

Indent only four-spaces in broken-up calls like
#+BEGIN_SRC perl
someCall(
$var,
$var2
)
#+END_SRC
#+BEGIN_SRC emacs-lisp
(setq cperl-indent-parens-as-block t)
(setq cperl-close-paren-offset -4)
#+END_SRC

Fix indentation for lines not starting statements (e.g., hash members)
#+BEGIN_SRC emacs-lisp
(setq cperl-continued-statement-offset 0)
#+END_SRC#+end_src

** PlantUML

#+begin_src emacs-lisp
(use-package plantuml-mode
:pin melpa-unstable
:ensure t
:mode ("\\.plantuml" . plantuml-mode)
:config
(setq plantuml-default-exec-mode 'jar)
(setq plantuml-jar-path "/usr/share/plantuml/plantuml.jar")
)
#+end_src
** Ruby
#+BEGIN_SRC emacs-lisp
; default for Ruby 2+ is UTF-8, so no need for this anymore
(setq ruby-insert-encoding-magic-comment nil)

(use-package rspec-mode
:pin melpa-stable
:ensure t
:bind (:map ruby-mode-map ("C-c , x" . rspec-verify-single))
:config
(setq rspec-use-rake-when-possible nil)
(setq rspec-use-spring-when-possible t))
(use-package ruby-mode
:mode
("\\.rb\\'" "\\.rake\\'" "Capfile" "Gemfile" "Guardfile" "Rakefile" "\\.ru\\'")
:preface
(defun jm/run-ruby-buffer ()
"Run the current Ruby script and switch focus back to the script."
(interactive)
(ruby-compilation-this-buffer)
(other-window -1))
:bind (:map ruby-mode-map ("C-c C-c" . jm/run-ruby-buffer))
:interpreter "ruby"
:config
(rspec-mode t))

(use-package ruby-compilation
:pin melpa-stable
:ensure t
:defer t)

(use-package inf-ruby
:pin melpa-stable
:defer t
:ensure t
:init
;; for binding.pry to work
(add-hook 'after-init-hook 'inf-ruby-switch-setup))
#+END_SRC

** Scheme
*** Variables
#+BEGIN_SRC emacs-lisp
(setq scheme-program-name "scheme")
#+END_SRC

*** Helper functions
#+BEGIN_SRC emacs-lisp
(defun scheme-run-buffer ()
"Runs the current buffer through scheme and switches focus back to the script."
(interactive)
(scheme-send-region (point-min) (point-max)))
#+END_SRC

*** Hooks
#+BEGIN_SRC emacs-lisp
(add-hook 'scheme-mode-hook
(lambda ()
(local-set-key (kbd "C-c C-c") 'scheme-run-buffer)
(local-set-key (kbd "C-j") 'scheme-send-last-sexp)))
#+END_SRC

*** YAML
#+BEGIN_SRC emacs-lisp
(use-package yaml-mode
:pin melpa-stable
:ensure t
:mode ("\\.yml\\'" "\\.yaml\\'")
:bind (:map yaml-mode-map ("C-m" . newline-and-indent)))
#+END_SRC

*** Docker
#+begin_src emacs-lisp
(use-package dockerfile-mode
:mode ("Dockerfile.*" ".*\\.docker'"))
#+end_src
* Tools
** Browsers
There are far too many ways to configure which browser to use in emacs.
xdg-open should be the default but alas, we need this:

#+BEGIN_SRC emacs-lisp
(setq shr-external-browser 'browse-url-xdg-open)
(setq browse-url-browser-function 'browse-url-generic
browse-url-generic-program "sensible-browser")
#+END_SRC

** Clock
Customize =M-x display-time-world=:
#+BEGIN_SRC emacs-lisp
(setq display-time-world-list
'(("America/Los_Angeles" "Seattle")
("America/Denver" "Cascade")
; coworkers:
("America/Chicago" "Ann Arbor")
("America/New_York" "New York")
("America/Sao_Paulo" "Brazil")
("America/Bogota" "Columbia")
("Asia/Karachi" "Karachi")
("Asia/Manila" "Manila")
("UTC" "UTC")))
#+END_SRC

** Dired
Make it so hitting =C= on a filename in a dired window defaults to the
other dired window:

#+BEGIN_SRC emacs-lisp
(setq dired-dwim-target t)
#+END_SRC

** Jump
#+BEGIN_SRC emacs-lisp
(use-package avy
:init
(bind-key "M-S" 'avy-goto-char-2))
#+END_SRC

** Editorconfig

#+BEGIN_SRC emacs-lisp
(use-package editorconfig
:pin melpa-stable
:ensure t
:config (editorconfig-mode t))
#+END_SRC

** Ledger
#+BEGIN_SRC emacs-lisp
(use-package ledger-mode
:pin melpa-unstable
:ensure t
:defer t
:config
(define-skeleton monthly-interest-skeleton
"Inserts an interest accrued entry into ledger."
"" (insert (replace-regexp-in-string "-" "/" (org-read-date))) " * Monthly Interest Paid" \n
" Assets:"(skeleton-read "Account: ") " " (skeleton-read "Amount: ") \n
"Income:Interest:CapitalOne" \n
\n _)

(defun ledger-toggle-cleared ()
"Toggle --cleared flag on an open ledger report."
(interactive)
(setq ledger-report-cmd
(if (string-match-p "--cleared" ledger-report-cmd)
(replace-regexp-in-string "--cleared" "" ledger-report-cmd)
(replace-regexp-in-string "$" " --cleared" ledger-report-cmd)))
(ledger-report-redo))

(define-key ledger-report-mode-map (kbd "C-c C-c") 'ledger-toggle-cleared)

(defun jm/ledger-format ()
"Clean up a ledger buffer automatically."
(interactive)
(ledger-sort-buffer)
(ledger-post-align-postings (point-min) (point-max)))

;; for consistency with ledger-mode:
(define-key ledger-report-mode-map (kbd "C-c C-o C-r") 'ledger-report-select-report)

(setq ledger-reports
'(
("bal" "%(binary) -f %(ledger-file) bal")
("biz" "%(binary) -f %(ledger-file) bal Biz")
("biz-income" "%(binary) -f %(ledger-file) equity Revenue Biz:Receivable")
("cash" "%(binary) -f %(ledger-file) bal Assets:Checking Assets:Savings --cleared")
("cat" "%(binary) -f %(ledger-file) reg Assets:Reimbursements:Catherine --dc --cleared")
("cc-rewards" "%(binary) -f %(ledger-file) bal Income:Rebate --cleared")
("cc-spending" "%(binary) -f %(ledger-file) bal Liabilities:Credit -l 'amount < 0'")
("checking-cap1" "%(binary) -f %(ledger-file) reg Assets:Checking:CapitalOne --display 'd>=[last month]' --cleared")
("credit-cap1" "%(binary) -f %(ledger-file) reg Liabilities:Credit:CapitalOne --display 'd>=[last month]' --cleared")
("donations" "%(binary) -f %(ledger-file) bal Expenses:Donations Liabilities:Donations")
("exp-nonessential" "%(binary) -f %(ledger-file) bal Expenses:Entertainment Expenses:Sports Expenses:Travel Expenses:Woodworking")
("mortgage" "%(binary) -f %(ledger-file) bal Virtual:Home Assets:Home")
("net" "%(binary) -f %(ledger-file) bal Assets Liabilities --cleared")
("payee" "%(binary) -f %(ledger-file) reg @%(payee)")
("reg" "%(binary) -f %(ledger-file) reg")
("savings-goals" "%(binary) -f %(ledger-file) bal Virtual:Goals Assets:Savings:Buffer Assets:Savings:Emergency ")
("savings-emergency" "%(binary) -f %(ledger-file) reg Assets:Savings:Emergency --display 'd>=[last month]' --cleared")
("savings-buffer" "%(binary) -f %(ledger-file) reg Assets:Savings:Buffer --display 'd>=[last month]' --cleared")
("savings-taxes" "%(binary) -f %(ledger-file) reg Assets:Savings:Taxes --display 'd>=[last month]' --cleared")
("taxes" "%(binary) -f %(ledger-file) bal --cleared Liabilities:Taxes Savings:Taxes")
("uncleared" "%(binary) -f %(ledger-file) reg --uncleared")
("year-spending" "%(binary) -f %(ledger-file) --monthly --empty --collapse reg Expenses")
)))
#+END_SRC

** Man
Open man pages in a different window
#+BEGIN_SRC emacs-lisp
(setq Man-notify-method 'friendly)
#+END_SRC

I tend to keep man pages pretty narrow
#+BEGIN_SRC emacs-lisp
(setenv "MANWIDTH" "72")
#+END_SRC

** Magit
#+BEGIN_SRC emacs-lisp
(use-package magit
:pin melpa-stable
:ensure t
:bind (("C-x g" . magit-status)
("C-x G" . magit-blame-addition)))
#+END_SRC

** MOTD

#+BEGIN_SRC emacs-lisp
(defun motd ()
"Inspirational quotes and such."
(interactive)
(let ((quotes '(("Victor Frankl" . "Between stimulus and response there is a space. In that space is our power to choose our response. In our response lies our growth and our freedom.")
("Steve Jobs" . "If today were the last day of my life, would I want to do what I am about to do today? And whenever the answer has been ``no'' for too many days in a row, I know I need to change something."))))
(let ((record (nth (random (length quotes)) quotes)))
(message "> %s\n> —%s" (cdr record) (car record)))))
#+END_SRC

Run the above every few hours:
#+BEGIN_SRC emacs-lisp
(setq my-timer (run-with-idle-timer 14400 t 'motd))
#+END_SRC

** Projectile
Find files in a project:
#+BEGIN_SRC emacs-lisp
(use-package projectile
:pin melpa-stable
:ensure t
:bind ("C-x p" . projectile-find-file)
:bind-keymap ("C-x P" . projectile-command-map)
:config
(projectile-mode t)
(setq projectile-enable-caching t)
(setq projectile-cache-file (jm/local-path "projectile-cache")))
(setq projectile-known-projects-file (jm/local-path "projectile-bookmarks.eld"))
#+END_SRC

** Shell
Set =$PAGER= to =cat= to avoid =WARNING: terminal is not fully
functional= messages.
#+BEGIN_SRC emacs-lisp
(setenv "PAGER" "cat")
#+END_SRC

Ensure eshell garbage stays in =~/.emacs.d/local=:
#+BEGIN_SRC emacs-lisp
(setq eshell-directory-name (concat user-emacs-directory "local/eshell"))
#+END_SRC

** Silver Searcher
#+BEGIN_SRC emacs-lisp
(use-package ag
:ensure t
:pin melpa-stable
:bind ("C-x a" . ag-project-regexp)
:config
(setq ag-highlight-search t))
#+END_SRC

* Local configuration
Load local config to override any of the above settings
#+BEGIN_SRC emacs-lisp
(load (jm/local-path "local") 'noerror)
#+END_SRC