Wolfe's Literate Emacs Config

Table of Contents

1 About

Build Status

This literate config is best read here or in emacs. This page is generated and kept up to date using a combination of travis ci and ReadTheOrg. If you want to see the script that travis uses here is the bash script it runs and this is the .el file that it runs through emacs to generate the html page (this was mostly stolen from IvanMalison).

Included in this section is also my export headers. These are responsible for including the ReadTheOrg theme as well as some metadata and options like title, author, table of contents etc. If you wish to see the headers I'm using, this is the raw org file.

Right off the bat we want these libraries but they don't really belong anywhere else. So here they are.

(use-package dash)
(use-package s)

2 Variables

Variables come at the beginning so that they're consistently available. If you don't care about these click here to skip over them.

2.1 Config Name

(defvar wolfe/literate-config-name "README.org"
  "The name of my literate config")

2.2 Init File

(defvar wolfe/init-file (concat user-emacs-directory wolfe/literate-config-name)
  "The path to my literate config file")

2.3 Linux Check

(defvar wolfe/linux? (eq system-type 'gnu/linux)
  "Are we on linux?")

2.4 Windows Check

(defvar wolfe/windows? (eq system-type 'windows-nt)
    "Are we on windows?")

2.5 Org Ellipsis

(defvar wolfe/org-ellipsis "⤵"
  "The indicates if an `org-mode' tree can be expanded")

2.6 Project Path

(defvar wolfe/project-path
  (cond
   (wolfe/linux? "~/Projects/")
   (wolfe/windows? "C:/dev/")
   (:else nil))
  "Path to my projects directory")

2.7 Dropbox Path

(defvar wolfe/org-dropbox-path
  (cond
   (wolfe/linux?
    "~/Dropbox/org/")
   (wolfe/windows?
    (concat "C:\\Users\\" (getenv "USERNAME") "\\Dropbox\\org\\"))
   (:else nil))
  "Path to my org files inside dropbox")

2.8 Theme Checks

(defvar wolfe/using-dark t
  "Indicates whether we're using my dark theme")
(defvar wolfe/using-light nil
  "Indicates whether we're using my light theme")

2.9 Lisp Path Location

(defvar wolfe/lisp-dir-path "~/.emacs.d/lisp/"
  "Path to my custom lisp files")

2.10 Highlight Escapes Modes

(defvar wolfe/highlight-escapes-mode-list '(python-mode
                                            c-mode
                                            c++-mode
                                            web-mode)
  "List of modes to highlight escape characters in")

2.11 IRC Info Path

(defvar wolfe/irc-info-path "~/.ircinfo.gpg"
  "Location of the GPG encrypted file that has my irc login info")

3 Startup

My graphical settings change depending on whether I'm in terminal and if a command line flag (-light) was specified.

3.1 WM

Start load emacs window manager config if it exists.

(when (file-exists-p "~/.exwm.org")
  (org-babel-load-file "~/.exwm.org"))

3.2 Theme Setup

This should be run regardless of whether I'm in terminal vs gui or dark vs light.

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

(defun check-and-remove-command-line-arg (argument)
  "Checks `command-line-args' for argument and removes it if found returning t or nil"
  (if (member argument command-line-args)
      (progn
        (setq command-line-args (delete argument command-line-args))
        t)
    nil))

(let ((result (check-and-remove-command-line-arg "-light")))
  (setq wolfe/using-light result)
  (setq wolfe/using-dark (not result)))

This checks which setup we're in and calls the appropriate function above.

(defun hook-if-daemonp (func)
  (if (daemonp)
      (add-hook 'after-make-frame-functions
                (lambda (frame)
                  (with-selected-frame frame
                    (funcall func))))
    (funcall func)))

3.3 Dark

Configuration for my dark theme base16 default dark which is loaded by default.

(defun wolfe/dark-setup ()
  (use-package base16-theme
    :config
    (load-theme 'base16-default-dark t)
    (defvar my/base16-colors base16-default-dark-colors)
    (setq evil-emacs-state-cursor   `(,(plist-get my/base16-colors :base0D) box)
          evil-insert-state-cursor  `(,(plist-get my/base16-colors :base0D) bar)
          evil-motion-state-cursor  `(,(plist-get my/base16-colors :base0E) box)
          evil-normal-state-cursor  `(,(plist-get my/base16-colors :base07) box)
          evil-replace-state-cursor `(,(plist-get my/base16-colors :base08) bar)
          evil-visual-state-cursor  `(,(plist-get my/base16-colors :base09) box)))

  (eval-after-load 'ivy (lambda () (setq ivy-switch-buffer-faces-alist '((dired-mode . ivy-subdir)))))
  (hook-if-daemonp (lambda () (set-face-attribute 'fringe nil :background nil)))

  (custom-set-faces
   '(org-block-begin-line      ((t (:inherit (org-meta-line) :height 0.7))))
   '(org-block-end-line        ((t (:inherit (org-meta-line) :height 0.7))))
   '(region ((t (:background "gray19"))))
   '(org-block ((t (:foreground "#d8d8d8"))))
   '(org-done ((t (:box (:line-width 1) :weight bold))))
   '(org-level-1 ((t (:inherit outline-1 :height 1.3))))
   '(org-todo ((t (:box (:line-width 1) :weight bold))))))

3.4 Light

Configuration for my light theme leuven. This is only loaded when the -light flag is specified on the command line.

(defun wolfe/light-setup ()
  (use-package leuven-theme
    :config
    (custom-set-faces
     '(ivy-subdir ((t (:background "gray88")))))
    (load-theme 'leuven t)))

3.5 Display check

(if wolfe/using-light
    (wolfe/light-setup)
  (wolfe/dark-setup))

4 General Settings

Basic settings I can't really live without.

4.1 Load Path

Recursively add ~/.emacs.d/lisp/ to my load path.

(add-to-list 'load-path wolfe/lisp-dir-path)
(let ((default-directory wolfe/lisp-dir-path))
  (normal-top-level-add-subdirs-to-load-path))

4.2 Splash and Startup

This makes sure I'm presented with a nice blank *scratch* buffer when emacs starts up.

(setq inhibit-splash-screen t
      inhibit-startup-message t
      initial-scratch-message "") ; No scratch text
(defun display-startup-echo-area-message ()
  (message "Welcome to the church of GNU/Emacs"))

4.3 Graphics

4.3.1 Bars

I don't really want to have to look at menu bars that I'm not going to use

(hook-if-daemonp
 (lambda ()
  (tool-bar-mode -1) ; No toolbar
  (scroll-bar-mode -1) ; Hide scrollbars
  (menu-bar-mode -1))) ; No menubar

4.3.2 Fonts

I used Inconsolata-dz for quite a long time but have recently been using Fira Mono.

(let* ((font "Fira Mono")
       (size 15)
       (font-size (format "%s-%s" font size)))
  (setq default-frame-alist `((font . ,font-size)))
  (set-face-attribute 'default t :font font-size))

Force Fira Code for all UTF-8 symbols.

(hook-if-daemonp
 (lambda ()
  (when (display-graphic-p)
    (let ((utf8-font "Fira Code"))
      (set-fontset-font "fontset-startup" '(#x000000 . #x3FFFFF) utf8-font)
      (set-fontset-font "fontset-default" '(#x000000 . #x3FFFFF) utf8-font)
      (set-fontset-font "fontset-standard" '(#x000000 . #x3FFFFF) utf8-font)))))

Make sure that UTF-8 is used everywhere.

(set-terminal-coding-system  'utf-8)
(set-keyboard-coding-system  'utf-8)
(set-language-environment    'utf-8)
(set-selection-coding-system 'utf-8)
(setq locale-coding-system   'utf-8)
(prefer-coding-system        'utf-8)
(set-input-method nil)

4.3.3 Pretty Symbols

In emacs 24.4 we got prettify-symbols-mode which replaces things like lambda with λ. This can help make the code easier to read. The inhibit-compacting-font-caches stops garbage collect from trying to handle font caches which makes things a lot faster and saves us ram.

(setq prettify-symbols-unprettify-at-point 'right-edge)
(setq inhibit-compacting-font-caches t)
4.3.3.1 Global

These symbols are the basics that I would like enabled for all prog-mode modes. This function can be called by the mode specific hook to push the defaults.

(defun wolfe/pretty-symbol-push-default ()
  (push '("!=" . ?≠) prettify-symbols-alist)
  (push '("<=" . ?≤) prettify-symbols-alist)
  (push '(">=" . ?≥) prettify-symbols-alist)
  (push '("=>" . ?⇒) prettify-symbols-alist))

Now apply the default to some modes I don't want anything special in.

(mapc
 (lambda (hook)
   (add-hook 'hook (lambda () (wolfe/pretty-symbol-push-default))))
 '(c-mode))
4.3.3.2 Python
(add-hook 'python-mode-hook
          (lambda ()
            (wolfe/pretty-symbol-push-default)
            (push '("def"    . ?ƒ) prettify-symbols-alist)
            (push '("sum"    . ?Σ) prettify-symbols-alist)
            (push '("**2"    . ?²) prettify-symbols-alist)
            (push '("**3"    . ?³) prettify-symbols-alist)
            (push '("None"   . ?∅) prettify-symbols-alist)
            (push '("in"     . ?∈) prettify-symbols-alist)
            (push '("not in" . ?∉) prettify-symbols-alist)
            (push '("return" . ?➡) prettify-symbols-alist)
            (prettify-symbols-mode t)))
4.3.3.3 Lisp
(add-hook 'emacs-lisp-mode-hook
          (lambda ()
            (wolfe/pretty-symbol-push-default)
            (push '("defun"    . ?ƒ) prettify-symbols-alist)
            (push '("defmacro" . ?μ) prettify-symbols-alist)
            (push '("defvar"   . ?ν) prettify-symbols-alist)
            (prettify-symbols-mode t)))
4.3.3.4 Go
(add-hook 'go-mode-hook
          (lambda ()
            (wolfe/pretty-symbol-push-default)
            (push '("func"    . ?ƒ) prettify-symbols-alist)
            (push '(":="    . ?←) prettify-symbols-alist)
            (prettify-symbols-mode t)))

4.3.4 Column Marker

(use-package column-marker
  :ensure nil
  :config
  (add-hook 'prog-mode-hook (lambda () (interactive) (column-marker-1 81)))
  (custom-set-faces
   '(column-marker-1 ((t (:background "dim gray"))))))

4.3.5 Highlight Escape Characters

This defines 4 new faces and the appropriate regexps that highlight them and maps them to all the modes in wolfe/highlight-escapes-mode-list.

(defface wolfe/backslash-escape-backslash-face
  '((t :inherit font-lock-regexp-grouping-backslash))
  "Face for the back-slash component of a back-slash escape."
  :group 'font-lock-faces)

(defface wolfe/backslash-escape-char-face
  '((t :inherit font-lock-regexp-grouping-construct))
  "Face for the charcter component of a back-slash escape."
  :group 'font-lock-faces)

(defface wolfe/format-code-format-face
  '((t :inherit font-lock-regexp-grouping-backslash))
  "Face for the % component of a printf format code."
  :group 'font-lock-faces)

(defface wolfe/format-code-directive-face
  '((t :inherit font-lock-regexp-grouping-construct))
  "Face for the directive component of a printf format code."
  :group 'font-lock-faces)

(mapc
 (lambda (mode)
   (font-lock-add-keywords
    mode
    '(("\\(\\\\\\)." 1 'wolfe/backslash-escape-backslash-face prepend)
      ("\\\\\\(.\\)" 1 'wolfe/backslash-escape-char-face      prepend)
      ("\\(%\\)."    1 'wolfe/format-code-format-face         prepend)
      ("%\\(.\\)"    1 'wolfe/format-code-directive-face      prepend))))
 wolfe/highlight-escapes-mode-list)

4.3.6 Highlight Todo, Fixme & Bug

(add-hook 'prog-mode-hook
               (lambda ()
                (font-lock-add-keywords nil
                 '(("\\<\\(FIXME\\|TODO\\|BUG\\|XXX\\)" 1 font-lock-warning-face t)))))

4.4 Personal Defaults

Nothing to crazy here just the type of behaviour I personally expect as default.

(show-paren-mode t) ; Highlights matching parens
(fset 'yes-or-no-p 'y-or-n-p) ; y/n instead of yes/no
(blink-cursor-mode -1) ; No need to flash the cursor
(column-number-mode t) ; Show column in mode-line
(delete-selection-mode 1) ; Replace selection on insert
(setq-default truncate-lines t ; Don't wrap
              indent-tabs-mode nil)
(setq vc-follow-symlinks t ; Always follow symlinks
      tags-revert-without-query t ; Don't ask to reload TAGS file
      echo-keystrokes 0.5
      custom-file "~/.emacs.d/custom.el" ; Set custom file and don't load it
      source-directory "~/Projects/emacs/")

4.5 Misc

4.5.1 Vim Scrolloff

This makes scrolling gradual rather than by half page. I find that the half page scroll really makes me lose where I am in the file so here I make sure to scroll one line at a time. In addition I want to keep what I'm working on centered so I start scrolling when the cursor is 10 lines away from the margin.

This behaviour in general emulates the scrolloff option in vim.

(setq scroll-margin 10
      scroll-step 1
      scroll-conservatively 10000
      scroll-preserve-screen-position 1)

4.5.2 Shell Tweaks

(setq explicit-shell-file-name
      (if (file-readable-p "/usr/bin/zsh") "/usr/bin/zsh" "/bin/bash"))
(when (eq system-type 'windows-nt)
  (setq explicit-shell-file-name "cmdproxy.exe"))

4.5.3 Spell Check

(when wolfe/windows?
  (setq ispell-program-name "c:/emacs/hunspell/bin/hunspell.exe"))

4.5.4 Help & Compilation

Keep the output scrolling as it compiles.

(require 'compile)
(setq compilation-scroll-output t)

q should really quit the buffer not just stick it at the bottom.

(dolist (m (list help-mode-map compilation-mode-map))
  (bind-key (kbd "q") (lambda () (interactive) (quit-window t)) m))

4.6 Mode Line

If we're in GUI emacs we make sure to use powerline otherwise we use a custom mode line configuration.

(if (or (display-graphic-p) (daemonp))
    (use-package powerline
      :config
      (setq powerline-arrow-shape 'curve
            powerline-display-buffer-size nil
            powerline-display-mule-info nil)
      (powerline-default-theme)
      (remove-hook 'focus-out-hook 'powerline-unset-selected-window)
      (setq powerline-height 24)
      (defpowerline powerline-minor-modes ""))

  (setq-default
   mode-line-format
   (list
    " "
    ;; is this buffer read-only?
    '(:eval (when buffer-read-only
              (propertize "RO"
                          'face 'font-lock-type-face
                          'help-echo "Buffer is read-only")))

    ;; was this buffer modified since the last save?
    '(:eval (when (buffer-modified-p)
              (propertize "M"
                          'face 'font-lock-warning-face
                          'help-echo "Buffer has been modified")))

    " "
    ;; the buffer name; the file name as a tool tip
    '(:eval (propertize "%b " 'face 'font-lock-keyword-face
                        'help-echo (buffer-file-name)))


    ;; the current major mode for the buffer.
    "["

    '(:eval (propertize (format-mode-line mode-name) 'face '(:family "Arial")
                        'help-echo buffer-file-coding-system))
    '(:eval (propertize (format-mode-line minor-mode-alist)
                        'face '(:family "Arial")))
    "]             "

    ;; line and column
    "(" ;; '%02' to set to 2 chars at least; prevents flickering
    (propertize "%02l" 'face 'font-lock-type-face) ","
    (propertize "%02c" 'face 'font-lock-type-face)
    ") "

    ;; relative position, size of file
    "["
    (propertize "%p" 'face 'font-lock-constant-face) ;; % above top
    "/"
    (propertize "%I" 'face 'font-lock-constant-face) ;; size
    "] "

    ;; add the time, with the date and the emacs uptime in the tooltip
    '(:eval (propertize (format-time-string "%H:%M")
                        'help-echo
                        (concat (format-time-string "%c; ")
                                (emacs-uptime "Uptime:%hh")))))))

4.7 Line Numbers

Vim-like relative line numbering. If we're on the latest versions of emacs (i.e. 26.0.50 or higher) then we should use the native line numbering otherwise we fall back to nlinum-relative.

(if (version< "26.0.50" emacs-version)
    (progn
      (add-hook 'prog-mode-hook (lambda ()
                                  (display-line-numbers-mode t)
                                  (setq display-line-numbers 'relative))))
  (progn
    (use-package nlinum-relative
      :config
      (nlinum-relative-setup-evil)
      (setq nlinum-relative-redisplay-delay 0.25)
      (setq nlinum-relative-current-symbol "")
      (add-hook 'prog-mode-hook 'nlinum-relative-mode))))

5 Functions

5.1 Face Under Point

Returns the font lock face that's under the cursor.

(defun what-face (pos)
  (interactive "d")
  (let ((face (or (get-char-property (point) 'read-face-name)
                  (get-char-property (point) 'face))))
    (if face (message "Face: %s" face) (message "No face at %d" pos))))

5.2 Compile Project

Compiles the project without a prompt.

(defun wolfe/compile-no-prompt ()
  (interactive)
  (let ((compilation-read-command nil))
    (compile (eval compile-command))))

5.3 Compile Dotfiles

Compiles all el files in the ~/.emacs.d directory.

(defun wolfe/compile-dot-emacs ()
  "Byte-compile dotfiles."
  (interactive)
  (byte-recompile-directory user-emacs-directory 0))
(defun wolfe/clear-all-elc ()
  (interactive)
  (shell-command "find ~/.emacs.d/ -name \"*.elc\" -type f -delete"))
(defun wolfe/remove-elc-on-save ()
  "If you're saving an emacs-lisp file, likely the .elc is no longer valid."
  (add-hook 'after-save-hook
            (lambda ()
              (if (file-exists-p (concat buffer-file-name "c"))
                  (delete-file (concat buffer-file-name "c"))))
            nil t))
(add-hook 'emacs-lisp-mode-hook 'wolfe/remove-elc-on-save)

5.4 Find Tags

Looks up tag under point.

(defun wolfe/find-tag ()
  "Jump to the tag at point without prompting"
  (interactive)
  (find-tag (find-tag-default)))
(defun wolfe/create-tags ()
  "Create the tags table"
  (interactive)
  (save-window-excursion (shell-command "etags -R -o ETAGS *")))
(defadvice xref-find-definitions (around refresh-etags activate)
  "Rerun etags and reload tags if tag not found and redo find-tag.
   If buffer is modified, ask about save before running etags."
  (condition-case err
      ad-do-it
    (error (and (buffer-modified-p) (not (ding))
                (save-buffer))
           (save-window-excursion (shell-command "etags -R *"))
           ad-do-it)))

5.5 Terminal Suspend

Fixes C-z in terminal.

(defun wolfe/controlz ()
  (interactive)
  (when (eq (display-graphic-p) nil)
    (suspend-frame)))

5.6 Dropbox

Utility functions for finding Dropbox directories/files.

(defun wolfe/org-open (name)
  "Opens the file in the dropbox path"
  (interactive)
  (evil-buffer-new nil (concat wolfe/org-dropbox-path name ".org")))
(defun wolfe/dropbox-start ()
  (interactive)
  (if (eq nil (file-exists-p "/virtual/wolfejos/dropbox/.dropbox-dist"))
      (call-process-shell-command "(python ~/.emacs.d/dropbox.py start -i&)")
    (call-process-shell-command "(python ~/.emacs.d/dropbox.py start&)")))
(defun wolfe/dropbox-stop ()
  (interactive)
  (call-process-shell-command "python ~/.emacs.d/dropbox.py stop&"))

5.7 Reload

For reloading init.el file without restarting.

(defun wolfe/load-init ()
  "Reloads init file"
  (interactive)
  (load-file "~/.emacs.d/init.el"))

5.8 Narrowing

Better narrowing.

(defun narrow-or-widen-dwim (p)
  "Widen if buffer is narrowed, narrow-dwim otherwise.
Dwim means: region, org-src-block, org-subtree, or
defun, whichever applies first. Narrowing to
org-src-block actually calls `org-edit-src-code'.

With prefix P, don't widen, just narrow even if buffer
is already narrowed."
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
        ((region-active-p)
         (narrow-to-region (region-beginning)
                           (region-end)))
        ((derived-mode-p 'org-mode)
         ;; `org-edit-src-code' is not a real narrowing
         ;; command. Remove this first conditional if
         ;; you don't want it.
         (cond ((ignore-errors (org-edit-src-code) t)
                (delete-other-windows))
               ((ignore-errors (org-narrow-to-block) t))
               (t (org-narrow-to-subtree))))
        ((derived-mode-p 'latex-mode)
         (LaTeX-narrow-to-environment))
        (t (narrow-to-defun))))

5.9 Man Replacement

Use the real man if I'm on a system that has the binary otherwise we should just use the emacs woman.

(defun wolfe/man ()
  (if (executable-find "man")
      (man (word-at-point))
    (woman)))

5.10 Hot Expand

Is used in one of my hydras wolfe/hydra-org-expand. For inserting org-templates.

(defun hot-expand (str &optional additional-text)
  "Expand org template."
  (insert str)
  (org-try-structure-completion)
  (when additional-text
    (insert additional-text)
    (forward-line)))

5.11 Projectile If-Else

This allows us to easily call a projectile version of a function if we're inside of a project otherwise we can just call the normal version. For example projectile-ag vs ag.

(defun wolfe/if-else-projectile (if-function else-function)
  "Calls the if-function if inside a project otherwise
it calls the else-function"
  (interactive)
  (if (projectile-project-p)
      (call-interactively if-function)
    (call-interactively else-function)))

5.12 Projectile Invalidate From List

Select project from list of projectile projects to invalidate.

(defun wolfe/projectile-invalidate-list ()
  (interactive)
  (projectile-invalidate-cache t))

5.13 User Pass Tupple

Uses GPG to decrypt file and returns a list of the contents split on spaces.

(defun wolfe/get-user-pass (file)
  (split-string
   (car (last (split-string
               (shell-command-to-string (concat "gpg --output - --decrypt "
                                                (expand-file-name file)))
               "[|\n]" t "[     \n]"))) " "))

5.14 Ag Kill Buffers and Close Window

Kill all the open ag buffers and delete the window I'm in. This is bound in my ag config in ag-mode-map so it will close the current ag window and all the buffers.

(defun wolfe/ag-kill-buffers-and-window ()
  (interactive)
  (ag-kill-buffers)
  (delete-window))

5.15 Org Tree Slides Set Transient Map

This function once called will keep a transient map active until wolfe--enable-transient-map is set to nil at which point it will unbind the variable. This is used with org-tree-slide-mode to add custom bindings regardless of the mode.

(defun wolfe/org-tree-set-transient-map ()
  (interactive)
  (if wolfe--enable-transient-map
      (let ((map (make-sparse-keymap)))
        (define-key map (kbd "<right>") 'org-tree-slide-move-next-tree)
        (define-key map (kbd "<left>")  'org-tree-slide-move-previous-tree)
        (define-key map (kbd "<up>")    'org-tree-slide-content)
        (define-key map (kbd "<down>")  'org-tree-slide-display-header-toggle)
        (set-transient-map map nil 'wolfe/org-tree-set-transient-map))
    (makeunbound wolfe--enable-transient-map)))

5.16 Eval and Replace

This was stolen from prelude emacs. Over there it's called prelude-eval-and-replace.

(defun wolfe/eval-and-replace (beginning end)
  "Replace the preceding sexp or region with its value."
  (interactive "r")
  (if (region-active-p)
      (delete-region beginning end)
    (backward-kill-sexp))
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
             (current-buffer))
    (error (message "Invalid expression")
           (insert (current-kill 0)))))

5.17 Call Function and Update Ex History

(defun wolfe/call-and-update-ex (fun)
  "Calls the function and updates `evil-ex-history' with the result"
  (interactive)
  (setq evil-ex-history (cons (format "e %s" (funcall fun)) evil-ex-history)))

6 Org Mode

6.1 General

Setup some basic quality of life org settings.

(setq org-pretty-entities t
      org-src-fontify-natively t
      org-src-tab-acts-natively t
      org-src-window-setup 'current-window
      org-fontify-whole-heading-line t
      org-fontify-done-headline t
      org-fontify-quote-and-verse-blocks t
      org-highlight-latex-and-related '(latex)
      org-enforce-todo-dependencies t
      org-agenda-use-time-grid nil
      org-agenda-skip-deadline-if-done t
      org-agenda-skip-scheduled-if-done t
      org-ellipsis wolfe/org-ellipsis
      org-entities-user '(("bot" "\\bot" nil "" "" "" "⊥")
                          ("square" "$\\square$" nil "" "" "" "□")))


(defun wolfe/org-tags-compute-width ()
  (- (floor (* 0.6 (frame-width)))))

(add-hook 'org-mode-hook
          (lambda ()
            (setq org-tags-column (wolfe/org-tags-compute-width))
            (org-align-all-tags)))
(add-hook 'org-agenda-mode-hook
          (lambda ()
            (setq org-agenda-tags-column (wolfe/org-tags-compute-width))
            (org-agenda-align-tags)))

(defun wolfe/save-org-archive-buffers (orig-fun &rest args)
  (save-some-buffers 'no-confirm
                     (lambda ()
                       (string-match "_archive\\'" buffer-file-name))))

(advice-add 'org-archive-subtree :after 'wolfe/save-org-archive-buffers)

(org-babel-do-load-languages
 'org-babel-load-languages
 '((shell . t)
   (  dot . t)))

(global-set-key "\C-cl" 'org-store-link)

;; ispell ignores SRC blocks
(add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_SRC" . "#\\+END_SRC"))
(add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_LATEX" . "#\\+END_LATEX"))

;; Refresh images after executing a src block
(add-hook 'org-babel-after-execute-hook
          (lambda ()
            (when org-inline-image-overlays
              (org-redisplay-inline-images))))

(defun wolfe/confirm-babel-evaluate (lang body)
  (not (string= lang "dot")))
(setq org-confirm-babel-evaluate 'wolfe/confirm-babel-evaluate)

;; Open PDFs with zathura
(add-hook 'org-mode-hook
          (lambda ()
            (setq org-file-apps
                  (append '(("\\.pdf\\'" . "zathura \"%s\"")) org-file-apps))))

6.2 Bullets

Replaces the asterisks with nice UTF-8 bullets.

(use-package org-bullets
  :config
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

6.3 Agenda

Setup org agenda for managing my life.

(use-package org-agenda
  :ensure nil
  :bind (("C-c a" . org-agenda)
         :map org-agenda-mode-map
         ("j" . org-agenda-next-item)
         ("k" . org-agenda-previous-item))
  :config
  ;; Formats the agenda into nice columns
  (setq org-agenda-prefix-format
        '((agenda . " %i %-12t% s %-12(car (last (org-get-outline-path)))")
          (timeline . "  % s")
          (todo . " %i %-12:c")
          (tags . " %i %-12:c")
          (search . " %i %-12:c")))

  ;; Sets location of org files
  (setq org-agenda-files `(,(concat wolfe/org-dropbox-path "everything.org")))
  (setq browse-url-browser-function 'browse-url-chromium))

6.4 Capture

(global-set-key "\C-cc" 'org-capture)

(setq org-default-notes-file (concat wolfe/org-dropbox-path "everything.org"))
(setq org-capture-templates
      '(("t" "Task" entry (file+headline "" "Need Refiling")
         "* TODO %?\n  DEADLINE: %t\n")))

6.5 Export

Setup html for syntax highlighting on export and add the apppropriate minted package for PDF export.

(use-package htmlize)

(require 'ox-latex)
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-export-allow-bind-keywords t
      org-latex-listings 'minted)
(setq org-latex-pdf-process
      '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
        "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
        "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

6.5.1 Hugo

(use-package ox-hugo
  :after ox)

6.6 Org Tree Slide

Presentation mode that runs from within an org document. I add a custom hook for a function that repeatedly creates a transient map replacing the controls regardless of my evil mode.

(use-package org-tree-slide
  :config
  (add-hook 'org-tree-slide-mode-hook
            (lambda ()
              (if org-tree-slide-mode
                  ;; When mode is enabled
                  (progn (setq wolfe--enable-transient-map t)
                         (wolfe/org-tree-set-transient-map))
                ;; When mode is disabled
                (setq wolfe--enable-transient-map nil)))))

7 Keymaps

7.1 Hydra

Customizable popup menus.

(use-package hydra)
(use-package major-mode-hydra
  :ensure nil)

7.1.1 Major Modes

7.1.1.1 C#
(major-mode-hydra-bind csharp-mode "Find"
  ("d" omnisharp-go-to-definition              "Goto definition")
  ("D" omnisharp-go-to-definition-other-window "Pop-open definition")
  ("u" omnisharp-find-usages                   "Find usages")
  ("p" omnisharp-find-implementations          "Find implementations"))

(major-mode-hydra-bind csharp-mode "Fix/Refactor"
  ("r" omnisharp-rename                        "Rename symbol")
  ("f" omnisharp-run-code-action-refactoring   "Code action")
  ("i" omnisharp-code-format-region            "Indent region")
  ("I" omnisharp-code-format-entire-file       "Indent entire file"))

(major-mode-hydra-bind csharp-mode "Solution"
  ("e" omnisharp-solution-errors               "Solution errors")
  ("a" omnisharp-add-to-solution-current-file  "Add current file to sln")
  ("s" omnisharp-reload-solution               "Reload solution"))
7.1.1.2 Python
(major-mode-hydra-bind python-mode "Python"
  ("i" elpy-importmagic-fixup "Importmagic fixup")
  ("d" elpy-goto-definition   "Goto definition")
  ("r" elpy-multiedit-python-symbol-at-point   "Rename symbol")
  ("f" elpy-format-code   "Format code")
  )
7.1.1.3 Org Mode
(major-mode-hydra-bind org-mode "Org Mode"
  ("t" (funcall wolfe/hydra-org-expand) "Expand template"))
7.1.1.4 Org Templates
(setq wolfe/hydra-org-expand
      (defhydra hydra-org-template (:color blue :hint nil)
        "
        _c_enter  _q_uote    _L_aTeX:
        _l_atex   _e_xample  _i_ndex:
        _a_scii   _v_erse    _I_NCLUDE:
        _s_rc     _t_angle   _H_TML:
        _h_tml    _d_ot src  _A_SCII:
        "
        ("s" (hot-expand "<s"))
        ("e" (hot-expand "<e"))
        ("q" (hot-expand "<q"))
        ("v" (hot-expand "<v"))
        ("t" (hot-expand "<s" "emacs-lisp :tangle yes"))
        ("d" (hot-expand "<s" "dot :file TMP.png :cmdline -Kdot -Tpng"))
        ("c" (hot-expand "<c"))
        ("l" (hot-expand "<l"))
        ("h" (hot-expand "<h"))
        ("a" (hot-expand "<a"))
        ("L" (hot-expand "<L"))
        ("i" (hot-expand "<i"))
        ("I" (hot-expand "<I"))
        ("H" (hot-expand "<H"))
        ("A" (hot-expand "<A"))))

7.1.2 Minor Modes

7.1.2.1 Projectile
(setq wolfe/hydra-projectile
      (pretty-hydra-define hydra-projectile (:exit t :hint nil)
        ("Files" (("f" counsel-projectile-find-file        "Find File")
                  ("d" counsel-projectile-find-dir         "Find Directory")
                  ("o" projectile-multi-occur              "Multi Occur")
                  ("s" counsel-projectile-switch-project   "Switch Project")
                  ("k" projectile-kill-buffers             "Kill Buffers"))

         "Cache" (("c" projectile-invalidate-cache         "Clear Cache")
                  ("C" wolfe/projectile-invalidate-list    "Clear A Cache")
                  ("P" projectile-clear-known-projects     "Clear Projects")))))
7.1.2.2 Jira
(defun wolfe/hydra-jira ()
  (interactive)
  (funcall
      (pretty-hydra-define hydra-jira (:exit t :hint nil)
        ("Get" (("p" org-jira-get-projects                "Get Projects")
                ("g" org-jira-get-issues                  "Get Issues")
                ("G" org-jira-get-subtasks                "Get Subtasks")
                ("r" org-jira-refresh-issue               "Refresh Issue")
                ("R" org-jira-refresh-issues-in-buffer    "Refresh Issues in Buffer"))

         "Manage" (("b" org-jira-browse-issue             "Browse Issue")
                   ("c" org-jira-create-issue             "Create Issue")
                   ("s" org-jira-create-subtask           "Create Subtask")
                   ("P" org-jira-progress-issue           "Update Issue Progress")
                   ("a" org-jira-assign-issue             "Assign Issue"))

         "Push" (("u" org-jira-update-issue                "Update Issue")
                 ("y" org-jira-copy-current-issue-key      "Copy Current Issue Key")
                 ("U" org-jira-update-comment              "Update Comment")
                 ("t" org-jira-todo-to-jira                "Todo to Jira"))))))

7.2 Evil & General

7.2.1 General

(use-package general)

7.2.2 Evil

(use-package evil
  :demand
  :bind
  (:map evil-motion-state-map
        ("C-u" . evil-scroll-up))
  :init
  (setq evil-want-C-u-scroll t
        evil-want-C-i-jump t
        evil-want-Y-yank-to-eol t)
  :config
  (evil-mode t)
  (setq evil-split-window-below t
        evil-vsplit-window-right t
        evil-lookup-func #'wolfe/man)
  (setq-default evil-symbol-word-search t)
  (custom-set-variables '(evil-search-module (quote evil-search)))
  (evil-ex-define-cmd "re[load]" 'wolfe/load-init) ; Custom reload command
  (evil-ex-define-cmd "Q" 'save-buffers-kill-terminal) ; For typos
  (define-key evil-ex-map "e " (lambda () (interactive) (wolfe/call-and-update-ex 'counsel-find-file))) ; Trigger file completion :e
  (global-unset-key (kbd "M-SPC")) ; Unbind secondary leader
  (add-to-list 'evil-emacs-state-modes 'vterm-mode)

  (general-create-definer wolfe/bind-leader
    :keymaps 'global
    :states '(normal insert visual emacs)
    :prefix "SPC"
    :non-normal-prefix "M-SPC")

  (general-define-key
   :states 'motion
   "k" 'evil-previous-visual-line
   "j" 'evil-next-visual-line)

  (general-define-key
   :states 'operator
   "k" 'evil-previous-line
   "j" 'evil-next-line)

  (general-define-key
   :states 'visual
   "<" (lambda ()
         (interactive)
         (evil-shift-left (region-beginning) (region-end))
         (evil-normal-state)
         (evil-visual-restore))
   ">" (lambda ()
         (interactive)
         (evil-shift-right (region-beginning) (region-end))
         (evil-normal-state)
         (evil-visual-restore)))

  (general-define-key
   :states 'normal
   "C-z"  'wolfe/controlz
   "C-l"  'evil-ex-nohighlight)

  (wolfe/bind-leader
    "w"  'save-buffer
    "S"  'wolfe/eval-and-replace
    "s"  'eval-defun
    "b"  'mode-line-other-buffer
    "k"  'kill-buffer
    "m"  'ivy-switch-buffer
    "e"  'iedit-mode
    "c"  'wolfe/compile-no-prompt
    "n"  'narrow-or-widen-dwim
    "a"  'org-agenda
    "g"  'magit-status
    "''" 'org-edit-src-exit
    "t"  'shell-pop
    "f"    (lambda() (interactive) (wolfe/if-else-projectile 'counsel-projectile-ag 'counsel-ag))
    "p"    (lambda() (interactive) (funcall wolfe/hydra-projectile))
    ";"    (lambda() (interactive) (save-excursion (end-of-line) (insert-char ?\;)))
    "id"   (lambda() (interactive) (indent-region (point-min) (point-max)))
    "o"    (lambda() (interactive) (wolfe/org-open "everything"))
    "init" (lambda() (interactive) (evil-buffer-new nil wolfe/init-file))
    "SPC"  'major-mode-hydra))

7.2.3 Evil Surround

Tpope's surround

(use-package evil-surround
  :config
  (global-evil-surround-mode 1))

7.2.4 Evil Machit

(use-package evil-matchit
  :config
  (global-evil-matchit-mode 1))

7.2.5 Evil Visual Star

This allows me to easily start a * or # search from a visual selection.

(use-package evil-visualstar
  :config
  (global-evil-visualstar-mode))

7.2.6 Evil Numbers

(use-package evil-numbers
  :bind
  (:map evil-normal-state-map
        ("C-a" . 'evil-numbers/inc-at-pt)
        ("C--" . 'evil-numbers/dec-at-pt)))

7.2.7 Evil Lion

(use-package evil-lion
  :config
  (evil-lion-mode))

7.2.8 Evil Exchange

(use-package evil-exchange
  :config
  (evil-exchange-install))

8 Project Management

8.1 Ag

Emacs interface for ag

(use-package ag
  :bind (:map ag-mode-map
         ("Q" . wolfe/ag-kill-buffers-and-window)))

8.2 Magit

Magic git interface from within emacs

(use-package magit
  :defer 10
  :config
  (use-package evil-magit)
  (setq magit-bury-buffer-function
        (lambda (con)
          (kill-buffer-and-window))))

8.3 Projectile

Project management

(use-package projectile
  :config
  (use-package counsel-projectile
    :config
    (counsel-projectile-mode))
  (setq projectile-enable-caching t)
  (setq projectile-indexing-method 'alien)
  (setq projectile-globally-ignored-file-suffixes
        '("#" "~" ".swp" ".o" ".so" ".exe" ".dll" ".elc" ".pyc" ".jar" "*.class"))
  (setq projectile-globally-ignored-directories
        '(".git" "node_modules" "__pycache__" ".vs"))
  (setq projectile-globally-ignored-files '("TAGS" "tags" ".DS_Store"))
  (projectile-mode))

8.4 Dumb Jump

Automatically grep or ag through a project for a definition. This is useful when semantic jump to definition or TAGS files aren't present or don't exist for the language.

(use-package dumb-jump
  :bind
  (:map evil-normal-state-map
        ("g D" . dumb-jump-go))
  :config
  (setq dumb-jump-selector 'ivy))

8.5 Persp Mode

(use-package persp-mode
  :hook (after-init . (lambda () (persp-mode 1)))
  :config
  (defvar wolfe/persp-default-workspace "main")
  (defvar wolfe/persp-shared-buffers '("*scratch*" "*Messages*"))
  (defvar wolfe/projectile-project-to-switch nil)

  (setq wg-morph-on nil ;; switch off animation
        persp-autokill-buffer-on-remove 'kill-weak
        persp-auto-save-opt 0
        persp-auto-resume-time -1
        persp-nil-hidden t
        persp-add-buffer-on-find-file t
        persp-add-buffer-on-after-change-major-mode t
        persp-hook-up-emacs-buffer-completion t)

  ;; Make ivy play nice
  (with-eval-after-load "ivy"
    (add-hook 'ivy-ignore-buffers
              #'(lambda (b)
                  (when persp-mode
                    (let ((persp (get-current-persp)))
                      (if persp
                          (not (persp-contain-buffer-p b persp))
                        nil)))))
    (setq ivy-sort-functions-alist
          (append ivy-sort-functions-alist
                  '((persp-kill-buffer   . nil)
                    (persp-remove-buffer . nil)
                    (persp-add-buffer    . nil)
                    (persp-switch        . nil)
                    (persp-window-switch . nil)
                    (persp-frame-switch . nil)))))

  (defun wolfe/projectile-switch-project-by-name (counsel-projectile-switch-project-by-name &rest args)
      (setq wolfe/projectile-project-to-switch (car args))
      (apply counsel-projectile-switch-project-by-name args)
      (setq wolfe/projectile-project-to-switch nil))
  (advice-add #'counsel-projectile-switch-project-by-name :around #'wolfe/projectile-switch-project-by-name)

  (defun wolfe/persp-create-project-persp ()
    (let ((frame (selected-frame))
          (name (file-name-nondirectory
                 (directory-file-name
                  (file-name-directory
                   wolfe/projectile-project-to-switch)))))
      (with-selected-frame frame
        (persp-add-new name)
        (persp-frame-switch name)
        (persp-add-buffer wolfe/persp-shared-buffers (get-current-persp) nil))))

  (add-hook 'projectile-before-switch-project-hook 'wolfe/persp-create-project-persp)

  (defun wolfe/persp-concat-name (count)
    (if (eq count 0)
        wolfe/persp-default-workspace
      (format "%s-%s" wolfe/persp-default-workspace count)))

  (defun wolfe/persp-next-main-name (&optional count)
    (let ((count (or count 0)))
      (if (persp-with-name-exists-p (wolfe/persp-concat-name count))
          (wolfe/persp-next-main-name (+ count 1))
        (wolfe/persp-concat-name count))))

  (add-hook
   'after-make-frame-functions
   (lambda (frame)
     (let ((name (wolfe/persp-next-main-name)))
       (with-selected-frame frame
         (set-frame-parameter frame 'wolfe/persp-current-main name)
         (persp-add-new name)
         (persp-frame-switch name frame)
         (persp-add-buffer wolfe/persp-shared-buffers (get-current-persp) nil)))))

  (add-hook
   'delete-frame-functions
   (lambda (frame)
     (with-selected-frame frame
       (persp-kill (frame-parameter frame 'wolfe/persp-current-main))))))

9 Languages

9.1 Generic Web

(use-package web-mode
  :defer t
  :mode ("\\.html\\'" "\\.php\\'" "\\.js\\'")
  :config
  (setq web-mode-enable-auto-closing t)
  (setq web-mode-enable-auto-opening t)
  (setq web-mode-enable-auto-indentation t))

(use-package json-mode)
(use-package company-restclient
  :after company
  :config
  (add-to-list 'company-backends 'company-restclient))

9.2 Javascript

(use-package company-tern
  :after company
  :config
  (add-to-list 'company-backends 'company-tern)
  (add-hook 'web-mode-hook 'tern-mode))
(use-package indium
  :defer t)

Basic editing mode for React.js files.

(use-package rjsx-mode
  :defer t)

9.3 Lisp Family

(use-package parinfer
  :defer t
  :bind
  (("C-," . parinfer-toggle-mode))
  :init
  (setq
   parinfer-extensions '(defaults pretty-parens evil smart-tab smart-yank)
   parinfer-lighters '(" Φi" . " Φp"))
  (add-hook 'racket-mode           #'parinfer-mode)
  (add-hook 'clojure-mode-hook     #'parinfer-mode)
  (add-hook 'emacs-lisp-mode-hook  #'parinfer-mode)
  (add-hook 'common-lisp-mode-hook #'parinfer-mode)
  (add-hook 'scheme-mode-hook      #'parinfer-mode)
  (add-hook 'lisp-mode-hook        #'parinfer-mode))

9.4 Racket

(use-package racket-mode
  :defer t)

9.5 Haskell

(use-package haskell-mode
  :defer t)

9.6 Latex

(use-package latex-preview-pane
  :defer t
  :ensure f)

9.7 C/C++

(setq gdb-many-windows t
      gdb-show-main t
      company-clang-insert-arguments nil)

(setq-default c-basic-offset 4)

(use-package company-irony
  :defer t
  :after company
  :config
  (add-hook 'c++-mode-hook 'irony-mode)
  (add-hook 'c-mode-hook 'irony-mode)
  (eval-after-load 'company
    '(add-to-list 'company-backends 'company-irony)))

9.8 C#

(use-package omnisharp
  :defer t
  :after company
  :config
  (when wolfe/windows?
    (setq omnisharp-server-executable-path "C:/emacs/omnisharp/Omnisharp.exe"))
  (add-hook 'csharp-mode-hook
            (lambda ()
              (evil-define-key 'normal omnisharp-mode-map (kbd "g d") 'omnisharp-go-to-definition)
              (unless (file-exists-p "Makefile")
                (set (make-local-variable 'compile-command) (concat "msbuild " (cdr (assoc :project-root omnisharp--server-info)))))))
  (add-hook 'csharp-mode-hook 'omnisharp-mode)
  (add-to-list 'company-backends 'company-omnisharp))

9.9 Python

I explicitly load the python package so that I can defer it and elpy together since elpy is a bit slow to load at startup.

(use-package python
  :defer 10
  :hook python-mode-hook)

(use-package elpy
  :after (company python)
  :init (elpy-enable)
  :config
  (setq elpy-rpc-backend "jedi")
  (when (executable-find "ipython")
    (setq python-shell-interpreter "ipython"
          python-shell-interpreter-args "-i --simple-prompt"))

  (delete 'elpy-module-highlight-indentation elpy-modules)
  (delete 'elpy-module-flymake elpy-modules))

9.10 Shell Scripts

(use-package company-shell
  :defer t
  :after company
  :config
  (add-to-list 'company-backends '(company-shell company-shell-env)))

9.11 Go

(use-package go-mode
  :defer t
  :config
  (add-hook 'go-mode-hook (lambda () (setq tab-width 4))))
(use-package company-go
  :defer t
  :after company
  :config
  (when wolfe/linux?
    (add-to-list 'exec-path "~/Projects/go/bin"))
  (add-to-list 'company-backends 'company-go))

9.12 Java

(use-package company-emacs-eclim
  :after company
  :config
  (company-emacs-eclim-setup)
  (setq eclimd-autostart t)

  (defun my-java-mode-hook ()
      (eclim-mode t))

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

10 Utility

10.1 Ranger

(use-package ranger
  :config
  (setq ranger-cleanup-on-disable t)
  (ranger-override-dired-mode t))

10.2 Iedit

Edit all instances of a string

(use-package iedit
  :config
  (setq iedit-toggle-key-default nil))

10.3 Quick Run

(use-package quickrun
  :defer t)

10.4 Restclient

Postman inside of emacs.

(use-package restclient
  :defer t)

10.5 Rainbow Mode

Shows hex colors inline.

(use-package rainbow-mode
  :defer t)

10.6 Helpful

(use-package helpful
  :defer t
  :bind
  (("C-h f" . helpful-callable)
   ("C-h v" . helpful-variable)
   ("C-h k" . helpful-key)
   ("C-h F" . helpful-function)
   ("C-h C" . helpful-command))
  :config
  (evil-define-key 'normal helpful-mode-map (kbd "q") 'kill-buffer-and-window)
  (set-face-attribute 'helpful-heading nil :height 1.1))

10.7 Shackle

(use-package shackle
  :config
  (setq shackle-default-alignment 'below
        shackle-default-size 0.4
        shackle-rules
        '(("*HTTP Response*" :popup t :align right)))
  (shackle-mode))

10.8 Zoom

(use-package zoom
  :config
  (setq zoom-size '(0.618 . 0.618))
  (zoom-mode t))

10.9 Exec Path From Shell

(use-package exec-path-from-shell
  :config
  (exec-path-from-shell-copy-env "GPG_TTY")
  (exec-path-from-shell-copy-env "SSH_AUTH_SOCK"))

10.10 Shell Pop

(use-package shell-pop
  :config
  (defun shell-pop--set-exit-action ()
    (if (string= shell-pop-internal-mode "eshell")
        (add-hook 'eshell-exit-hook 'shell-pop--kill-and-delete-window nil t)
      (let ((process (get-buffer-process (current-buffer))))
        (when process
          (set-process-sentinel
           process
           (lambda (_proc change)
             (when (string-match-p "\\(?:finished\\|exited\\)" change)
               (if (one-window-p)
                   (switch-to-buffer shell-pop-last-buffer)
                 (kill-buffer-and-window)))))))))

  (custom-set-variables
   '(shell-pop-shell-type (quote ("vterm" "*vterm*" (lambda nil (vterm)))))
   '(shell-pop-term-shell "/usr/bin/zsh")
   '(shell-pop-window-position "right")))

11 Completion

11.1 Ivy & Counsel

(use-package ivy
  :demand
  :bind (("M-x" . counsel-M-x)
         ("C-x C-f" . counsel-find-file)
         :map ivy-minibuffer-map
         ("TAB" . ivy-next-line)
         ("RET" . ivy-alt-done)
         :map ivy-switch-buffer-map
         ("C-d" . ivy-switch-buffer-kill))
  :init
  (use-package smex)
  (use-package counsel)
  :config
  (setq ivy-re-builders-alist
        '((t . ivy--regex-ignore-order)))
  (setq ivy-wrap t)
  (ivy-mode 1)

  (use-package doom-todo-ivy
    :ensure nil
    :config
    (evil-define-command doom/ivy-tasks-ex (&optional bang)
      "An ex wrapper around `doom/ivy-tasks'."
      (interactive "<!>")
      (doom/ivy-tasks bang))
    (evil-ex-define-cmd "todo" 'doom/ivy-tasks-ex))

  (eval-after-load "hydra" (use-package ivy-hydra)))

11.2 Swiper

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

11.3 Company

Autocomplete engine

(use-package company
  :bind (:map company-active-map
         ("C-n" . company-select-next)
         ("C-p" . company-select-previous))
  :init
  (global-company-mode)
  :config
  (setq company-idle-delay 0) ; Delay to complete
  (setq company-minimum-prefix-length 1)
  (setq company-selection-wrap-around t) ; Loops around suggestions

  (if (display-graphic-p)
      (define-key company-active-map [tab] 'company-select-next)
    (define-key company-active-map (kbd "C-i") 'company-select-next))
(hook-if-daemonp
 (lambda ()
   (require 'color)
   (let ((bg (face-attribute 'default :background))
         (ac (face-attribute 'match :foreground)))
     (custom-set-faces
      `(company-tooltip ((t (:inherit default :background ,(color-lighten-name bg 2)))))
      `(company-scrollbar-bg ((t (:background ,(color-lighten-name bg 10)))))
      `(company-scrollbar-fg ((t (:background ,(color-lighten-name bg 5)))))
      `(company-tooltip-selection ((t (:inherit font-lock-function-name-face))))
      `(company-tooltip-common ((t (:inherit font-lock-constant-face))))
      `(company-preview-common ((t (:foreground ,ac :background ,(color-lighten-name bg 10))))))))))

11.4 Flycheck Linting

On the fly syntax checking

(use-package flycheck
  :config
  (global-flycheck-mode)
  (setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc)))

11.5 Yasnippet

(use-package yasnippet
  :config
  (yas-global-mode 1))

12 Misc

12.1 Email

(require 'epa-file)
(custom-set-variables '(epg-gpg-program  "c:/Program Files (x86)/GNU/GnuPG/pub/gpg2"))
(epa-file-enable)

(require 'gnus)
(setq user-mail-address "joshuafwolfe@gmail.com"
      user-full-name "Josh Wolfe")

(setq gnus-select-method
      '(nnimap "gmail"
         (nnimap-address "imap.gmail.com")
         (nnimap-server-port 993)
         (nnimap-stream ssl)))

(setq smtpmail-smtp-server "smtp.gmail.com"
      smtpmail-smtp-service 587
      gnus-ignored-newsgroups "^to\\.\\|^[0-9. ]+\\( \\|$\\)\\|^[\"]\"[#'()]")

(setq gnus-thread-sort-functions
      '(gnus-thread-sort-by-most-recent-date
        (not gnus-thread-sort-by-number)))

(defun my-gnus-group-list-subscribed-groups ()
  "List all subscribed groups with or without un-read messages"
  (interactive)
  (gnus-group-list-all-groups 5))

(define-key gnus-group-mode-map
  ;; list all the subscribed groups even they contain zero un-read messages
  (kbd "o") 'my-gnus-group-list-subscribed-groups)

12.2 IRC

My erc settings are pretty basic. I have the fill column recalculate on window resize and I put the scroll margin back to default so that my scrolloff settings don't mess with it.

(use-package erc
  :ensure nil
  :defer t
  :config
  (add-hook 'window-configuration-change-hook
            (lambda ()
              (setq erc-fill-column (- (window-width) 2))))
  (add-hook 'erc-mode-hook
            (lambda ()
              (setq-local scroll-margin 1)))

  (setq erc-rename-buffers t
        erc-interpret-mirc-color t
        erc-lurker-hide-list '("JOIN" "PART" "QUIT")
        erc-autojoin-channels-alist '(("freenode.net" "#emacs"))))

Simple function that pulls my credentials from a GPG encrypted file and connects to freenode providing a nick and password to verify my user.

(defun wolfe/irc ()
      (interactive)
      (let* ((tupple (wolfe/get-user-pass wolfe/irc-info-path))
             (user (car tupple))
             (pass (cadr tupple)))
        (erc
         :server "irc.freenode.net"
         :port 6667
         :nick user
         :password pass)))

12.3 Meme

Meme creator from within emacs… what more is there to say?

(use-package meme
  :ensure nil
  :commands (meme meme-file))

13 Backups

Stores all backups and temp files in ~/.bak.emacs/

(setq backup-by-copying t) ; Stop shinanigans with links
(setq backup-directory-alist '((".*" . "~/.bak.emacs/backup/")))
;; Creates directory if it doesn't already exist
(make-directory "~/.bak.emacs/" t)
;; Creates auto directory if it doesn't already exist
(make-directory "~/.bak.emacs/auto" t)
;; backup in one place. flat, no tree structure
(setq auto-save-file-name-transforms '((".*" "~/.bak.emacs/auto/" t)))

14 Testing

14.1 Org Project

(let ((todo-file-path "~/Projects/todo-projectile/todo-projectile.el"))
  (when wolfe/windows?
    (setq todo-file-path "c:/dev/SideProjects/todo-projectile/todo-projectile.el"))
  (when (file-exists-p todo-file-path)
    (load-file todo-file-path)
    (setq todo-projectile-use-ag t)))

14.2 Extract Dates

(defun wolfe/extract-dates (file-path)
  "Parse through a file for a list of all the comments"
  (let (already-open
        buf
        start
        (comments '()))
    (setq already-open (find-buffer-visiting file-path)
          buf (find-file-noselect file-path))
    (with-current-buffer buf
      (goto-char (point-min))
      (while (setq start (text-property-any
                          (point) (point-max)
                          'face 'org-date))
        (goto-char start)
        (goto-char (next-single-char-property-change (point) 'face))
        (let ((item (string-trim (buffer-substring-no-properties start (point)))))
          (setq comments (cons item comments)))))
    (unless already-open (kill-buffer buf))
    (reverse comments)))

14.3 Vterm

(add-to-list 'load-path "~/emacs-libvterm/")
(require 'vterm)