No description, website, or topics provided.
Emacs Lisp
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
conf
snippets
.gitignore
README.org
init.el

README.org

Emacs Configuration

User information

(setq user-full-name "Svend Sorensen")
(setq user-mail-address "svend@svends.net")

Initialize package.el

(require 'package)
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")))
;; Add nix elpa directory
(add-to-list 'package-directory-list "~/.nix-profile/share/emacs/site-lisp/elpa")

;; Do not write installed packages to package-selected-packages in custom-file
(defun package--save-selected-packages (&rest opt) nil)

From MELPA - Getting Started.

(require 'package) ;; You might already have this line
(let* ((no-ssl (and (memq system-type '(windows-nt ms-dos))
                    (not (gnutls-available-p))))
       (url (concat (if no-ssl "http" "https") "://melpa.org/packages/")))
  (add-to-list 'package-archives (cons "melpa" url) t))
(when (< emacs-major-version 24)
  ;; For important compatibility libraries like cl-lib
  (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/")))
(package-initialize) ;; You might already have this line

Initialize use-package

(defun my-require-package (package)
  "Install PACKAGE unless already installed."
  (unless (package-installed-p package)
    (package-refresh-contents)
    (package-install package)))

(my-require-package 'use-package)

This is required before any use-package forms.

(eval-when-compile
  (require 'use-package))
(require 'diminish)
(require 'bind-key)

Install all packages.

(setq use-package-always-ensure t)

Initialize exec-path-from-shell

Function that gets environmental variables from bash. This uses printenv from nixpkgs on macOS.

(defun bash-shell-variables()
  "Return a list of env variables.
  This requires the nixpkgs coreutils package on macOS."
  (let ((printenv (if (eq window-system 'ns)
                      (expand-file-name "~/.nix-profile/bin/printenv")
                    "printenv")))
    (mapcar (lambda (s) (car (split-string s "=")))
            (split-string
             (shell-command-to-string
              (format
               "bash -l -c \"%s --null\" 2>/dev/null" printenv))
             (char-to-string ?\x0) t))))

(defun my-exec-path-from-shell-initialize ()
  "Initialize environment with all shell variables."
  (interactive)
  (exec-path-from-shell-copy-envs (bash-shell-variables)))

This needs to come before anything that uses PATH (e.g. executable-find).

(use-package exec-path-from-shell
  :if window-system
  :init (setq exec-path-from-shell-variables (bash-shell-variables))
  :config (exec-path-from-shell-initialize))

Emacs UI

Chrome

  • Disable welcome screen
  • Disable menu bar
  • Disable tool bar
(setq inhibit-splash-screen t)
(if (fboundp 'menu-bar-mode) (menu-bar-mode -1))
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))

Mode line

  • Display clock in the status bar
  • Display column number in mode-line (line number is displayed by default)
(display-time-mode t)
(column-number-mode t)

Display date in 24 hour format in mode line.

(setq display-time-day-and-date t)
(setq display-time-24hr-format t)

Make the cursor a bar instead of a filled box.

(setq-default cursor-type 'bar)

Scrolling

  • Enable smooth scrolling.
  • Horizontally scroll current line.
(pixel-scroll-mode)
(setq auto-hscroll-mode 'current-line)

Fonts

Linux

User fonts go in $XDG_DATA_HOME/fonts/ (~/.local/share/fonts).

macOS

Install homebrew-cask and caskroom-fonts.

brew tap caskroom/cask
brew tap caskroom/font

Install fonts.

brew cask install font-dejavu-sans

Fixed pitch mode

(require 'face-remap)

(defun my-fixed-pitch-mode (&optional arg)
  "Fixed-pitch default-face mode.
  An interface to `buffer-face-mode' which uses the `fixed-pitch' face.
  Besides the choice of face, it is the same as `buffer-face-mode'."
  (interactive (list (or current-prefix-arg 'toggle)))
  (buffer-face-mode-invoke 'fixed-pitch arg
                           (called-interactively-p 'interactive)))

;; Remove BufFace from mode line
(eval-after-load "face-remap"
  '(diminish 'buffer-face-mode))

Disable pager

Set PAGER to cat to disable less in async buffers.

(setenv "PAGER" "cat")

Emacs themes

Disable current theme before loading new theme. This prevents artifacts from the old theme.

Emacs disable-theme after loading a different one (Stack Overflow)

(defun disable-all-themes ()
  "Disable all active themes."
  (interactive)
  (dolist (i custom-enabled-themes)
    (disable-theme i)))

(defun my-load-theme ()
  "Load a single theme then load override theme."
  (interactive)
  (disable-all-themes)
  (call-interactively 'load-theme)
  (load-theme 'svend t)
  (load-theme 'svend-font-dejavu t))

Treat all themes as safe.

(setq custom-safe-themes t)
(setq custom-theme-directory "~/.emacs.d/conf/")

Load my basic themes.

(load-theme 'svend 't)
(load-theme 'svend-font-dejavu t)

Emacs settings

Bell

Use visual bell.

(setq visible-bell t)

Reduce bell noise for common actions (e.g. C-g).

(setq ring-bell-function
      (lambda ()
        (unless
            (memq this-command
                  '(abort-recursive-edit
                    isearch-abort
                    isearch-printing-char
                    keyboard-quit
                    nil))
          (ding))))

Mouse

Copy test selected by the mouse to the kill ring. This was turned off in Emacs 24.

(setq mouse-drag-copy-region t)

Highlight current line

Highlight the current line. Highlight line in inactive windows.

(setq global-hl-line-sticky-flag t)
(global-hl-line-mode t)

To disable for a mode, add this to the mode hook:

(make-local-variable 'global-hl-line-mode)
(setq global-hl-line-mode nil)

Y/N answers

Enable y/n answers.

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

Balance windows

Balance windows horizontally automatically.

This is now disabled.

(advice-add 'split-window-below :after #'balance-windows-horizontally)
(advice-add 'split-window-right :after #'balance-windows-horizontally)
;; (advice-add 'split-window :after #'balance-windows-horizontally)
(advice-add 'delete-window :after #'balance-windows-horizontally)

Disabled commands

(mapc (lambda (command) (put command 'disabled nil))
      '(erase-buffer
        downcase-region
        upcase-region
        upcase-initials-region))

Disable keyboard shortcut to print buffer.

(global-unset-key (kbd "s-p"))

Enable delete-selection-mode

(delete-selection-mode)

macOS specific configuration

Turn on menu bar, since it does not use any extra space on macOS.

(when (eq window-system 'ns)
  (menu-bar-mode 1))

Programming modes

Turn on flyspell and goto-address for all text buffers.

(add-hook 'text-mode-hook #'flyspell-mode)
(add-hook 'text-mode-hook #'goto-address-mode)
(add-hook 'text-mode-hook #'variable-pitch-mode)

Turn on flyspell, goto-address, linum, and whitespace for programming buffers.

(defun my-prog-mode-hook()
  (flyspell-prog-mode)
  (goto-address-prog-mode)

  (if (< emacs-major-version 26)
      (nlinum-mode)
    (setq display-line-numbers t))

  (setq show-trailing-whitespace t))

(add-hook 'prog-mode-hook #'my-prog-mode-hook)
(add-hook 'yaml-mode-hook #'my-prog-mode-hook)
(add-hook 'yaml-mode-hook #'my-fixed-pitch-mode)

Auto modes

bash-fc-* are bash command editing temporary files (fc built-in).

(add-to-list 'auto-mode-alist '(".mrconfig$" . conf-mode))
(add-to-list 'auto-mode-alist '("/etc/network/interfaces" . conf-mode))
(add-to-list 'auto-mode-alist '("Carton\\'" . lisp-mode))
(add-to-list 'auto-mode-alist '("bash-fc-" . sh-mode))

Lock files

http://www.gnu.org/software/emacs/manual/html_node/elisp/File-Locks.html

Locks are created in the same directory as the file being edited. They can be disabled as of 24.3.

http://lists.gnu.org/archive/html/emacs-devel/2011-07/msg01020.html

(setq create-lockfiles nil)

Backup and auto-saves

Put all backup and auto-saves into ~/.emacs.d instead of the current directory.

(setq backup-directory-alist
      `((".*" . ,(expand-file-name "backup/" user-emacs-directory))))
(setq auto-save-file-name-transforms
      `((".*" ,(expand-file-name "backup/" user-emacs-directory) t)))

Revert

Enable global auto-revert mode.

(global-auto-revert-mode 1)
(setq global-auto-revert-non-file-buffers t)

Key bindings

C-c letter and <F5> through <F9> are reserved for user use. Press C-c C-h to show all of these.

(bind-key "C-c b" 'browse-url-at-point)
(bind-key "C-c d" 'my-insert-date)
(bind-key "C-c e" 'eww)
(bind-key "C-c j" 'dired-jump)
(bind-key "C-c r" 'revert-buffer)

Space as control key

Use space as control key using xcape on Linux and Karabiner on macOS.

xcape:

# Map an unused modifier's keysym to the spacebar's keycode and make
# it a control modifier. It needs to be an existing key so that emacs
# won't spazz out when you press it. Hyper_L is a good candidate.
spare_modifier="Hyper_L"
xmodmap -e "keycode 65 = $spare_modifier"
xmodmap -e "remove mod4 = $spare_modifier" # hyper_l is mod4 by default
xmodmap -e "add Control = $spare_modifier"

# Map space to an unused keycode (to keep it around for xcape to use).
xmodmap -e "keycode any = space"

# Finally use xcape to cause the space bar to generate a space when
# tapped.
xcape -e "$spare_modifier=space"

Karabiner:

  • Change Space Key
    • Space to Control_L (+ When you type Space only, send Space)
(bind-key "C-x M-SPC" 'pop-global-mark)
(bind-key "M-SPC" 'set-mark-command)
(bind-key "M-s-SPC" 'mark-sexp)
(bind-key "M-s- " 'mark-sexp)           ; macOS
(bind-key "s-SPC" 'just-one-space)

Other settings

Rapid mark-pop (C-u C-SPC C-SPC...).

(setq set-mark-command-repeat-pop t)

Shorter auto-revert interval. Default is 5 seconds.

(setq auto-revert-interval 1)

Misc settings.

(setq enable-local-variables :safe)
(setq require-final-newline 'ask)
(setq save-interprogram-paste-before-kill t) ;; Do not clobber text copied from the clipboard
(setq sentence-end-double-space nil)
(setq-default indent-tabs-mode nil)
(show-paren-mode)

Wrap lines at N columns instead of 70.

(setq-default fill-column 80)

Add timezones for display-time-world.

(add-to-list 'zoneinfo-style-world-list '("UTC" "UTC"))
(add-to-list 'zoneinfo-style-world-list '("Europe/Budapest" "Budapest"))
(add-to-list 'zoneinfo-style-world-list '("America/Chicago" "Chicago"))

Prefer newer files.

(setq load-prefer-newer t)

Add options to kill or revert buffer when prompting to save modified buffers.

(add-to-list
 'save-some-buffers-action-alist
 '(?k
   (lambda (buf)
     (kill-buffer buf))
   "kill this buffer"))

(add-to-list
 'save-some-buffers-action-alist
 '(?r
   (lambda (buf)
     (save-current-buffer
       (set-buffer buf)
       (revert-buffer t t t)))
   "revert this buffer"))

Compile

(setq compilation-scroll-output 'first-error)
(defun my-colorize-compilation-buffer ()
  "Colorize a compilation mode buffer."
  ;; we don't want to mess with child modes such as grep-mode, ack, ag, etc
  (when (eq major-mode 'compilation-mode)
    (let ((inhibit-read-only t))
      (ansi-color-apply-on-region (point-min) (point-max)))))

;; Colorize output of Compilation Mode, see
;; http://stackoverflow.com/a/3072831/355252
(require 'ansi-color)
(add-hook 'compilation-filter-hook #'my-colorize-compilation-buffer)

Scratch buffer

(setq initial-major-mode 'org-mode)
(setq initial-scratch-message "#+TITLE: Scratch Buffer\n\n")

User defined functions

Hacked version of balance-windows which only balances windows horizontally.

(defun balance-windows-horizontally (&optional window-or-frame)
  "Horizontally balance the sizes of windows of WINDOW-OR-FRAME.
  WINDOW-OR-FRAME is optional and defaults to the selected frame.
  If WINDOW-OR-FRAME denotes a frame, balance the sizes of all
  windows of that frame.  If WINDOW-OR-FRAME denotes a window,
  recursively balance the sizes of all child windows of that
  window."
  (interactive)
  (let* ((window
          (cond
           ((or (not window-or-frame)
                (frame-live-p window-or-frame))
            (frame-root-window window-or-frame))
           ((or (window-live-p window-or-frame)
                (window-child window-or-frame))
            window-or-frame)
           (t
            (error "Not a window or frame %s" window-or-frame))))
         (frame (window-frame window)))
    ;; ;; Balance vertically.
    ;; (window--resize-reset (window-frame window))
    ;; (balance-windows-1 window)
    ;; (when (window--resize-apply-p frame)
    ;;   (window-resize-apply frame)
    ;;   (window--pixel-to-total frame)
    ;;   (run-window-configuration-change-hook frame))
    ;; Balance horizontally.
    (window--resize-reset (window-frame window) t)
    (balance-windows-1 window t)
    (when (window--resize-apply-p frame t)
      (window-resize-apply frame t)
      (window--pixel-to-total frame t)
      (run-window-configuration-change-hook frame))))
(defun my-toggle-line-numbers()
  (interactive)
  (if (< emacs-major-version 26)
      (nlinum-mode)
    (call-interactively #'display-line-numbers-mode)))
(defun my-shell-cd ()
  "Switch to shell buffer and change directory to `default-directory'."
  (interactive)
  (let ((d default-directory))
    (shell)
    (goto-char (point-max))
    (insert (format "cd %s" d))
    (comint-send-input)))
(defun my-insert-date (arg)
  "Insert date string"
  (interactive "p")
  (cond ((= arg 1)
         (insert (format-time-string "%F")))
        ((= arg 4)
         (insert (format-time-string "%F-%H%M%S")))))

Packages

ace-link

(use-package ace-link
  :init (ace-link-setup-default))

ace-window

(use-package ace-window
  :bind (("C-x o" . ace-window)))

aggressive-indent

(use-package aggressive-indent
  :config
  (add-to-list 'aggressive-indent-excluded-modes 'nix-mode)
  (add-to-list 'aggressive-indent-excluded-modes 'rust-mode)
  :init
  (global-aggressive-indent-mode 1))

alert

(use-package alert
  :defer t
  :init
  (defun comint-alert-on-prompt (string)
    "Send alert when prompt is detected."
    (when (let ((case-fold-search t))
            (string-match comint-prompt-regexp string))
      (alert (format "Prompt: %s" string)))
    string)

  (defun comint-toggle-alert ()
    "Toggle alert on prompt for current buffer"
    (interactive)
    (make-local-variable 'comint-output-filter-functions)
    (if (member 'comint-alert-on-prompt comint-output-filter-functions)
        (remove-hook 'comint-output-filter-functions 'comint-alert-on-prompt)
      (add-hook 'comint-output-filter-functions #'comint-alert-on-prompt)))
  :config
  (setq alert-default-style
        (if (eq window-system 'ns)
            'notifier
          'notifications)))

amx

(use-package amx
  :bind (("M-X" . amx-major-mode-commands))
  :init (amx-mode))

auth-password-store

(use-package auth-password-store
  :if (< emacs-major-version 26)
  :init (auth-pass-enable))

auth-source-pass

(use-package auth-source-pass
  :if (>= emacs-major-version 26)
  :init (auth-source-pass-enable))

avy

(use-package avy
  :bind (("C-c a" . avy-goto-char-timer)
         ("M-g M-g" . avy-goto-line)))

bash-completion

(use-package bash-completion
  :config
  (defun my-bash-completion-dynamic-complete-local()
    "Returns the completion table for bash command at point if the buffer is not remote."
    (unless (file-remote-p default-directory)
      (bash-completion-dynamic-complete)))

  ;; My bash-completion is loaded by .bash_profile, which is only sourced by a
  ;; login shell
  (setq bash-completion-args '("--noediting" "--login"))
  ;; I use nixpkgs bash, which puts bash in my PATH
  (setq bash-completion-prog "bash")

  (add-hook 'shell-dynamic-complete-functions
            'my-bash-completion-dynamic-complete-local))

bpr

(define-derived-mode bpr-shell-mode
            shell-mode "BPR"
            "Major mode for BPR process buffers.")

(defun my-bpr-on-start (process)
  (set-process-filter process 'comint-output-filter))

;;;###autoload
(defun my-bpr-switch-to-last-buffer ()
  "Opens the buffer of the last spawned process."
  (interactive)
  (if (buffer-live-p bpr-last-buffer)
      (switch-to-buffer bpr-last-buffer)
    (message "Can't find last used buffer")))

(defun my-bpr-spawn (open-buffer)
  "Run 'bpr-spawn'.
If OPEN-BUFFER is set, open the new buffer."
  (interactive "P")
  (call-interactively #'bpr-spawn)
  (if open-buffer
      (my-bpr-switch-to-last-buffer)))

(use-package bpr
  :bind (("M-&" . my-bpr-spawn))
  :config
  (setq bpr-show-progress nil
        bpr-on-start #'my-bpr-on-start
        bpr-process-mode #'bpr-shell-mode
        bpr-use-projectile nil))

calfw

(use-package calfw
  :defer t
  :config
  (setq cfw:fchar-junction ?╋
        cfw:fchar-vertical-line ?┃
        cfw:fchar-horizontal-line ?━
        cfw:fchar-left-junction ?┣
        cfw:fchar-right-junction ?┫
        cfw:fchar-top-junction ?┯
        cfw:fchar-top-left-corner ?┏
        cfw:fchar-top-right-corner ?┓))

color-theme-sanityinc-tomorrow

(use-package color-theme-sanityinc-tomorrow
  :defer t)

comint-mode

Add more password prompts.

(setq comint-password-prompt-regexp
      (concat comint-password-prompt-regexp
              "\\|"
              ;; OpenStack
              "Please enter your OpenStack Password:"
              "\\|"
              ;; curl
              "Enter host password for user '[^']*':"
              "\\|"
              ;; Ansible
              "SUDO password:"
              "\\|"
              "Vault password:"
              "\\|"
              ;; collins-shell (https://tumblr.github.io/collins/tools.html#collins%20shell)
              "Enter your password:"
              "\\|"
              ;; openssl pkcs12 -nocerts -nodesopenssl
              "Enter Import Password:"
              "\\|"
              ;; sshuttle
              "[local sudo] Password:"))

Change scrolling behavior for comint modes.

(defun comint-mode-config()
  ;; Do not move prompt to bottom of the screen on output
  (setq comint-scroll-show-maximum-output nil)
  ;; Do not center the prompt when scrolling
  ;;
  ;; ("If the value is greater than 100, redisplay will never recenter
  ;; point, but will always scroll just enough text to bring point
  ;; into view, even if you move far away.")
  (setq-local scroll-conservatively 101))

(add-hook 'comint-mode-hook #'comint-mode-config)

company

(use-package company
  :init
  (global-company-mode)
  :config
  (setq company-lighter-base "Co"
        company-show-numbers t
        company-minimum-prefix-length 2))

company-go

(use-package company-go
  :defer t)

company-jedi

(use-package company-jedi
  ;; :init (add-hook 'python-mode-hook 'jedi:setup)
  :config
  (setq jedi:use-shortcuts t))

counsel

(use-package counsel
  :bind (("C-c y" . counsel-yank-pop)
         ("C-x C-f" . counsel-find-file))
  :config
  (setq counsel-find-file-at-point t
        counsel-rg-base-command "rg --smart-case --no-heading --line-number --max-columns 150 --color never %s ."))

csv-mode

(use-package csv-mode
  :defer t)

debbugs

(use-package debbugs
  :defer t)

desktop

(use-package desktop
  :config
  (defun my-shell-save-desktop-data (desktop-dirname)
    "Extra info for shell-mode buffers to be saved in the desktop file."
    (list default-directory comint-input-ring))

  (defun my-shell-restore-desktop-buffer
      (desktop-buffer-file-name desktop-buffer-name desktop-buffer-misc)
    "Restore a shell buffer's state from the desktop file."
    (let ((dir (nth 0 desktop-buffer-misc))
          (ring (nth 1 desktop-buffer-misc)))
      (when desktop-buffer-name
        (set-buffer (get-buffer-create desktop-buffer-name))
        (when dir
          (setq default-directory dir))
        (shell desktop-buffer-name)
        (when ring
          (setq comint-input-ring ring))
        (current-buffer))))

  (defun my-shell-setup-desktop ()
    "Sets up a shell buffer to have its state saved in the desktop file."
    (set (make-local-variable 'desktop-save-buffer) #'my-shell-save-desktop-data))

  (add-to-list 'desktop-buffer-mode-handlers
               '(shell-mode . my-shell-restore-desktop-buffer))
  (add-hook 'shell-mode-hook #'my-shell-setup-desktop)

  (setq desktop-buffers-not-to-save "\\*Async Shell Command\\*\\|\\*shell\\*<")

  ;; Do not save GPG-encrypted files to the desktop
  (setq desktop-files-not-to-save "\\(^/[^/:]*:\\|(ftp)$\\|\\.gpg$\\)")
  ;; Do not save BPR shell buffers
  (setq desktop-modes-not-to-save '(tags-table-mode bpr-shell-mode))
  ;; Load 20 buffers on start, then lazily restore emaining buffer
  (setq desktop-restore-eager 20)
  ;; Do not save frame and window configuration (saving these leaves artifacts
  ;; from loaded themes)
  (setq desktop-restore-frames nil)

  ;; Periodically save desktop
  (defun my-setup-desktop-auto-save ()
    (setq my-save-desktop-timer
          (run-with-idle-timer
           5 t
           (lambda ()
             (desktop-save desktop-dirname)))))
  (add-hook 'desktop-after-read-hook #'my-setup-desktop-auto-save)
  :init
  (desktop-save-mode 1))

dns-mode

(use-package dns-mode
  :defer t
  :config
  ;; Do not auto increment serial (C-c C-s to increment)
  (setq dns-mode-soa-auto-increment-serial nil))

docker-tramp

(use-package docker-tramp
  :defer t)

dockerfile-mode

(use-package dockerfile-mode
  :defer t)

ediff

(use-package ediff
  :defer t)

edit-indirect

This is used to edit code blocks in markdown-mode.

(use-package edit-indirect
  :defer t)

ensime

(use-package ensime
  :defer t
  :config
  (add-hook 'scala-mode-hook #'ensime-scala-mode-hook))

erc

(use-package erc
  :defer t
  :config
  (erc-services-mode 1)
  (erc-spelling-mode 1)

  (setq erc-hide-list '("JOIN" "MODE" "PART" "QUIT"))

  ;; Nickserv configuration
  (setq erc-nick "svend")
  (setq erc-prompt-for-nickserv-password nil)
  (let ((bitlbee-username (password-store-get "bitlbee-username"))
        (bitlbee-password (password-store-get "bitlbee-password"))
        (freenode-username (password-store-get "freenode/username"))
        (freenode-password (password-store-get "freenode/password")))
    (setq erc-nickserv-passwords
          `((BitlBee ((,bitlbee-username . ,bitlbee-password)))
            ((freenode ((,freenode-username . ,freenode-password)))))))

  (setq erc-autojoin-channels-alist '(("freenode.net" "#nixos" "##nix-darwin" "#org-mode" "#emacs"))))

erc-track

(use-package erc-track
  :ensure nil
  :defer t
  :config
  ;; Do not notify for join, part, or quit
  (add-to-list 'erc-track-exclude-types "JOIN")
  (add-to-list 'erc-track-exclude-types "PART")
  (add-to-list 'erc-track-exclude-types "QUIT"))

erlang

(use-package erlang
  :defer t)

expand-region

(use-package expand-region
  :bind (("M-S-SPC" . er/expand-region)))

flycheck

(use-package flycheck
  :init
  (use-package flycheck-ledger
    :defer t)
  (use-package flycheck-rust
    :config
    (add-hook 'flycheck-mode-hook #'flycheck-rust-setup))
  :config
  ;; (add-hook 'flycheck-mode-hook #'flycheck-cask-setup)
  (flycheck-add-mode #'yaml-ruby #'ansible-playbook-mode)
  (flycheck-add-next-checker 'chef-foodcritic 'ruby-rubocop)
  (add-hook 'after-init-hook #'global-flycheck-mode))

git

(use-package git
  :defer t
  :config
  (defun my-git-clone (url)
    (interactive "sGit repository URL: ")
    (let ((git-repo "~/src"))
      (git-clone url))))

git-commit

(use-package git-commit)

gitconfig-mode

(use-package gitconfig-mode
  :defer t)

gitignore-mode

(use-package gitignore-mode
  :defer t)

gnuplot

(use-package gnuplot
  :defer t)

gnus

Sanitized version of .authinfo.gpg for Gmail IMAP and SMTP.

gpg --batch -d ~/.authinfo.gpg | awk '/\.gmail\.com/{$4="EMAIL";$6="PASSWORD";print}'
pass show imap.gmail.com | sed -e '1s/.*/PASSWORD/' -e '/user:/s/[^ ]*$/EMAIL/'
pass show smtp.gmail.com | sed -e '1s/.*/PASSWORD/' -e '/user:/s/[^ ]*$/EMAIL/'
(use-package gnus
  :config
  ;; Use secondary-select-methods
  (setq gnus-select-method '(nnnil ""))

  ;; ;; Gmane
  (add-to-list 'gnus-secondary-select-methods
               '(nntp "news.gmane.org"))

  ;; Fastmail
  (add-to-list 'gnus-secondary-select-methods
               '(nnimap "imap.fastmail.com"))
  ;; Gmail
  (add-to-list 'gnus-secondary-select-methods
               '(nnimap "imap.gmail.com"))

  ;; (add-to-list 'gnus-secondary-select-methods
  ;;              '(nnimap "imap.gmail.com"
  ;;                       (nnimap-address "imap.gmail.com")
  ;;                       ;; (nnimap-server-port 993)
  ;;                       ;; (nnimap-stream ssl)
  ;;                       ))

  ;; ;; Record all IMAP commands in the ‘"*imap log*"’
  ;; (setq nnimap-record-commands t)

  ;; Skip prompt: "Gnus auto-save file exists. Do you want to read it?"
  (setq gnus-always-read-dribble-file t
        ;; Mark sent messages as read
        gnus-gcc-mark-as-read t
        gnus-inhibit-startup-message t
        ;; Do not take over the entire frame
        gnus-use-full-window nil))

gnus-alias

(use-package gnus-alias
  :defer t
  :config
  (setq gnus-alias-identity-alist
        '(("fastmail" nil "Svend Sorensen <svend@svends.net>" nil (("Bcc" . "svend@svends.net")) nil)
          ("gmail" nil "Svend Sorensen <svend@ciffer.net>" nil nil nil)
          ("wp" nil "Svend Sorensen <ssorensen@whitepages.com>" nil (("Bcc" . "ssorensen@whitepages.com")) nil nil)))
  (setq gnus-alias-default-identity "fastmail")
  (setq gnus-alias-identity-rules '()))

gnutls

(use-package gnutls
  :defer t
  :config
  (add-to-list 'gnutls-trustfiles
               (expand-file-name "~/.certs/ca-bundle.crt")))

go-eldoc

(use-package go-eldoc
  :defer t)

go-mode

  • gocode (for go-eldoc)
  • godef (for go-mode’s godef-* commands)
  • goimports (for gofmt-command)
  • golint (used by flycheck)
  • errcheck (used by flycheck)
go get -u golang.org/x/tools/cmd/goimports
go get -u github.com/rogpeppe/godef
go get -u github.com/golang/lint/golint
go get -u github.com/nsf/gocode
go get -u github.com/kisielk/errcheck
(use-package go-mode
  :defer t
  :config
  (setq gofmt-command "goimports")

  (defun my-go-mode-defaults ()
    (local-set-key (kbd "M-.") 'godef-jump)
    (set (make-local-variable 'company-backends) '(company-go))
    (add-hook 'before-save-hook #'gofmt-before-save)

    ;; El-doc for Go
    (go-eldoc-setup)

    ;; CamelCase aware editing operations
    (subword-mode +1))
  (add-hook 'go-mode-hook #'my-go-mode-defaults))

dired

(use-package dired
  :ensure nil
  :config
  (defun my-dired-mode-hook ()
    (setq truncate-lines t))
  (add-hook 'dired-mode-hook #'my-dired-mode-hook))

groovy-mode

(use-package groovy-mode
  :config
  (defun my-groovy-mode-hook ()
    ;; Indent groovy code four spaces instead of two
    (setq c-basic-offset 4))
  (add-hook 'groovy-mode-hook #'my-groovy-mode-hook)
  :mode
  (("Jenkinsfile\\'" . groovy-mode)))

haskell-mode

(use-package haskell-mode
  :defer t
  :config
  (defun my-haskell-mode-defaults ()
    (subword-mode +1)
    (turn-on-haskell-doc-mode)
    (turn-on-haskell-indentation)
    (interactive-haskell-mode +1))
  (add-hook 'haskell-mode-hook #'my-haskell-mode-defaults))

hippie-exp

info:autotype#Hippie Expand http://www.gnu.org/software/emacs/manual/html_node/autotype/Hippie-Expand.html

(use-package hippie-exp
  :bind (("M-/" . hippie-expand)))

hydra

(use-package hydra
  :defer t
  :config
  (global-set-key
   (kbd "C-c t")
   (defhydra hydra-toggle ()
     "Toggle"
     ("b" scroll-bar-mode "scroll-bar")
     ("c" flycheck-mode "flycheck")
     ("f" variable-pitch-mode "fixed-pitch")
     ("h" global-hl-line-mode "hl-line")
     ("l" visual-line-mode "visual-line")
     ("m" menu-bar-mode "menu-bar")
     ("n" my-toggle-line-numbers "line-numbers")
     ("s" flyspell-mode "flyspell")
     ("t" toggle-truncate-lines "trucate")
     ("v" visual-fill-column-mode "visual-fill-column")
     ("w" whitespace-mode "whitespace")))

  (defhydra hydra-winner ()
    "Winner"
    ("w" winner-undo "back")
    ("r" winner-redo "forward" :exit t))
  (global-set-key (kbd "C-c w") 'hydra-winner/winner-undo))

ibuffer

(use-package ibuffer
  :ensure nil
  :bind (("C-x C-b" . ibuffer)))

ibuffer-tramp

(use-package ibuffer-tramp
  :config
  (add-hook 'ibuffer-hook
            (lambda ()
              (ibuffer-tramp-set-filter-groups-by-tramp-connection)
              (ibuffer-do-sort-by-alphabetic))))

inf-ruby

(use-package inf-ruby
  :defer t
  :config
  (defun my-inf-ruby-mode-setup ()
    (setq comint-input-ring-file-name "~/.pry_history")
    (when (ring-empty-p comint-input-ring)
      (comint-read-input-ring t)))
  (add-hook 'inf-ruby-mode-hook #'my-inf-ruby-mode-setup)
  (setq inf-ruby-default-implementation "pry"))

ivy

(use-package ivy
  :bind (("C-c s" . swiper))
  :config
  (setq ivy-re-builders-alist '((swiper . ivy--regex-plus)
                                (t . ivy--regex-fuzzy))
        ivy-magic-tilde nil
        ivy-use-virtual-buffers t)
  :init
  (ivy-mode 1))

jabber

(use-package jabber
  :defer t
  :config
  (add-hook 'jabber-chat-mode-hook #'visual-line-mode)

  (add-to-list 'jabber-account-list '("23430_935967@chat.hipchat.com"))

  ;; jabber-jid-user: Wrong type argument: stringp, ("svend@ciffer.net/emacs" (:network-server . "talk.google.com") (:connection-type . starttls))
  ;; (add-to-list 'jabber-account-list '(("svend@ciffer.net/emacs"
  ;;                                      (:network-server . "talk.google.com")
  ;;                                      (:connection-type . starttls))))
  ;; FIXME: svend@ciffer.net/emacs: connection lost: ‘STARTTLS negotiation
  ;; failed: The x509 certificate does not match "ciffer.net"’
  (add-to-list 'jabber-invalid-certificate-servers "ciffer.net")

  (defvar hipchat-number "23430")
  (defvar hipchat-nickname "Svend Sorensen")
  (defvar hipchat-rooms '("ops" "ops-notifications" "outages" "release")
    "List of hipchat rooms to auto-join")

  (dolist (muc-room
           (mapcar (lambda (room)
                     (concat hipchat-number "_" room "@conf.hipchat.com"))
                   hipchat-rooms))
    (add-to-list 'jabber-muc-autojoin muc-room)
    (add-to-list 'jabber-muc-default-nicknames  `(,muc-room . ,hipchat-nickname)))

  (defun hipchat-join (room)
    (interactive "sRoom name: ")
    (jabber-muc-join
     (jabber-read-account)
     (concat hipchat-number "_" room "@conf.hipchat.com")
     hipchat-nickname
     t)))

json-mode

Terraform state files are JSON.

(use-package json-mode
  :defer t
  :mode ("\\.tfstate\\'" "\\.tfstate\\.backup\\'")
  :config
  ;; Two-space indentation for JSON (default if 4)
  (setq json-reformat:indent-width 2)
  (add-hook 'json-mode-hook
            (lambda ()
              (make-local-variable 'js-indent-level)
              (setq js-indent-level 2))))

kubernetes

(use-package kubernetes
  :defer t
  :commands (kubernetes-use-context))

ledger-mode

(use-package ledger-mode
  :defer t)

lisp-mode

(use-package lisp-mode
  :ensure nil
  :config
  (add-hook 'emacs-lisp-mode-hook
            (lambda ()
              (turn-on-eldoc-mode))))

lua-mode

(use-package lua-mode
  :defer t)

magit

(use-package magit
  :bind (("C-c m" . magit-dispatch-popup))
  :init
  ;; We have global-auto-revert mode enabled
  (setq magit-auto-revert-mode nil)
  :config
  (setq magit-completing-read-function 'ivy-completing-read
        magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1
        magit-repository-directories '("~/src")
        magit-save-repository-buffers 'dontask)

  (if (< emacs-major-version 26)
      ;; See https://github.com/magit/magit/issues/2265
      ;; and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847
      (when (eq window-system 'ns) (setq magit-revision-use-gravatar-kludge t)))

  (add-hook 'after-save-hook #'magit-after-save-refresh-status))

markdown-mode

(use-package markdown-mode
  :defer t
  :mode (("README\\.md\\'" . gfm-mode)
         ("CHANGELOG\\.md\\'" . markdown-mode)))

message

(use-package message
  :ensure nil
  :defer t
  :config
  ;; Internal SMTP library
  (setq message-send-mail-function 'smtpmail-send-it
        smtpmail-smtp-server "smtp.fastmail.com"
        smtpmail-smtp-service 587)

  ;; OR

  ;; Use MSMTP with auto-smtp selection
  ;; http://www.emacswiki.org/emacs/GnusMSMTP#toc3
  ;;
  (setq sendmail-program "/usr/bin/msmtp"
        mail-specify-envelope-from t
        mail-envelope-from 'header
        message-sendmail-envelope-from 'header)

  ;; Enable notmuch-address completion
  ;; (notmuch-address-message-insinuate)

  ;; Enable gnus-alias
  (add-hook 'message-setup-hook #'gnus-alias-determine-identity)
  (define-key message-mode-map (kbd "C-c C-p") 'gnus-alias-select-identity))

monokai-theme

(use-package monokai-theme
  :defer t)

nginx-mode

(use-package nginx-mode
  :defer t)

nim-mode

(use-package nim-mode
  :defer t)

nix-mode

(use-package nix-mode
  :defer t)

nlinum

(use-package nlinum
  :if (< emacs-major-version 26))

notmuch

(use-package notmuch
  :defer t
  :config
  ;; notmuch-always-prompt-for-sender requires ido-mode
  ;; Add (ido-mode t) to emacs configuration
  (setq notmuch-always-prompt-for-sender t)

  ;; Use Bcc instead of Fcc
  (setq notmuch-fcc-dirs nil)

  (setq notmuch-saved-searches '(("Personal Inbox" . "tag:inbox and not tag:uw and (not tag:lists or (tag:lists::wallop_2012 or tag:lists::cheastyboys))")
                                 ("UW Inbox" . "tag:inbox and tag:uw and (not tag:lists or (tag:lists::cirg-adm or tag:lists::cirg-adm-alerts or tag:lists::cirg-core tag:lists::kenyaemr-developers)) and not (from:root or (tag:nagios and not tag:lists))")
                                 ("Action" . "tag:action")
                                 ("Waiting" . "tag:waiting")
                                 ("Secondary Lists" . "tag:inbox and (tag:lists::notmuch or tag:lists::vcs-home or tag:lists::techsupport)")
                                 ("Debian Security Inbox" . "tag:inbox and tag:lists::debian-security-announce")))

  ;; Show newest mail first
  (setq notmuch-search-oldest-first nil)

  ;; ;; Notmuch remote setup (on all hosts except garnet)
  ;; (when (not (string= system-name "garnet.ciffer.net"))
  ;;   (setq notmuch-command "notmuch-remote"))

  ;; Getting Things Done (GTD) keybindings

  (setq notmuch-tag-macro-alist
        (list
         '("a" "+action" "-waiting" "-inbox")
         '("w" "-action" "+waiting" "-inbox")
         '("d" "-action" "-waiting" "-inbox")))

  (defun notmuch-search-apply-tag-macro (key)
    (interactive "k")
    (let ((macro (assoc key notmuch-tag-macro-alist)))
      (notmuch-search-tag (cdr macro))))

  (defun notmuch-show-apply-tag-macro (key)
    (interactive "k")
    (let ((macro (assoc key notmuch-tag-macro-alist)))
      (notmuch-show-tag (cdr macro))))

  (define-key notmuch-search-mode-map "`" 'notmuch-search-apply-tag-macro)
  (define-key notmuch-show-mode-map "`" 'notmuch-show-apply-tag-macro))

nov

EPUB reader package.

(use-package nov
  :mode ("\\.epub\\'" . nov-mode)
  :config
  (setq nov-save-place-file (expand-file-name "nov-save-place" user-emacs-directory)))

ob-go

Requires cargo-script.

package main

import "fmt"

func main() {
	fmt.Println("Hello, world")
}
(use-package ob-go)

ob-rust

Requires cargo-script.

cargo install cargo-script
fn main() {
    for count in 0..3 {
        println!("{}. Hello World!", count);
    }
}
(use-package ob-rust)

operate-on-number

(use-package operate-on-number
  :defer t)

org

(use-package org
  :ensure nil
  :bind (("C-c c" . org-capture)
         ("C-c o a" . org-agenda)
         ("C-c o b" . org-iswitchb)
         ("C-c o l" . org-store-link))
  :config
  (add-hook 'org-mode-hook #'auto-fill-mode)
  (add-hook 'org-mode-hook #'org-babel-result-hide-all)

  (setq org-babel-python-command "python3"
        org-capture-templates  '(("t" "Task" entry (file "tasks.org")
                                  "* TODO %?\n   SCHEDULED: %T\n\n%a" :prepend t))
        org-ellipsis ""
        org-plantuml-jar-path (expand-file-name "~/.nix-profile/lib/plantuml.jar")
        org-refile-targets '((nil :maxlevel . 9))
        org-src-ask-before-returning-to-edit-buffer nil
        org-src-preserve-indentation t
        org-src-window-setup 'current-window
        org-startup-with-inline-images t
        org-use-speed-commands t)

  ;; Lower case all org template block headers
  (mapc (lambda (asc)
          (let ((org-sce-dc (downcase (nth 1 asc))))
            (setf (nth 1 asc) org-sce-dc)))
        org-structure-template-alist)

  (org-babel-do-load-languages
   'org-babel-load-languages
   '((calc . t)
     (emacs-lisp . t)
     (perl . t)
     (plantuml . t)
     (python . t)
     (ruby . t)
     (scala . t)
     (shell . t))))

org-capture

(use-package org-capture
  :ensure nil
  :bind (("C-c o c" . org-capture))
  :config
  (setq org-capture-templates
        '(("t" "Task" entry (file "tasks.org")
           "* TODO %?\n   SCHEDULED: %T\n\n%a" :prepend t))))

package-lint

(use-package package-lint
  :defer t)

pass

(use-package pass
  :defer t)

password-store

(use-package password-store
  :defer t)

pdf-tools

brew install poppler
cd ~/.emacs.d/elpa/pdf-tools-*/build
zlib_CFLAGS=-I/usr/include zlib_LIBS='-L/usr/lib -lz' \
           PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig \
           make melpa-build
(use-package pdf-tools
  :init
  (pdf-tools-install)
  :config
  ;; pdf-view-auto-slice-minor-mode shows more of the main text, but looks
  ;; ugly because page margins are cut. Instead, run
  ;; pdf-view-set-slice-from-bounding-box (s b).
  ;; (add3-to-list 'pdf-tools-enabled-modes 'pdf-view-auto-slice-minor-mode)
  (add-hook 'pdf-view-mode-hook #'pdf-view-fit-page-to-window))

plantuml-mode

(use-package plantuml-mode
  :config
  (setq plantuml-jar-path "/usr/local/opt/plantuml/libexec/plantuml.jar"))

projectile

(use-package projectile
  :init (projectile-mode)
  :config
  ;; Patch to fix https://github.com/bbatsov/projectile/issues/1171
  (defun projectile-project-root ()
    "Retrieves the root directory of a project if available.
The current directory is assumed to be the project's root otherwise."
    ;; the cached value will be 'none in the case of no project root (this is to
    ;; ensure it is not reevaluated each time when not inside a project) so use
    ;; cl-subst to replace this 'none value with nil so a nil value is used
    ;; instead
    (or (cl-subst nil 'none
                  (or (and projectile-cached-buffer-file-name
                           (equal projectile-cached-buffer-file-name buffer-file-name)
                           projectile-cached-project-root)
                      (progn
                        (setq projectile-cached-buffer-file-name buffer-file-name)
                        (setq projectile-cached-project-root
                              ;; The `is-local' and `is-connected' variables are
                              ;; used to fix the behavior where Emacs hangs
                              ;; because of Projectile when you open a file over
                              ;; TRAMP. It basically prevents Projectile from
                              ;; trying to find information about files for which
                              ;; it's not possible to get that information right
                              ;; now.
                              (or (let* ((dir default-directory)
                                         (is-local (not (file-remote-p dir)))      ;; `true' if the file is local
                                         (is-connected (file-remote-p dir nil t))) ;; `true' if the file is remote AND we are connected to the remote
                                    (when (or is-local is-connected)
                                      (cl-some
                                       (lambda (func)
                                         (let* ((cache-key (format "%s-%s" func dir))
                                                (cache-value (gethash cache-key projectile-project-root-cache)))
                                           (if (and cache-value (file-exists-p cache-value))
                                               cache-value
                                             (let ((value (funcall func (file-truename dir))))
                                               (puthash cache-key value projectile-project-root-cache)
                                               value))))
                                       projectile-project-root-files-functions)))
                                  ;; set cached to none so is non-nil so we don't try
                                  ;; and look it up again
                                  'none)))))
        (if projectile-require-project-root
            (error "You're not in a project")
          default-directory)))

  (defun projectile-project-name ()
    "Return project name."
    (or projectile-project-name
        (and projectile-cached-buffer-file-name
             (equal projectile-cached-buffer-file-name buffer-file-name)
             projectile-cached-project-name)
        (progn
          (setq projectile-cached-buffer-file-name buffer-file-name)
          (setq projectile-cached-project-name
                (let ((project-root
                       (condition-case nil
                           (projectile-project-root)
                         (error nil))))
                  (if project-root
                      (funcall projectile-project-name-function project-root)
                    "-"))))))

  ;; Mark projectile variables as safe
  (seq-doseq (var '(projectile-project-compilation-cmd
                    projectile-project-test-cmd
                    projectile-project-run-cmd))
    (put var 'safe-local-variable #'stringp))

  (setq projectile-completion-system 'ivy)
  ;; Work around
  ;; https://github.com/bbatsov/projectile/issues/1183
  (setq projectile-mode-line
        '(:eval (format " Projectile[%s]"
                        (projectile-project-name))))
  (setq projectile-use-git-grep t)
  (add-to-list 'projectile-project-root-files ".kitchen.yml")
  (projectile-cleanup-known-projects))

python

Associate Nagios check-mk files with python.

(use-package python
  :mode
  (("\\.mk\\'" . python-mode))
  :config
  ;; PEP 8 compliant filling rules, 79 chars maximum
  (add-hook 'python-mode-hook (lambda () (setq fill-column 79))))

quickrun

Increase timeout to 60 seconds from the default of 10 seconds.

(use-package quickrun
  :bind (("C-c q a" . quickrun-with-arg)
         ("C-c q q" . quickrun)
         ("C-c q r" . quickrun-region)
         ("C-c q s" . quickrun-shell))
  :config
  (setq quickrun-timeout-seconds 60))

racer

(use-package racer
  :config
  (add-hook 'rust-mode-hook #'racer-mode)
  (add-hook 'racer-mode-hook #'eldoc-mode)
  (add-hook 'racer-mode-hook #'company-mode)
  ;; (global-set-key (kbd "TAB") #'company-indent-or-complete-common)
  ;; (setq company-tooltip-align-annotations t)
  )

recentf

(use-package recentf
  :ensure nil
  :init (recentf-mode 1)
  :config
  ;; Increase size of recent file list
  (setq recentf-max-saved-items 1000)

  ;; Ignore temporary notmuch ical files
  (add-to-list 'recentf-exclude "^/tmp/notmuch-ical"))

restclient

(use-package restclient
  :defer t)

robe

(use-package robe
  :config
  (add-hook 'ruby-mode-hook #'robe-mode))

ruby-mode

Ruby auto-modes. These are from prelude.

(use-package ruby-mode
  :mode
  (("\\.rake\\'" . ruby-mode)
   ("Rakefile\\'" . ruby-mode)
   ("\\.gemspec\\'" . ruby-mode)
   ("\\.ru\\'" . ruby-mode)
   ("Gemfile\\'" . ruby-mode)
   ("Guardfile\\'" . ruby-mode)
   ("Capfile\\'" . ruby-mode)
   ("\\.thor\\'" . ruby-mode)
   ("\\.rabl\\'" . ruby-mode)
   ("Thorfile\\'" . ruby-mode)
   ("Vagrantfile\\'" . ruby-mode)
   ("\\.jbuilder\\'" . ruby-mode)
   ("Podfile\\'" . ruby-mode)
   ("\\.podspec\\'" . ruby-mode)
   ("Puppetfile\\'" . ruby-mode)
   ("Berksfile\\'" . ruby-mode)
   ("Appraisals\\'" . ruby-mode))
  :config
  (defun my-ruby-mode-defaults ()
    (inf-ruby-minor-mode +1)
    (ruby-tools-mode +1)
    ;; CamelCase aware editing operations
    (subword-mode +1))
  (add-hook 'ruby-mode-hook #'my-ruby-mode-defaults))

ruby-tools

(use-package ruby-tools
  :defer t)

rust-mode

(use-package rust-mode
  :defer t
  :config (setq rust-format-on-save t))

savehist

(use-package savehist
  :ensure nil
  :init (savehist-mode 1))

saveplace

(use-package saveplace
  :ensure nil
  :init (save-place-mode))

scala-mode2

Scala worksheets end in .sc.

(use-package scala-mode
  :mode
  (("\\.sc\\'" . scala-mode))
  :config
  (defun my-scala-mode-defaults ()
    (subword-mode +1))
  (add-hook 'scala-mode-hook #'my-scala-mode-defaults))

server

Start Emacs server unless one is already running. server-running-p requires server.

(use-package server
  :ensure nil
  :config
  (unless (server-running-p)
    (server-start)))

sh-script

(use-package sh-script
  :ensure nil
  :defer t
  :config
  (defun my-setup-sh-mode ()
    "My preferences for sh-mode"
    (setq sh-basic-offset 2)
    (setq sh-indent-after-continuation 'always)
    (setq sh-indent-for-case-alt '+)
    (setq sh-indent-for-case-label 0))

  (add-hook 'sh-mode-hook #'my-setup-sh-mode))

shell

See http://stackoverflow.com/a/11255996

(defun shell-mode-config ()
  ;; company-mode
  ;;
  ;; Disable idle completion
  (setq-local company-idle-delay nil)
  ;; Tab to complete. Use company-complete-common instead of
  ;; company-manual-begin to complete on tab.
  (define-key shell-mode-map (kbd "TAB") #'company-complete-common)

  ;; Do not store duplicate history entries
  (setq comint-input-ignoredups t))
(use-package shell
  :ensure nil
  :config
  (add-to-list 'display-buffer-alist
               '("^\\*shell\\*" . ((display-buffer-reuse-window display-buffer-same-window))))
  (setq explicit-shell-file-name "bash")
  ;; Do not try to colorize comments and strings in shell mode
  (setq shell-font-lock-keywords nil)
  ;; This seems to be slowing down shell buffers
  ;; (remove-hook 'shell-mode-hook 'goto-address-mode)
  (add-hook 'shell-mode-hook #'shell-mode-config))

To disable scroll to bottom:

(remove-hook 'comint-output-filter-functions
             'comint-postoutput-scroll-to-bottom)

Changing directory generates a message with the new directory path. To disable this:

(setq shell-dirtrack-verbose nil)

To search history when you are at a command line using C-r (instead of M-r):

(setq comint-history-isearch dwim)

slime

Slime Installation

(use-package slime
  :defer t
  :config
  (setq inferior-lisp-program "sbcl"))

smartparens

(use-package smartparens
  :init
  (smartparens-global-mode t)
  (require 'smartparens-config)
  (sp-use-paredit-bindings)
  ;; sp-paredit-bindings: ("M-r" . sp-splice-sexp-killing-around)
  (define-key sp-keymap (kbd "M-r") nil)
  (define-key sp-keymap (kbd "M-s") nil)
  ;; sp-smartparens-bindings: ("M-<backspace>" . sp-backward-unwrap-sexp)
  (define-key sp-keymap (kbd "M-<backspace>") nil))

smtpmail-multi

(use-package smtpmail-multi
  :defer t)

solarized-theme

(use-package solarized-theme
  :defer t)

swiper

(use-package swiper
  :bind (("C-c s" . swiper)))

tango-plus-theme

(use-package tango-plus-theme
  :init (load-theme 'tango-plus t))

term

(defun my-setup-term-mode ()
  "My preferences for term mode"
  ;; Settings recommended in term.el
  ;;
  ;; http://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/term.el?id=c720ef1329232c76d14a0c39daa00e37279aa818#n179
  (make-local-variable 'mouse-yank-at-point)
  (setq mouse-yank-at-point t)
  ;; End of recommended settings

  ;; Make term mode more term-like

  (define-key term-raw-map (kbd "<C-backspace>") 'term-send-raw)
  (define-key term-raw-map (kbd "<C-S-backspace>") 'term-send-raw)

  ;; Toogle between line and char mode in term-mode
  (define-key term-raw-map (kbd "C-'") 'term-line-mode)
  (define-key term-mode-map (kbd "C-'") 'term-char-mode)

  ;; Enable Emacs key bindings in term mode
  (define-key term-raw-map (kbd "M-!") nil)
  (define-key term-raw-map (kbd "M-&") nil)
  (define-key term-raw-map (kbd "M-:") nil)
  (define-key term-raw-map (kbd "M-x") nil)

  ;; Paste key bindings for Mac keyboards with no insert
  (define-key term-raw-map (kbd "C-c y") 'term-paste)
  (define-key term-raw-map (kbd "s-v") 'term-paste)

  ;; Enable address links in term mode
  (goto-address-mode))

(use-package term
  :ensure nil
  :config
  (setq-default term-buffer-maximum-size 10000)
  (add-hook 'term-mode-hook #'my-setup-term-mode))

terraform-mode

(use-package terraform-mode
  :defer t)

toml-mode

(use-package toml-mode
  :defer t
  :mode
  (("Cargo\\.lock\\'" . toml-mode)))

tramp

Edit remote files via sudo

See http://www.gnu.org/software/emacs/manual/html_node/tramp/Ad_002dhoc-multi_002dhops.html

/ssh:example.com|sudo::/file

Use SSH default control master settings. Add the following to ~/.ssh/config.

ControlMaster auto
ControlPath ~/.ssh/control.%h_%p_%r
ControlPersist 60m
(use-package tramp
  :ensure nil
  :defer t
  :config
  ;; Frequently Asked Questions: How could I speed up tramp?
  ;; https://www.gnu.org/software/emacs/manual/html_node/tramp/Frequently-Asked-Questions.html
  (setq vc-ignore-dir-regexp
        (format "\\(%s\\)\\|\\(%s\\)"
                vc-ignore-dir-regexp
                tramp-file-name-regexp))

  (setq tramp-use-ssh-controlmaster-options nil
        ;; Tramp sets HISTFILE so bash history on remote shells does not work.
        tramp-histfile-override nil))

Default value of explicit-bash-args is ("--noediting" "-i"). We want login shell for remote hosts. This should be harmless for local shells, however it does increase the start-up time for local shells.

Attempt to start or reattach to a dtach session and fall back to a bash shell.

(setq explicit-bash-args
      '("-c" "dtach -A \"$HOME/.dtach-$(hostname -f 2>/dev/null || hostname)-ssorensen\" -z bash --noediting --login -i 2>/dev/null || bash --noediting --login -i"))
(require 'tramp)

(defun ssh-host-completing-read ()
  (completing-read
   "Open ssh connection to [user@]host: "
   (completion-table-dynamic
    (lambda (str)
      (tramp-completion-handle-file-name-all-completions str "/")))))

(defun ssh-shell-2 (host)
  "Open SSH connection to HOST."
  (interactive "f")
  (let ((default-directory host))
    ;; Opening the shell occasionally hangs and locks up Emacs. Opening a remote
    ;; file first seems to fix this.
    ;;
    ;; Cannot read shell history file when using with-current-buffer.
    (find-file-noselect default-directory)
    (shell (format "*shell*<%s>" host))))

(defun ssh-shell (host)
  "Open SSH connection to HOST."
  (interactive (list (ssh-host-completing-read)))
  (let* ((host (if (string-suffix-p ":" host)
                   host
                 (format  "%s:" host)))
         (default-directory (format  "/ssh:%s" host)))
    ;; Opening the shell occasionally hangs and locks up Emacs. Opening a remote
    ;; file first seems to fix this.
    ;;
    ;; Cannot read shell history file when using with-current-buffer.
    (find-file-noselect default-directory)
    (shell (format "*shell*<%s>" host))))

(defun dtach-shell (socket)
  "Attach to specified dtach SOCKET or create it if it does not exist"
  (interactive "F")
  (let ((explicit-shell-file-name "dtach")
        (explicit-dtach-args `("-A" ,socket "-z" "bash" "--noediting" "--login" "-i")))
    (shell (format "*dtach*<%s>" socket))))
(defun tramp-comint-read-input-ring ()
  "Read remote bash_history file into comint input ring."
  (when (tramp-tramp-file-p default-directory)
    (tramp-set-comint-input-ring-file)
    (when (ring-empty-p comint-input-ring)
      (comint-read-input-ring t))))

(defun tramp-set-comint-input-ring-file ()
  "Set the name of the remote comint-input-ring-file."
  (when (tramp-tramp-file-p default-directory)
    (setq comint-input-ring-file-name (format "%s~/.bash_history" default-directory))))

(add-hook 'shell-mode-hook #'tramp-set-comint-input-ring-file)
(add-hook 'shell-mode-hook #'tramp-comint-read-input-ring)

visual-fill-column

(use-package visual-fill-column
  :init
  (dolist (hook '(visual-line-mode-hook
                  compilation-mode-hook
                  comint-mode-hook
                  conf-mode-hook
                  custom-mode-hook
                  dired-mode-hook
                  gnus-article-mode-hook
                  gnus-group-mode-hook
                  gnus-summary-mode-hook
                  Info-mode-hook
                  package-menu-mode-hook
                  prog-mode-hook
                  special-mode-hook
                  text-mode-hook))
    (add-hook hook #'visual-fill-column-mode))
  :config
  (setq-default visual-fill-column-center-text t
                visual-fill-column-fringes-outside-margins nil
                visual-fill-column-width 100)
  (setq split-window-preferred-function #'visual-fill-column-split-window-sensibly))

winner

The winner-mode package provides a way to restore previous window layouts.

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

yaml-mode

(use-package yaml-mode
  :defer t
  :config
  (defconst yaml-outline-regex
    (concat "\\( *\\)\\(?:\\(?:--- \\)?\\|{\\|\\(?:[-,] +\\)+\\) *"
            "\\(?:" yaml-tag-re " +\\)?"
            "\\(" yaml-bare-scalar-re "\\) *:"
            "\\(?: +\\|$\\)")
    "Regexp matching a single YAML hash key. This is adds a
    capture group to `yaml-hash-key-re' for the
    indentation.")

  (defun yaml-outline-level ()
    "Return the depth to which a statement is nested in the outline."
    (- (match-end 1) (match-beginning 1)))

  (defun my-yaml-mode-hook()
    (outline-minor-mode)
    (define-key yaml-mode-map (kbd "<backtab>") 'outline-toggle-children)
    (setq-local outline-regexp yaml-outline-regex)
    (setq-local outline-level #'yaml-outline-level))

  (add-hook 'yaml-mode-hook #'my-yaml-mode-hook))

yasnippet

(use-package yasnippet
  :init
  (yas-global-mode))

zoom-frm

The zoom-frm package allows scaling all text. (As opposed to text-scale-adjust, which only scales the text for a single buffer. Both are useful.)

(use-package zoom-frm
  :bind (("C-c C-+" . zoom-in/out)
         ("C-c C--" . zoom-in/out)
         ("C-c C-0" . zoom-in/out)
         ("C-c C-=" . zoom-in/out)))

External config

Load load config stored outside ~/.emacs.d.

(when (file-exists-p "~/.emacs.d/local.el")
  (load-file "~/.emacs.d/local.el"))
(load-file "~/.emacs.d/conf/ob-ansible-playbook.el")

Easy Customization

Save customization in conf/emacs-custom.el instead of init.el.

(setq custom-file "~/.emacs.d/conf/emacs-custom.el")
(load custom-file)

Full screen

(toggle-frame-fullscreen)