Skip to content

Latest commit

 

History

History
4988 lines (4599 loc) · 175 KB

config.org

File metadata and controls

4988 lines (4599 loc) · 175 KB

Emacs Configuration

This is my emacs configuration file. I use org-mode to organize it and then “tangle” the file using org-babel. You can find a helpful discussion of this method here.

I use emacs for all my academic work. The configuration tends in that direction. It also uses vim keybindings. I used vim (or neovim) previously. I think vim’s modal editing is the best way to use a text-editor. If you like vim bindings but don’t tend to want to think about configuring emacs, I strongly recommend spacemacs as a way of managing your configuration. For a more traditional emacs feel there are also the configurations of purcell and batsov (prelude). For a minimally sane setup you might also look at some sensible defaults.

Installing Emacs

On OS X, which I use, homebrew is an easy way to install emacs. Starting out on OS X I would recommend using the emacs mac port version of emacs, which has a variety of options set that make for smoother running on OS X. The one downside is that it loads a bit slower than regular GNU emacs. For more info on the various configurations available for OS X use brew info.

Here’s what some example parameters mean.

--with-cocoa
installs emacs with the OS X GUI version
--with-imagemagick
installs emacs with imagemagick support for image processing
--with-gnutls
installs emacs with GnuTLS to utilize encrypted SSL and TLS connections

For emacs-mac use:

brew install emacs-mac --with-gnutls --with-imagemagick --with-librsvg

For GNU emacs 25 use the following:

brew install emacs --with-cocoa --HEAD --with-gnutls --with-imagemagick --with-librsvg

If you use homebrew cask you can install an emacs binary from emacs for mac, like so:

brew cask install emacs

Bootstrapping

This is the bootstrap code for getting the literate configuration file in config.org up and running. The original source for much of this code is from sriramkswamy/dotemacs. I’ve also been inspired by Sacha Chua’s configuration. There are also many other sources from around the Internet whose names I’ve forgotten. Thanks to all of you for making your configurations public! This config is fed into the init file. Org mode is installed if not already present, as is use-package. There is no need for any other package management.

Core Configuration

These settings constitute those settings I regard as essential to normal emacs operation.

Settings

System Defaults

Let’s use sane defaults. Sources for this section include Magnars Sveen and Sacha Chua.

Environment settings

Make sure emacs correctly sets up your PATH.

(defvar cpm-local-bin (concat (getenv "HOME") "/bin") "Local execs.")
(defvar usr-local-bin "/usr/local/bin")
(setenv "PATH" (concat usr-local-bin ":" (getenv "PATH") ":" cpm-local-bin))
(setq exec-path (append exec-path (list cpm-local-bin usr-local-bin)))

Deal with warnings

No bells and no visible “bell” either!

(setq visible-bell nil) ;; The default
(setq ring-bell-function 'ignore)
;; Silence warnings generated by a function's being redefine by =defadvice=.
(setq ad-redefinition-action 'accept)

No startup message

  ;; Change the echo message
(defun display-startup-echo-area-message ()
  (message ""))

These functions are useful. Activate them.

(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'dired-find-alternate-file 'disabled nil)

Answering just ‘y’ or ‘n’ will do

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

UTF-8 please

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

Give buffers unique names

(setq uniquify-buffer-name-style 'forward)

Dired settings

;; (setq insert-directory-program "gls" dired-use-ls-dired t)
;; stop asking about recurisve actions
(setq dired-recursive-copies 'always)
(setq dired-recursive-deletes 'always)

Help Buffers

;; Keep focus while navigating help buffers
(setq help-window-select 't)

Clipboard

;; Save whatever’s in the current (system) clipboard before
;; replacing it with the Emacs’ text.
;; https://github.com/dakrone/eos/blob/master/eos.org
(setq save-interprogram-paste-before-kill t)

File Endings

Make all files POSIX compliant for newlines

;; Make sure your text files end in a newline
(setq require-final-newline t)

Start from scratch

Start up with a clean scratch buffer.

(setq inhibit-splash-screen t)
(setq inhibit-startup-message t)
(setq initial-scratch-message "")
;; And bury the scratch buffer, don't kill it
(defadvice kill-buffer (around kill-buffer-around-advice activate)
(let ((buffer-to-kill (ad-get-arg 0)))
  (if (equal buffer-to-kill "*scratch*")
      (bury-buffer)
    ad-do-it)))

Start scratch in fundamental mode

Useful to get a faster Emacs load time because it avoids autoloads of elisp modes or other minor modes

(setq initial-major-mode 'fundamental-mode)

Turn off the blinking cursor

(blink-cursor-mode 0)

Cache Directory

(defconst user-cache-directory
  (expand-file-name (concat user-emacs-directory ".cache/"))
  "My emacs storage area for persistent files.")
;; create the `user-cache-directory' if it doesn't exist
(make-directory user-cache-directory t)

Backups

(let ((backup-dir (concat user-cache-directory "backup")))
  ;; Move backup file to `~/.emacs.d/.cache/backup'
  (setq backup-directory-alist `(("." . ,backup-dir)))
  ;; Makesure backup directory exist
  (when (not (file-exists-p backup-dir))
    (make-directory backup-dir t)))

(setq make-backup-files t               ; backup of a file the first time it is saved.
      backup-by-copying t               ; don't clobber symlinks
      version-control t                 ; version numbers for backup files
      delete-old-versions t             ; delete excess backup files silently
      delete-by-moving-to-trash t
      kept-old-versions 6               ; oldest versions to keep when a new numbered backup is made
      kept-new-versions 6               ; newest versions to keep when a new numbered backup is made
      )
(setq vc-make-backup-files t) ;;  backup versioned files, which Emacs does not do by default

Backup Walker

Traverse backups with backup-walker

(use-package backup-walker)

Auto Save

I make sure Emacs auto-saves often but the result is that it messes up my file tree. So, let’s ask Emacs to store its backups in the cache directory.

(setq auto-save-list-file-prefix
      (concat user-cache-directory "auto-save-list/.saves-"))

(setq auto-save-default t               ; auto-save every buffer that visits a file
      auto-save-timeout 20              ; number of seconds idle time before auto-save (default: 30)
      auto-save-interval 200            ; number of keystrokes between auto-saves (default: 300)
      auto-save-visited-file-name nil
      delete-auto-save-files t
      create-lockfiles nil)

Full Auto Save

I also make emacs just outright save all buffers.

(defun full-auto-save ()
  (interactive)
  (save-excursion
    (dolist (buf (buffer-list))
      (set-buffer buf)
      (if (and (buffer-file-name) (buffer-modified-p))
          (basic-save-buffer)))))
(add-hook 'auto-save-hook 'full-auto-save)

Custom file settings

Set up the customize file to its own separate file, instead of saving customize settings in init.el.

(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
  (load custom-file))

Desktop save

(setq desktop-dirname             (concat user-cache-directory "desktop")
      desktop-base-file-name      "emacs.desktop"
      desktop-base-lock-name      "lock"
      desktop-path                (list desktop-dirname)
      desktop-save                'ask-if-new
      desktop-files-not-to-save   (concat "^$" ".*magit$")
      desktop-restore-eager 10
      desktop-load-locked-desktop t)
(setq desktop-buffers-not-to-save
        (concat "\\("
                "^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS"
                "\\|\\.emacs.*\\|\\.diary\\|\\.newsrc-dribble\\|\\.bbdb"
	          "\\)$"))
(desktop-save-mode 0)
(defun my-desktop ()
  "Load the desktop and enable autosaving"
  (interactive)
  (let ((desktop-load-locked-desktop "ask"))
    (desktop-read)
    (desktop-save-mode 1)))

(defun save-desktop-save-buffers-kill-emacs ()
  "Save buffers and current desktop every time when quitting emacs."
  (interactive)
  (desktop-save-in-desktop-dir)
  (save-buffers-kill-emacs))

;; better session management
(use-package desktop+
  :ensure t
  :commands (desktop+-create desktop+-load)
  :config
  (setq desktop+-base-dir (concat user-cache-directory "desktop"))
  (defun my/desktop-frame-title-function (desktop-name)
  (list (concat "%f | [" desktop-name "]")))

  (setq desktop+-frame-title-function
      'my/desktop-frame-title-function)
) 

OSX settings

There is some configuration to do when running Emacs on OS X (hence the “darwin” system-type check).

(let ((is-mac (string-equal system-type "darwin")))
  (when is-mac
    ;; make fonts look better with anti-aliasing
    (setq mac-allow-anti-aliasing t)
    ;; delete files by moving them to the trash
    (setq delete-by-moving-to-trash t)
    (setq trash-directory "~/.Trash")

    ;; Don't make new frames when opening a new file with Emacs
    (setq ns-pop-up-frames nil)
    
    ;; non-lion fullscreen
    (setq ns-use-native-fullscreen nil)

    ;; Set modifier keys
    (setq mac-option-modifier 'meta) ;; Bind meta to ALT
    (setq mac-command-modifier 'super) ;; Bind apple/command to super if you want
    (setq mac-function-modifier 'hyper) ;; Bind function key to hyper if you want 
    (setq mac-right-option-modifier 'none) ;; unbind right key for accented input

    ;; Make forward delete work 
    (global-set-key (kbd "<H-backspace>") 'delete-forward-char)
  
    ;; Keybindings
    (global-set-key (kbd "s-=") 'scale-up-font)
    (global-set-key (kbd "s--") 'scale-down-font)
    (global-set-key (kbd "s-0") 'reset-font-size)
    (global-set-key (kbd "s-q") 'save-buffers-kill-terminal)
    (global-set-key (kbd "s-v") 'yank)
    (global-set-key (kbd "s-c") 'evil-yank)
    (global-set-key (kbd "s-a") 'mark-whole-buffer)
    (global-set-key (kbd "s-x") 'kill-region)
    (global-set-key (kbd "s-w") 'delete-window)
    (global-set-key (kbd "s-W") 'delete-frame)
    (global-set-key (kbd "s-n") 'make-frame)
    (global-set-key (kbd "s-z") 'undo-tree-undo)
    (global-set-key (kbd "s-s")
                    (lambda ()
                      (interactive)
                      (call-interactively (key-binding "\C-x\C-s"))))
    (global-set-key (kbd "s-Z") 'undo-tree-redo)
    (global-set-key (kbd "C-s-f") 'toggle-frame-fullscreen)
    ;; Emacs sometimes registers C-s-f as this weird keycode
    (global-set-key (kbd "<C-s-268632070>") 'toggle-frame-fullscreen)
))
 
    (defun open-dir-in-iterm ()
      "Open the current directory of the buffer in iTerm."
      (interactive)
      (let* ((iterm-app-path "/Applications/iTerm.app")
             (iterm-brew-path "/opt/homebrew-cask/Caskroom/iterm2/2.1.4/iTerm.app")
             (iterm-path (if (file-directory-p iterm-app-path)
                             iterm-app-path
                           iterm-brew-path)))
        (shell-command (concat "open -a " iterm-path " ."))))
        (global-set-key (kbd "C-x t") 'open-dir-in-iterm)

    ;; Not going to use these commands
    (put 'ns-print-buffer 'disabled t)
    (put 'suspend-frame 'disabled t)

Time stamps

(setq 
  time-stamp-active t          ; do enable time-stamps
  time-stamp-line-limit 10     ; check first 10 buffer lines for Time-stamp: 
  time-stamp-format "Last modified on %04y-%02m-%02d %02H:%02M:%02S (%U)") ; date format
(add-hook 'write-file-hooks 'time-stamp) ; update when saving

Text Settings

General Text settings and hooks

Sentence endings

;; Single space between sentences is more widespread than double
(setq-default sentence-end-double-space nil)

Spelling

Use flyspell and aspell

(use-package ispell
  :defer 10
  :config
  ;; Save a new word to personal dictionary without asking
  (setq ispell-silently-savep t)
  (setq-default ispell-program-name "aspell")
  (setq-default ispell-list-command "list"))

(use-package flyspell
  :diminish flyspell-mode
  :defer 11
  ;; :commands (flyspell-mode flyspell-prog-mode)
  :init
  (progn
  ;; Below variables need to be set before `flyspell' is loaded.
    (setq flyspell-use-meta-tab nil))
  :config
  ;; Save a new word to personal dictionary without asking
  (setq flyspell-issue-welcome-flag nil))

Spelling Autocorrect

Use abbrev-mode as my autocorrect. Via Endless Parentheses.

(define-key ctl-x-map "\C-i"
  #'endless/ispell-word-then-abbrev)

(defun endless/simple-get-word ()
  (car-safe (save-excursion (ispell-get-word nil))))

(defun endless/ispell-word-then-abbrev (p)
  "Call `ispell-word', then create an abbrev for it.
With prefix P, create local abbrev. Otherwise it will
be global.
If there's nothing wrong with the word at point, keep
looking for a typo until the beginning of buffer. You can
skip typos you don't want to fix with `SPC', and you can
abort completely with `C-g'."
  (interactive "P")
  (let (bef aft)
    (save-excursion
      (while (if (setq bef (endless/simple-get-word))
                 ;; Word was corrected or used quit.
                 (if (ispell-word nil 'quiet)
                     nil ; End the loop.
                   ;; Also end if we reach `bob'.
                   (not (bobp)))
               ;; If there's no word at point, keep looking
               ;; until `bob'.
               (not (bobp)))
        (backward-word)
        (backward-char))
      (setq aft (endless/simple-get-word)))
    (if (and aft bef (not (equal aft bef)))
        (let ((aft (downcase aft))
              (bef (downcase bef)))
          (define-abbrev
            (if p local-abbrev-table global-abbrev-table)
            bef aft)
          (message "\"%s\" now expands to \"%s\" %sally"
                   bef aft (if p "loc" "glob")))
      (user-error "No typo at or before point"))))

(setq save-abbrevs 'silently)

(use-package abbrev-mode
  :ensure nil
  :commands (abbrev-mode))

Flyspell is in elisp mode. And this in turn loads flyspell directly after launching emacs, which is a bit unfortunate.

(defun my-flyspell-prog-mode ()
  (interactive)
  (unless (string= (buffer-name) "*scratch*")
	(flyspell-prog-mode)))
    (add-hook 'prog-mode-hook  #'my-flyspell-prog-mode)
    (add-hook 'text-mode-hook  #'flyspell-mode)
    (add-hook 'org-mode-hook   #'flyspell-mode)
    (add-hook 'latex-mode-hook #'flyspell-mode)
    (add-hook 'LaTeX-mode-hook #'flyspell-mode)

Only use spaces

(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq-default indicate-empty-lines nil)

Line wrap

(global-visual-line-mode)
(setq line-move-visual t) ;; move via visual lines

Fill column

(setq-default fill-column 78)

Visual replace

This is the good old search and replace as opposed to the fancy alternatives such as iedit and multiple cursors. You search for a word in the buffer/region, type in the replacement and confirm each one by pressing y or n or just press ! to apply this to everything.

(use-package visual-regexp
  :commands (vr/query-replace)
  :config
  (use-package visual-regexp-steroids
    :commands (vr/select-query-replace)))

Show Matching Brackets

Show matching brackets, parenthesis, etc.

(show-paren-mode t)

Useful Libraries

async, s, dash, and cl-lib are libraries for asynchronous processing, string manipulation, list manipulation and backward compatibility respectively.

(use-package async :commands (async-start))

(use-package cl-lib :defer t)

(use-package dash :defer t)

(use-package s :defer t)

Useful Functions & Macros

Various useful functions and macros I’ve written or pilfered from others.

Crux

A collection of ridiculously useful extensions. Indeed.

(use-package crux :defer 2)

Config functions

(defun goto-init.el ()
    "Open init.el file"
    (interactive)
    (find-file "~/.emacs.d/init.el"))
(defun goto-custom.el ()
    "Open custom.el file"
    (interactive)
    (find-file "~/.emacs.d/custom.el"))
(defun goto-config.org ()
    "Open config.org file"
    (interactive)
    (find-file "~/.emacs.d/config.org"))
(defun load-config ()
    "Load config "
    (interactive)
    (load-file "~/.emacs.d/init.el"))

Duplicate file

Duplicate a file in dired or deer

(defun cpm/duplicate-file ()
  (interactive)
  (dired-do-copy-regexp "\\(.*\\)\\.\\(.*\\)" "\\1 (copy).\\2"))

Switch to previous buffer

(defun switch-to-previous-buffer ()
  (interactive)
  (switch-to-buffer (other-buffer (current-buffer) 1)))

Make parent directory

Create a directory – or a hierarchy of them – while finding a file in a nonexistent directory. From mbork.

(defun make-parent-directory ()
  "Make sure the directory of `buffer-file-name' exists."
  (make-directory (file-name-directory buffer-file-name) t))

(add-hook 'find-file-not-found-functions #'make-parent-directory)

Org wrap in block template

A helpful function I found here for wrapping text in a block template.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; function to wrap blocks of text in org templates                       ;;
;; e.g. latex or src etc                                                  ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun org-block-wrap ()
  "Make a template at point."
  (interactive)
  (if (org-at-table-p)
      (call-interactively 'org-table-rotate-recalc-marks)
    (let* ((choices '(
                      ("a" . "ASCII")
                      ("c" . "COMMENT")
                      ("C" . "CENTER")
                      ("e" . "EXAMPLE")
                      ("E" . "SRC emacs-lisp")
                      ("h" . "HTML")
                      ("l" . "LaTeX")
                      ("n" . "NOTES")
                      ("q" . "QUOTE")
                      ("s" . "SRC")
                      ("v" . "VERSE")
                      ))
           (key
            (key-description
             (vector
              (read-key
               (concat (propertize "Template type: " 'face 'minibuffer-prompt)
                       (mapconcat (lambda (choice)
                                    (concat (propertize (car choice) 'face 'font-lock-type-face)
                                            ": "
                                            (cdr choice)))
                                  choices
                                  ", ")))))))
      (let ((result (assoc key choices)))
        (when result
          (let ((choice (cdr result)))
            (cond
             ((region-active-p)
              (let ((start (region-beginning))
                    (end (region-end)))
                (goto-char end)
                (insert "#+END_" choice "\n")
                (goto-char start)
                (insert "#+BEGIN_" choice "\n")))
             (t
              (insert "#+BEGIN_" choice "\n")
              (save-excursion (insert "#+END_" choice))))))))))

Copy formatted org-mode text to rtf

Via the always resourceful John Kitchin.

  (defun formatted-copy ()
  "Export region to HTML, and copy it to the clipboard."
  (interactive)
  (save-window-excursion
    (let* ((buf (org-export-to-buffer 'html "*Formatted Copy*" nil nil t t))
           (html (with-current-buffer buf (buffer-string))))
      (with-current-buffer buf
        (shell-command-on-region
         (point-min)
         (point-max)
         "textutil -stdin -format html -convert rtf -stdout | pbcopy")) 
      (kill-buffer buf))))

(global-set-key (kbd "H-w") 'formatted-copy)

Don’t export Org-mode headlines

(defun org-remove-headlines (backend)
"Remove headlines with :no_title: tag."
(org-map-entries (lambda () (let ((beg (point)))
                              (outline-next-visible-heading 1)
                              (backward-char)
                              (delete-region beg (point))))
                 "no_export" tree)
(org-map-entries (lambda () (delete-region (point-at-bol) (point-at-eol)))
                 "no_title"))

;; the following isn't currently working with org-mode 9
;; (add-hook 'org-export-before-processing-hook #'org-remove-headlines)

Move File

(defun move-file ()
  "Write this file to a new location, and delete the old one."
  (interactive)
  (let ((old-location (buffer-file-name)))
    (call-interactively #'write-file)
    (when old-location
      (delete-file old-location))))

Pandoc conversion from clipboard

(defun cpm/org-to-markdown ()
  "convert clipboard contents from org to markdown and paste"
  (interactive)
  (kill-new (shell-command-to-string "osascript -e 'the clipboard as unicode text' | pandoc -f org -t markdown"))
  (yank))

(defun cpm/markdown-to-org ()
  "convert clipboard contents from markdown to org and paste"
  (interactive)
  (kill-new (shell-command-to-string "osascript -e 'the clipboard as unicode text' | pandoc -f markdown -t org"))
  (yank))

(defun cpm/tex-to-org ()
  "convert clipboard contents from markdown to org and paste"
  (interactive)
  (kill-new (shell-command-to-string "osascript -e 'the clipboard as unicode text' | pandoc -f latex -t org"))
  (yank))

(defun cpm/tex-to-markdown ()
  "convert clipboard contents from markdown to org and paste"
  (interactive)
  (kill-new (shell-command-to-string "osascript -e 'the clipboard as unicode text' | pandoc -f latex -t markdown"))
  (yank))

Resume last search

(defun last-search-buffer ()
      "open last helm-ag or hgrep buffer."
      (interactive)
      (cond ((get-buffer "*helm ag results*")
             (switch-to-buffer-other-window "*helm ag results*"))
            ((get-buffer "*helm-ag*")
             (helm-resume "*helm-ag*"))
            ((get-buffer "*hgrep*")
             (switch-to-buffer-other-window "*hgrep*"))
            (t
             (message "No previous search buffer found"))))

Rotate windows

;; from magnars modified by ffevotte for dedicated windows support
(defun rotate-windows (count)
  "Rotate your windows.
Dedicated windows are left untouched. Giving a negative prefix
argument takes the kindows rotate backwards."
  (interactive "p")
  (let* ((non-dedicated-windows (remove-if 'window-dedicated-p (window-list)))
         (num-windows (length non-dedicated-windows))
         (i 0)
         (step (+ num-windows count)))
    (cond ((not (> num-windows 1))
           (message "You can't rotate a single window!"))
          (t
           (dotimes (counter (- num-windows 1))
             (let* ((next-i (% (+ step i) num-windows))

                    (w1 (elt non-dedicated-windows i))
                    (w2 (elt non-dedicated-windows next-i))

                    (b1 (window-buffer w1))
                    (b2 (window-buffer w2))

                    (s1 (window-start w1))
                    (s2 (window-start w2)))
               (set-window-buffer w1 b2)
               (set-window-buffer w2 b1)
               (set-window-start w1 s2)
               (set-window-start w2 s1)
               (setq i next-i)))))))

(defun rotate-windows-backward (count)
  "Rotate your windows backward."
  (interactive "p")
  (spacemacs/rotate-windows (* -1 count)))

Open projects directory

(defun goto-projects ()
    "Open projects dir"
    (interactive)
    (require 'ranger)
    (find-file "~/projects"))

Reveal in Finder

(defun browse-file-directory ()
  "Open the current file's directory however the OS would."
  (interactive)
  (if default-directory
      (browse-url-of-file (expand-file-name default-directory))
    (error "No `default-directory' to open")))

Search directories with ag

(defun cpm/helm-files-do-ag (&optional dir)
      "Search in files with `ag' using a default input."
      (interactive)
      (helm-do-ag dir))

Jump in buffer

I got this from the spacemacs config. Useful for navigating in tagged buffers.

(defun jump-in-buffer ()
  (interactive)
  (cond
   ((eq major-mode 'org-mode)
    (call-interactively 'helm-org-in-buffer-headings))
   (t
    (call-interactively 'helm-semantic-or-imenu))))

Jump to sexp

(defun forward-or-backward-sexp (&optional arg)
  "Go to the matching parenthesis character if one is adjacent to point."
  (interactive "^p")
  (cond ((looking-at "\\s(") (forward-sexp arg))
        ((looking-back "\\s)" 1) (backward-sexp arg))
        ;; Now, try to succeed from inside of a bracket
        ((looking-at "\\s)") (forward-char) (backward-sexp arg))
        ((looking-back "\\s(" 1) (backward-char) (forward-sexp arg))))

Goto journal

(defun goto-journal ()
  (interactive)
  (find-file "/Users/Roambot/Dropbox/journal.org"))

Kill all other buffers

Kill all the buffers except *scratch* buffer

(defun kill-other-buffers ()
    "Kill all other buffers."
    (interactive)
    (mapc 'kill-buffer (delq (current-buffer) (buffer-list))))
;; (defun nuke-all-buffers ()
;; "Kill all buffers, leaving *scratch* only."
;; (interactive)
;; (mapcar (lambda (x) (kill-buffer x)) (buffer-list))
;; (delete-other-windows))

Eval emacs buffer until error

(defun eval-buffer-until-error ()
"Evaluate emacs buffer until error occured."
(interactive)
(goto-char (point-min))
(while t (eval (read (current-buffer)))))

Timestamps

The code below sets the correct value for system-time-locale, and binds keys for insert-date/long and insert-date/short. Courtesy of emacs-hacks.

  (defun format-date (format)
  (let ((system-time-locale "en_US.UTF-8"))
    (insert (format-time-string format))))

(defun insert-date ()
  (interactive)
  (format-date "%A, %B %d %Y"))

(defun insert-date-and-time ()
  (interactive)
  (format-date "%Y-%m-%d %H:%M:%S"))

Reveal to PDF

(defun reveal-to-pdf ()
"print reveal.js slides to pdf"
(interactive)
(async-shell-command "phantomjs /Users/Roambot/bin/print-pdf.js 'file:///Users/Roambot/projects/phil101/content/slides/lecture_outline.html?print-pdf'")) 

Other functions

Most of these are from the spacemacs distribution.

;; Regexp for useful and useless buffers for smarter buffer switching, from spacemacs

(defvar spacemacs-useless-buffers-regexp '("*\.\+")
  "Regexp used to determine if a buffer is not useful.")
(defvar spacemacs-useful-buffers-regexp '("\\*\\(scratch\\|terminal\.\+\\|ansi-term\\|eshell\\)\\*")
  "Regexp used to define buffers that are useful despite matching
`spacemacs-useless-buffers-regexp'.")

(defun spacemacs/useless-buffer-p (buffer)
  "Determines if a buffer is useful."
  (let ((buf-paren-major-mode (get (with-current-buffer buffer
                                     major-mode)
                                   'derived-mode-parent))
        (buf-name (buffer-name buffer)))
    ;; first find if useful buffer exists, if so returns nil and don't check for
    ;; useless buffers. If no useful buffer is found, check for useless buffers.
    (unless (cl-loop for regexp in spacemacs-useful-buffers-regexp do
                     (when (or (eq buf-paren-major-mode 'comint-mode)
                               (string-match regexp buf-name))
                       (return t)))
      (cl-loop for regexp in spacemacs-useless-buffers-regexp do
               (when (string-match regexp buf-name)
                 (return t))))))

(defun spacemacs/next-useful-buffer ()
  "Switch to the next buffer and avoid special buffers."
  (interactive)
  (let ((start-buffer (current-buffer)))
    (next-buffer)
    (while (and (spacemacs/useless-buffer-p (current-buffer))
                (not (eq (current-buffer) start-buffer)))
      (next-buffer))))

(defun spacemacs/previous-useful-buffer ()
  "Switch to the previous buffer and avoid special buffers."
  (interactive)
  (let ((start-buffer (current-buffer)))
    (previous-buffer)
    (while (and (spacemacs/useless-buffer-p (current-buffer))
                (not (eq (current-buffer) start-buffer)))
      (previous-buffer))))

;; from magnars
(defun spacemacs/rename-current-buffer-file ()
  "Renames current buffer and file it is visiting."
  (interactive)
  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (error "Buffer '%s' is not visiting a file!" name)
      (let ((new-name (read-file-name "New name: " filename)))
        (cond ((get-buffer new-name)
               (error "A buffer named '%s' already exists!" new-name))
              (t
               (let ((dir (file-name-directory new-name)))
                 (when (and (not (file-exists-p dir)) (yes-or-no-p (format "Create directory '%s'?" dir)))
                   (make-directory dir t)))
               (rename-file filename new-name 1)
               (rename-buffer new-name)
               (set-visited-file-name new-name)
               (set-buffer-modified-p nil)
               (when (fboundp 'recentf-add-file)
                   (recentf-add-file new-name)
                   (recentf-remove-if-non-kept filename))
               (message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name))))))))

;; from magnars
(defun spacemacs/delete-current-buffer-file ()
  "Removes file connected to current buffer and kills buffer."
  (interactive)
  (let ((filename (buffer-file-name))
        (buffer (current-buffer))
        (name (buffer-name)))
    (if (not (and filename (file-exists-p filename)))
        (ido-kill-buffer)
      (when (yes-or-no-p "Are you sure you want to delete this file? ")
        (delete-file filename t)
        (kill-buffer buffer)
        (message "File '%s' successfully removed" filename)))))
      
;; found at http://emacswiki.org/emacs/KillingBuffers
(defun spacemacs/kill-other-buffers ()
  "Kill all other buffers."
  (interactive)
  (when (yes-or-no-p (format "Killing all buffers except \"%s\"? " (buffer-name)))
    (mapc 'kill-buffer (delq (current-buffer) (buffer-list)))
    (message "Buffers deleted!")))

;; http://camdez.com/blog/2013/11/14/emacs-show-buffer-file-name/
(defun spacemacs/show-and-copy-buffer-filename ()
  "Show the full path to the current file in the minibuffer."
  (interactive)
  (let ((file-name (buffer-file-name)))
    (if file-name
        (progn
          (message file-name)
          (kill-new file-name))
      (error "Buffer not visiting a file"))))

(defun spacemacs/new-empty-buffer ()
  "Create a new buffer called untitled(<n>)"
  (interactive)
  (let ((newbuf (generate-new-buffer-name "untitled")))
    (switch-to-buffer newbuf)))

;; from https://github.com/gempesaw/dotemacs/blob/emacs/dg-defun.el
(defun spacemacs/kill-matching-buffers-rudely (regexp &optional internal-too)
  "Kill buffers whose name matches the specified REGEXP. This
function, unlike the built-in `kill-matching-buffers` does so
WITHOUT ASKING. The optional second argument indicates whether to
kill internal buffers too."
  (interactive "sKill buffers matching this regular expression: \nP")
  (dolist (buffer (buffer-list))
    (let ((name (buffer-name buffer)))
      (when (and name (not (string-equal name ""))
                 (or internal-too (/= (aref name 0) ?\s))
                 (string-match regexp name))
        (kill-buffer buffer)))))

;; http://stackoverflow.com/a/10216338/4869
(defun spacemacs/copy-whole-buffer-to-clipboard ()
  "Copy entire buffer to clipboard"
  (interactive)
  (clipboard-kill-ring-save (point-min) (point-max)))

(defun spacemacs/copy-clipboard-to-whole-buffer ()
  "Copy clipboard and replace buffer"
  (interactive)
  (delete-region (point-min) (point-max))
  (clipboard-yank)
  (deactivate-mark))

(defun spacemacs/copy-file ()
  "Write the file under new name."
  (interactive)
  (call-interactively 'write-file))

Macros

These are a few useful macros I got from hlissner’s “doom” .emacs.d

(defmacro after! (feature &rest forms)
  "A smart wrapper around `with-eval-after-load', that supresses warnings
during compilation."
  (declare (indent defun) (debug t))
  `(,(if (or (not (boundp 'byte-compile-current-file))
             (not byte-compile-current-file)
             (if (symbolp feature)
                 (require feature nil :no-error)
               (load feature :no-message :no-error)))
         'progn
       (message "after: cannot find %s" feature)
       'with-no-warnings)
    (with-eval-after-load ',feature ,@forms)))

(defmacro add-hook! (hook &rest func-or-forms)
  "A convenience macro for `add-hook'.
HOOK can be one hook or a list of hooks. If the hook(s) are not quoted, -hook is
appended to them automatically. If they are quoted, they are used verbatim.
FUNC-OR-FORMS can be a quoted symbol, a list of quoted symbols, or forms. Forms will be
wrapped in a lambda. A list of symbols will expand into a series of add-hook calls.
Examples:
    (add-hook! 'some-mode-hook 'enable-something)
    (add-hook! some-mode '(enable-something and-another))
    (add-hook! '(one-mode-hook second-mode-hook) 'enable-something)
    (add-hook! (one-mode second-mode) 'enable-something)
    (add-hook! (one-mode second-mode) (setq v 5) (setq a 2))"
  (declare (indent defun) (debug t))
  (unless func-or-forms
    (error "add-hook!: FUNC-OR-FORMS is empty"))
  (let* ((val (car func-or-forms))
         (quoted (eq (car-safe hook) 'quote))
         (hook (if quoted (cadr hook) hook))
         (funcs (if (eq (car-safe val) 'quote)
                    (if (cdr-safe (cadr val))
                        (cadr val)
                      (list (cadr val)))
                  (list func-or-forms)))
         (forms '()))
    (mapc
     (lambda (f)
       (let ((func (cond ((symbolp f) `(quote ,f))
                         (t `(lambda (&rest _) ,@func-or-forms)))))
         (mapc
          (lambda (h)
            (push `(add-hook ',(if quoted h (intern (format "%s-hook" h))) ,func) forms))
          (-list hook)))) funcs)
    `(progn ,@forms)))
    
;;;###autoload
(defmacro def-popup! (&rest params)
  `(push ',params shackle-rules))

Packages

General

A convenient way to bind keys. Compatible with evil. For helpful discussion of setting up evil with general see this post.

(use-package general
  :config
  (general-create-definer cpm-leader1 
    :states '(normal insert visual motion emacs) 
    :keymaps 'global 
    :prefix "SPC" 
    :non-normal-prefix "C-SPC"))

Evil Mode

I’m coming from vim, and want modal keybidings in emacs. There are other, less radical ways of getting modal editing in emacs. For example, modalka is a nice package for modal editing (see also ryo-modal). But nothing beats full vim keybindings. And that is what evil is for.

Evil mode

The essential stuff

(use-package evil
  :ensure t
  :config
  (progn
  ;; Cursor shape and color
    (defcustom dotemacs-evil/emacs-cursor
    "red"
    "The color of the cursor when in Emacs state."
    :type 'color
    :group 'dotemacs-evil)

    (defcustom dotemacs-evil/emacs-insert-mode
    nil
    "If non-nil, insert mode will act as Emacs state."
    :type 'boolean
    :group 'dotemacs-evil)

    (setq evil-search-module 'evil-search)
    (setq evil-magic 'very-magic)

    (setq evil-emacs-state-cursor `(,dotemacs-evil/emacs-cursor box))
    (setq evil-normal-state-cursor '("DarkGoldenrod2" box))
    (setq evil-visual-state-cursor '("gray" box)) 
    (setq evil-insert-state-cursor '("chartreuse3" (bar . 2)))
    (setq evil-replace-state-cursor '("red" hbar))
    (setq evil-operator-state-cursor '("red" hollow))
    (setq evil-visual-state-tag "VISUAL")
    
    ;; evil-normal-state is preferred, so revert when idle
    (run-with-idle-timer 20 t 'evil-normal-state)
    ;; don't echo evil state
    (setq evil-echo-state nil)
    ;; evil everywhere
    (evil-mode 1)))

Evil escape

Use a key sequence for escaping.

(use-package evil-escape
  :ensure t
  :diminish ""
  :init
  (evil-escape-mode)
  ;; use "fd" for escape
  (setq-default evil-escape-key-sequence "fd"))

Evil packages & settings

There are some other useful setup packages for evil

Navigate Using Visual Lines Rather Than True Lines
(general-define-key 
  :states '(normal visual)
  "j" 'evil-next-visual-line
  "k" 'evil-previous-visual-line)
Evil indent
(use-package evil-indent-textobject :commands (evil-indent))
Increment And Decrement Numbers
(use-package evil-numbers
  :ensure t
  :commands (evil-numbers/inc-at-pt evil-numbers/dec-at-pt)
  :init
  (general-define-key
    :states '(normal visual insert emacs)
    "H-s" 'evil-numbers/inc-at-pt
    "H-a" 'evil-numbers/dec-at-pt))
Change Cursor In Terminal
(defun my-send-string-to-terminal (string)
  (unless (display-graphic-p) (send-string-to-terminal string)))

(defun my-evil-terminal-cursor-change ()
  (when (string= (getenv "TERM_PROGRAM") "iTerm.app")
    (add-hook 'evil-insert-state-entry-hook (lambda () (my-send-string-to-terminal "\e]50;CursorShape=1\x7")))
    (add-hook 'evil-insert-state-exit-hook  (lambda () (my-send-string-to-terminal "\e]50;CursorShape=0\x7"))))
  (when (and (getenv "TMUX") (string= (getenv "TERM_PROGRAM") "iTerm.app"))
    (add-hook 'evil-insert-state-entry-hook (lambda () (my-send-string-to-terminal "\ePtmux;\e\e]50;CursorShape=1\x7\e\\")))
    (add-hook 'evil-insert-state-exit-hook  (lambda () (my-send-string-to-terminal "\ePtmux;\e\e]50;CursorShape=0\x7\e\\")))))

(add-hook 'after-make-frame-functions (lambda (frame) (my-evil-terminal-cursor-change)))
(my-evil-terminal-cursor-change)

  (use-package evil-terminal-cursor-changer
    :ensure t
    :disabled t
    :defer t
    :init
     (unless (display-graphic-p)
             (require 'evil-terminal-cursor-changer)
    (progn 
     (setq evil-visual-state-cursor '("red" box));
     (setq evil-insert-state-cursor '("green" bar));
     (setq evil-emacs-state-cursor '("blue" hbar)); _
     )))
Evil Surround Commands Like Vim-Surround
(use-package evil-surround
  :ensure t
  ;; :defer 2
  :commands (evil-surround-region evil-surround-change)
  :init 
  (general-define-key
  :states '(visual)
  "s" 'evil-surround-region
  "S" 'evil-substitute)
  :config (global-evil-surround-mode 1))

(use-package embrace
 :ensure t)
(use-package evil-embrace
 :ensure t
 :config
 (evil-embrace-enable-evil-surround-integration)
 (setq evil-embrace-show-help-p nil)
 (add-hook 'org-mode-hook 'embrace-org-mode-hook)
 (add-hook 'text-mode-hook
    (lambda () 
        (embrace-add-pair ?$ "$" "$")))
 (add-hook 'LaTeX-mode-hook
    (lambda ()
        (embrace-add-pair ?a "`" "'")
        (embrace-add-pair ?e "\\emph{" "}"))))
Evil-Avy

Use evil motions with avy

(use-package evil-avy
  :after avy 
)
Commenting
(use-package evil-commentary
  :commands (evil-commentary evil-commentary-line)
  :diminish evil-commentary-mode
  :config
  (evil-commentary-mode))
Graphical undo
(use-package undo-tree
  :commands (undo-tree-undo undo-tree-visualize)
  :init
  ;; (global-undo-tree-mode)
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-visualizer-diff t)
  (let ((undo-dir (concat user-cache-directory "undo")))
    (setq undo-tree-history-directory-alist '((".*" . ,undo-dir)))))

;; (use-package undo-tree
;;   :ensure t
;;   :init
;;   (progn
;;     (global-undo-tree-mode)
;;     (setq undo-tree-mode-lighter "")
;;     ;; (setq undo-tree-auto-save-history t)
;;     (setq undo-tree-visualizer-timestamps t)
;;     (setq undo-tree-visualizer-diff t)
;;     (let ((undo-dir (concat user-cache-directory "undo")))
;;     (setq undo-tree-history-directory-alist `((".*" . ,undo-dir)))))
;;   )

Persistent Scratch

Make the content of the scratch buffer persist between settings

(use-package persistent-scratch
  :config
 (setq persistent-scratch-backup-directory (concat user-cache-directory "scratch-backups"))
 (setq persistent-scratch-save-file (concat user-cache-directory "persistent-scratch"))
 ;; keep backups not older than a month
 (setq persistent-scratch-backup-filter
    (persistent-scratch-keep-backups-not-older-than
     (days-to-time 90)))
  (persistent-scratch-setup-default)
  (persistent-scratch-autosave-mode)
)

Projectile

(use-package projectile
  ;; :commands (projectile-ack
  ;;            projectile-ag
  ;;            projectile-compile-project
  ;;            projectile-dired
  ;;            projectile-find-dir
  ;;            projectile-find-file
  ;;            projectile-find-tag
  ;;            projectile-find-test-file
  ;;            projectile-grep
  ;;            projectile-invalidate-cache
  ;;            projectile-kill-buffers
  ;;            projectile-multi-occur
  ;;            projectile-project-p
  ;;            projectile-project-root
  ;;            projectile-recentf
  ;;            projectile-regenerate-tags
  ;;            projectile-replace
  ;;            projectile-run-async-shell-command-in-root
  ;;            projectile-run-shell-command-in-root
  ;;            projectile-switch-project
  ;;            projectile-switch-to-buffer
  ;;            projectile-vc)
  :init
  ;; save projectile-known-projects-file in cache folder
  (setq projectile-known-projects-file
     (concat user-cache-directory "projectile-bookmarks.eld"))
  (setq projectile-cache-file
     (concat user-cache-directory "projectile.cache"))
  (setq projectile-enable-caching t)
  :config
  (projectile-global-mode t))

Restart emacs

(use-package restart-emacs
  :commands restart-emacs)

Ranger & Deer

Better dired navigation using ranger-like settings

(use-package ranger
  :commands (ranger deer deer-jump-other-window)
  :init
  (setq ranger-override-dired t
        ranger-cleanup-eagerly t)
  ;; set up image-dired to allow picture resize
  (setq image-dired-dir (concat user-cache-directory "image-dir"))
  (unless (file-directory-p image-dired-dir)
    (make-directory image-dired-dir))
  :config
  (setq  ranger-dont-show-binary t
         ranger-excluded-extensions '("mkv" "iso" "mp4")
         ranger-max-preview-size 25
         ranger-preview-file t
         ranger-show-dotfiles t
         ranger-width-parents 0.25
         ranger-width-preview 0.55 
         ))

;; (defun deer-jump-other-window (&optional path)
;;   "Launch dired in a minimal ranger window in other window."
;;   (interactive)
;;   (switch-to-buffer-other-window (current-buffer))
;;   (deer path))

Recent files

(use-package recentf
  :defer 2
  :init
  (setq recentf-save-file (expand-file-name "recentf" user-cache-directory)))

Helm

Helm is a robust and well-designed completion framework. It can do quite a lot.

Helm Settings

(use-package helm
  :diminish (helm-mode . "")
  :defer 1
  :init
  (setq helm-locate-fuzzy-match nil
        helm-locate-command "locate %s -e -A --regex %s")
  :config
  (progn
    ;; Use helm to provide :ls, unless ibuffer is used
    (evil-ex-define-cmd "buffers" 'helm-buffers-list)
    (setq helm-M-x-fuzzy-match t  ;; Use fuzzy match in helm
          helm-apropos-fuzzy-match t
          helm-buffers-fuzzy-matching t
          helm-imenu-fuzzy-match t
          helm-recentf-fuzzy-match t
          helm-prevent-escaping-from-minibuffer t
          helm-bookmark-show-location t
          helm-ff-file-name-history-use-recentf t
          helm-find-files-sort-directories t
          helm-display-header-line nil
          helm-move-to-line-cycle-in-source nil
          helm-always-two-windows t                       
          helm-split-window-in-side-p nil
          ;; helm-split-window-default-side 'other
          helm-echo-input-in-header-line t)
    ;;keybindings
    (general-define-key "M-x" 'helm-M-x)
    ;;; helm vim-bindings in buffer ;;
    (define-key helm-map (kbd "C-a") (kbd "RET"))
    (general-define-key :keymaps 'helm-map 
      "TAB"   'helm-execute-persistent-action ; rebind tab to do persistent action
      "C-i"   'helm-execute-persistent-action ; make TAB works in terminal
      "C-z"   'helm-select-action ; list actions using C-z
      "C-j"   'helm-next-line
      "C-k"   'helm-previous-line
      "C-h"   'helm-next-source
      "C-l"   'helm-previous-source
      "C-S-h" 'describe-key)
    (setq helm-boring-buffer-regexp-list '("\\*SPEEDBAR" "\\*magit" "\\*Sunshine" "\\*Help" "\\*Shell Command Output" "\\*Flycheck error message" "\\*Compile-Log" "\\` " "\\*helm" "\\*helm-mode" "\\*Echo Area" "\\*Minibuf"))
    (helm-autoresize-mode 1)
    (setq helm-autoresize-max-height 40)
    (setq helm-autoresize-min-height 35)
    ;; helm selection faces
    ;; (set-face-attribute 'helm-selection nil
    ;;     :foreground "#f7f438"
    ;;     :background "#64b5ea"
    ;;     :underline nil
    ;;     :weight 'bold))
    (helm-mode 1)
    ))

Hide Mode Lines

Hide modelines of other windows while helm is open, again from https://github.com/hatschipuh/better-helm.

 (defvar my-helm-bottom-buffers nil
	"List of bottom buffers before helm session.
	Its element is a pair of `buffer-name' and `mode-line-format'.")

 (defun my-helm-bottom-buffers-init ()
	(setq-local mode-line-format (default-value 'mode-line-format))
	(setq my-helm-bottom-buffers
	  (cl-loop for w in (window-list)
		   when (window-at-side-p w 'bottom)
		   collect (with-current-buffer (window-buffer w)
				 (cons (buffer-name) mode-line-format)))))

 (defun my-helm-bottom-buffers-hide-mode-line ()
	(setq-default cursor-in-non-selected-windows nil)
	(mapc (lambda (elt)
		(with-current-buffer (car elt)
		  (setq-local mode-line-format nil)))
	  my-helm-bottom-buffers))

 (defun my-helm-bottom-buffers-show-mode-line ()
	(setq-default cursor-in-non-selected-windows t)
	(when my-helm-bottom-buffers
	  (mapc (lambda (elt)
		  (with-current-buffer (car elt)
		(setq-local mode-line-format (cdr elt))))
		my-helm-bottom-buffers)
	  (setq my-helm-bottom-buffers nil)))

 (defun my-helm-keyboard-quit-advice (orig-func &rest args)
	(my-helm-bottom-buffers-show-mode-line)
	(apply orig-func args))

 (add-hook 'helm-before-initialize-hook #'my-helm-bottom-buffers-init)
 (add-hook 'helm-after-initialize-hook #'my-helm-bottom-buffers-hide-mode-line)
 (add-hook 'helm-exit-minibuffer-hook #'my-helm-bottom-buffers-show-mode-line)
 (add-hook 'helm-cleanup-hook #'my-helm-bottom-buffers-show-mode-line)
 (advice-add 'helm-keyboard-quit :around #'my-helm-keyboard-quit-advice)

Hide Minibuffer

Hide minibuffer while helm is active

 (defun my-helm-hide-minibuffer-maybe ()
	(when (with-helm-buffer helm-echo-input-in-header-line)
	  (let ((ov (make-overlay (point-min) (point-max) nil nil t)))
	(overlay-put ov 'window (selected-window))
	(overlay-put ov 'face (let ((bg-color (face-background 'default nil)))
				`(:background ,bg-color :foreground ,bg-color)))
	(setq-local cursor-type nil))))
 (add-hook 'helm-minibuffer-set-up-hook #'helm-hide-minibuffer-maybe)

Helm packages

Helm ag
(use-package helm-ag  
  :commands (helm-ag helm-ag-buffers helm-ag-this-file helm-do-ag helm-ag-project-root)
  :config
  (setq helm-ag-base-command "rg --no-heading")
  (setq helm-ag-fuzzy-match t))
Helm descbinds
(use-package helm-descbinds 
  :defer t
  :config
  (setq helm-descbinds-window-style 'same-window)
  (add-hook 'helm-mode-hook 'helm-descbinds-mode))
Helm git list
(use-package helm-ls-git :defer t)
Helm hunks
(use-package helm-hunks
  :commands helm-hunks)
Helm swoop

Search on steroids

(use-package helm-swoop
  :commands (helm-swoop helm-swoop-back-to-last-point helm-multi-swoop helm-multi-swoop-all)
  :config
  (setq helm-swoop-use-fuzzy-match t)
  (setq helm-swoop-split-with-multiple-windows t))
Helm flyspell

Use helm with flyspell

(use-package helm-flyspell
  :if (not noninteractive)
  :ensure t
  :commands helm-flyspell-correct
  :config
  (bind-key "C-;" 'helm-flyspell-correct flyspell-mode-map)
)
Helm Flx
(use-package helm-flx
  :after helm
  :config
  (setq helm-flx-for-helm-find-files t ;; t by default
        helm-flx-for-helm-locate t) ;; nil by default
 )
Helm recent directories

Recent directories

(use-package helm-dired-recent-dirs
  :defer t)
Helm files
(use-package helm-files
  :ensure nil
  :config
  (setq helm-ff-skip-boring-files t)
  (setq helm-idle-delay 0.05)
  (setq helm-input-idle-delay 0.05)
  (setq helm-ff-file-name-history-use-recentf t)
  (setq helm-boring-file-regexp-list
  '("\\.git$" "\\.hg$" "\\.svn$" "\\.CVS$" "\\._darcs$" "\\.la$" "\\.o$" "~$"
    "\\.so$" "\\.a$" "\\.elc$" "\\.fas$" "\\.fasl$" "\\.pyc$" "\\.pyo$")))
Helm-projectile
(use-package helm-projectile
  :commands (helm-projectile-switch-to-buffer
             helm-projectile-find-dir
             helm-projectile-dired-find-dir
             helm-projectile-recentf
             helm-projectile-find-file
             helm-projectile-grep
             helm-projectile
             helm-projectile-switch-project)
  :init
  (setq projectile-switch-project-action 'helm-projectile))
Helm interface for themes (helm-themes)
(use-package helm-themes
  :commands helm-themes)
(defadvice helm-themes--load-theme (after helm-themes--load-theme-after activate) (require 'powerline) (powerline-reset)) 
;; (ad-unadvise 'helm-themes--load-theme)

Windows

Window Numbering

Numbered window shortcuts for Emacs

 (use-package window-numbering
   :ensure t
   :config
   (defun window-numbering-install-mode-line (&optional position)
   "Do nothing, the display is handled by the powerline.")
   (setq window-numbering-auto-assign-0-to-minibuffer nil)
   (cpm-leader1
     "0" 'select-window-0
     "1" 'select-window-1
     "2" 'select-window-2
     "3" 'select-window-3
     "4" 'select-window-4
     "5" 'select-window-5)
     ;; "6" 'select-window-6
     ;; "7" 'select-window-7
     ;; "8" 'select-window-8
     ;; "9" 'select-window-9)
   (window-numbering-mode 1)

;; make sure neotree is always 0
 (defun spacemacs//window-numbering-assign ()
   "Custom number assignment for neotree."
   (when (and (boundp 'neo-buffer-name)
              (string= (buffer-name) neo-buffer-name)
              ;; in case there are two neotree windows. Example: when
              ;; invoking a transient state from neotree window, the new
              ;; window will show neotree briefly before displaying the TS,
              ;; causing an error message. the error is eliminated by
              ;; assigning 0 only to the top-left window
              (eq (selected-window) (window-at 0 0)))
     0))

 ;; using lambda to work-around a bug in window-numbering, see
 ;; https://github.com/nschum/window-numbering.el/issues/10
 (setq window-numbering-assign-func
       (lambda () (spacemacs//window-numbering-assign))))

  ;; (defun spacemacs//window-numbering-assign (windows)
  ;;   "Custom number assignment for special buffers."
  ;;   (mapc (lambda (w)
  ;;           (when (and (boundp 'neo-global--window)
  ;;                      (eq w neo-global--window))
  ;;             (window-numbering-assign w 0)))
  ;;         windows))
  ;; (add-hook 'window-numbering-before-hook 'spacemacs//window-numbering-assign)
  ;; (add-hook 'neo-after-create-hook '(lambda (w) (window-numbering-update)))

Windmove

(use-package windmove
  :commands (windmove-up windmove-down windmove-left windmove-right)
  :config
  (defun split-window-right-and-focus ()
  "Split the window horizontally and focus the new window."
  (interactive)
  (split-window-right)
  (windmove-right))
  (defun split-window-below-and-focus ()
  "Split the window vertically and focus the new window."
  (interactive)
  (split-window-below)
  (windmove-down))
  ;; add edit mode keybindings
  (global-set-key (kbd "<H-up>")     'windmove-up)
  (global-set-key (kbd "<H-down>")   'windmove-down)
  (global-set-key (kbd "<H-left>")   'windmove-left)
  (global-set-key (kbd "<H-right>")  'windmove-right)
  )

Autorevert

Auto-revert buffers of changed files

(use-package autorevert                 
  :defer 2
  :ensure nil
  :init
  (global-auto-revert-mode 1)
  :config
  (progn 
    (setq auto-revert-verbose nil ; Shut up, please!
          revert-without-query '(".*") ;; disable revert query
          ;; Revert Dired buffers, too
          global-auto-revert-non-file-buffers t)))

Appearance & UI

Various settings to make Emacs (mostly the GUI version) look better or make interaction smoother.

Appearance

Frame startup size and position

I like the frame centered and approximately 2/3 of a 13inch laptop screen.

;; Set Frame width/height
(setq default-frame-alist
      '((top . 25) (left . 275) (width . 105) (height . 60)))

Name frame

Show the filepath in the frame title.

(setq frame-title-format
      '(" "
      (buffer-file-name "%f"
      (dired-directory dired-directory "%b"))))

Get rid of UI cruft

Turn off all of the GUI cruft.

;; Turn off mouse interface early in startup to avoid momentary display
(when (display-graphic-p)
  (menu-bar-mode -1)
  (tool-bar-mode -1)
  (scroll-bar-mode -1)
  (tooltip-mode -1))

No menu bar in terminal

Ditto for the terminal.

(when (not (display-graphic-p))
  (menu-bar-mode -1))

Font

Inconsolata is a nice monospaced font.

To install it on OS X, you can use Homebrew with Homebrew Cask.

# You may need to run these two lines if you haven't set up Homebrew
# Cask and its fonts formula.
brew install caskroom/cask/brew-cask
brew tap caskroom/fonts
brew cask install font-inconsolata

And here’s how we tell Emacs to use the font we want to use.

;; deal with fonts [[https://github.com/rolandwalker/dynamic-fonts][dynamically]]. 
(use-package dynamic-fonts
  :config (dynamic-fonts-setup) 
   :init
   (progn (setq dynamic-fonts-preferred-proportional-fonts
                '("Cantarell" "Source Sans Pro" "Helvetica"))
          (setq dynamic-fonts-preferred-monospace-fonts
             '("Inconsolata LGC for Powerline" "Source Code Pro" "Monaco" "Consolas" "Menlo"
               "DejaVu Sans Mono" "Droid Sans Mono Pro" "Droid Sans Mono")))
)
  (global-set-key (kbd "C-+") 'text-scale-increase)
  (global-set-key (kbd "C--") 'text-scale-decrease)
  ;; C-x C-0 restores the default font size

Modeline

Spaceline

This is a really nice powerline-ish modeline.

(use-package spaceline
  :ensure t
  :init 
  (progn 
    ;; size of modeline
    (setq powerline-height 21)
    (setq spaceline-highlight-face-func 'spaceline-highlight-face-evil-state)
    ;; (setq-default powerline-default-separator nil) 
    ;; (setq-default powerline-default-separator 'utf-8) 
    ;; (setq powerline-utf-8-separator-left #xe0b0)
    ;; (setq powerline-utf-8-separator-right #xe0b2)
    ;; (set-face-attribute 'mode-line nil :font "Source Code Pro-14")

    ;; small triangles
    ;; (setq powerline-utf-8-separator-left #x25ba)
    ;; (setq powerline-utf-8-separator-right #x25c4)
    ;; (setq powerline-text-scale-factor .3)
    ;; half circles
    ;; (setq powerline-utf-8-separator-left 9687 
    ;;       powerline-utf-8-separator-right 9686)

    ;; slant (requires srbg support)
    (setq-default powerline-default-separator 'slant) 
    (setq spaceline-separator-dir-left '(right . right))
    (setq spaceline-separator-dir-right '(right . right))

    ;; fancy git icon for the modeline
    (defadvice vc-mode-line (after strip-backend () activate)
    (when (stringp vc-mode)
      (let ((gitlogo (replace-regexp-in-string "^ Git." ":" vc-mode)))
            (setq vc-mode gitlogo)))))
  :config
  (require 'spaceline-config)
  (spaceline-toggle-buffer-size-off)
  (spaceline-spacemacs-theme)
  (setq spaceline-buffer-encoding-abbrev-p nil
        spaceline-window-numbers-unicode t
        spaceline-line-column-p nil
        spaceline-buffer-id-p nil
        spaceline-minor-modes-separator " "))
        (powerline-reset)
;; nil - don't use srgb & get proper powerline faces
(setq ns-use-srgb-colorspace t)

Fancy Battery

(use-package fancy-battery
  :init 
  (fancy-battery-mode)
  :config
  (setq-default battery-update-interval 10))
  ;; :config
  ;; (set-face-attribute 'fancy-battery-charging nil 
  ;; :foreground "dark blue" :weight 'bold)
  ;; (set-face-attribute 'fancy-battery-discharging nil 
  ;; :foreground "dark magenta" :weight 'bold)
  ;; (set-face-attribute 'fancy-battery-critical nil 
  ;; :foreground "dark red" :weight 'bold))

Display Time

(setq display-time-format " %a %b %d | %H:%M |")
(display-time-mode)

Hide mode line

Hide mode line. From http://bzg.fr/emacs-hide-mode-line.html

(defvar-local hidden-mode-line-mode nil)
(defvar-local hide-mode-line nil)
(define-minor-mode hidden-mode-line-mode
  "Minor mode to hide the mode-line in the current buffer."
  :init-value nil
  :global t
  :variable hidden-mode-line-mode
  :group 'editing-basics
  (if hidden-mode-line-mode
      (setq hide-mode-line mode-line-format
            mode-line-format nil)
    (setq mode-line-format hide-mode-line
          hide-mode-line nil))
  (force-mode-line-update)
  ;; Apparently force-mode-line-update is not always enough to
  ;; redisplay the mode-line
  (redraw-display)
  (when (and (called-interactively-p 'interactive)
             hidden-mode-line-mode)
    (run-with-idle-timer
     0 nil 'message
     (concat "Hidden Mode Line Mode enabled.  "
             "Use M-x hidden-mode-line-mode to make the mode-line appear."))))

Theme

Solarized

The best low-contrast theme out there.

(use-package solarized-theme
  :ensure t
  :if (display-graphic-p)
  :init
    (progn
        ;; don't make the fringe stand out from the background
        (setq solarized-distinct-fringe-background nil)

        ;; change the font for some headings and titles
        (setq solarized-use-variable-pitch t)

        ;; make the modeline high contrast
        (setq solarized-high-contrast-mode-line t)

        ;; Use bolding
        (setq solarized-use-less-bold nil)

        ;; Use more italics
        (setq solarized-use-more-italic t)

        ;; Use colors for indicators such as git:gutter, flycheck and similar
        (setq solarized-emphasize-indicators t)

        ;; Don't change size of org-mode headlines (but keep other size-changes)
        (setq solarized-scale-org-headlines t)

        ;; don't italicize line numbers
        ;; (add-hook 'after-make-frame-functions
        ;; (lambda (frame)
        ;; (select-frame frame)
        ;; (if (display-graphic-p)
        ;; (set-face-attribute 'linum frame
        ;; :background (face-attribute 'default :background)
        ;; :foreground (face-attribute 'linum :foreground) :slant 'normal))))

        ;; Theme toggle
        (setq active-theme 'solarized-dark)
        (defun toggle-dark-light-theme ()
        (interactive)
        (if (eq active-theme 'solarized-light)
            (setq active-theme 'solarized-dark)
          (setq active-theme 'solarized-light))
        (load-theme active-theme)
        (powerline-reset))
        )
        :config
         (progn
           (defvar after-load-theme-hook nil
             "Hook run after a color theme is loaded using `load-theme'.")
           (defadvice load-theme (after run-after-load-theme-hook activate)
             "Run `after-load-theme-hook'."
             (run-hooks 'after-load-theme-hook))
           (defun customize-solarized-dark ()
             "Customize solarized theme"
             (if (member 'solarized-dark custom-enabled-themes)
                 (custom-theme-set-faces
                 'solarized-dark
                 ;; org faces
                 '(org-block ((t (:foreground "#2E8B57"))))
                 '(org-block-begin-line ((t (:foreground "#74a8a4" :weight bold :slant normal))))
                 '(org-level-1 ((t (:inherit variable-pitch :foreground "#268bd2" :height 1.5))))
                 '(org-level-2 ((t (:inherit variable-pitch :foreground "medium sea green" :height 1.3))))
                 '(org-level-3 ((t (:inherit variable-pitch :foreground "#cb4b16" :height 1.2))))
                 '(org-level-8 ((t (:inherit variable-pitch :foreground "#9e1e86" :height 1.1))))
                 '(org-quote ((t (:inherit org-block :slant normal :weight normal))))
                 ;; markdown faces
                 '(markdown-comment-face ((t (:weight normal :slant italic :strike-through nil))))
                 '(markdown-header-face-1 ((t (:inherit variable-pitch :foreground "#268bd2" :height 1.75))))
                 '(markdown-header-face-2 ((t (:inherit variable-pitch :foreground "medium sea green" :height 1.45))))
                 '(markdown-header-face-3 ((t (:inherit variable-pitch :foreground "#cb4b16" :height 1.2))))
                 ;; helm faces
                 '(helm-selection ((t (:foreground "#f7f438" :background "#64b5ea" :underline nil :weight bold))))
                 ;; line highlighting 
                  '(linum-highlight-face ((t (:inherit default :foreground "goldenrod1"))))
                 ;; battery faces
                 '(fancy-battery-charging ((t (:foreground "dark blue" :weight bold))))
                 '(fancy-battery-critical ((t (:foreground "dark red" :weight bold))))
                 '(fancy-battery-discharging ((t (:foreground "dark magenta" :weight bold)))))))

          (add-hook 'after-load-theme-hook 'customize-solarized-dark)

          (defun customize-solarized-light ()
             "Customize solarized theme"
             (if (member 'solarized-light custom-enabled-themes)
                 (custom-theme-set-faces
                 'solarized-light
                 ;; org faces
                 '(org-block ((t (:foreground "#2E8B57"))))
                 '(org-block-begin-line ((t (:foreground "#74a8a4" :weight bold :slant normal))))
                 '(org-level-1 ((t (:inherit variable-pitch :foreground "#268bd2" :height 1.3))))
                 '(org-level-2 ((t (:inherit variable-pitch :foreground "medium sea green" :height 1.2))))
                 '(org-level-3 ((t (:inherit variable-pitch :foreground "#cb4b16" :height 1.15))))
                 '(org-level-8 ((t (:inherit variable-pitch :foreground "#9e1e86" :height 1.1))))
                 '(org-quote ((t (:inherit org-block :slant normal :weight normal))))
                 ;; markdown faces
                 '(markdown-comment-face ((t (:weight normal :slant italic :strike-through nil))))
                 '(markdown-header-face-1 ((t (:inherit variable-pitch :foreground "#268bd2" :height 1.75))))
                 '(markdown-header-face-2 ((t (:inherit variable-pitch :foreground "medium sea green" :height 1.45))))
                 '(markdown-header-face-3 ((t (:inherit variable-pitch :foreground "#cb4b16" :height 1.2))))

                 ;; helm faces
                 '(helm-selection ((t (:foreground "#f7f438" :background "#64b5ea" :underline nil :weight bold))))
                 ;; line highlighting 
                  '(linum-highlight-face ((t (:inherit default :foreground "#002b36"))))
                 ;; battery faces
                 '(fancy-battery-charging ((t (:foreground "dark blue" :weight bold))))
                 '(fancy-battery-critical ((t (:foreground "dark red" :weight bold))))
                 '(fancy-battery-discharging ((t (:foreground "dark magenta" :weight bold)))))))

          (add-hook 'after-load-theme-hook 'customize-solarized-light)
          )
          (load-theme 'solarized-dark t)
          )

        ;; Avoid all font-size changes
        ;; (setq solarized-height-minus-1 1)
        ;; (setq solarized-height-plus-1 1)
        ;; (setq solarized-height-plus-2 1)
        ;; (setq solarized-height-plus-3 1)
        ;; (setq solarized-height-plus-4 1))


  ;; An alternative solarized theme
    (use-package color-theme-sanityinc-solarized
      :ensure t
      :disabled t
      :init
         (progn
            (load-theme 'sanityinc-solarized-dark t)))

Gruvbox

This is a great general-purpose theme. Use it in terminal.

(use-package gruvbox-theme
  :ensure t 
  :if (not (display-graphic-p))
  :config
  (load-theme 'gruvbox t))

Zerodark

Nice dark theme with custom modeline

(use-package zerodark-theme
  :if (display-graphic-p)
  :config
  (custom-set-faces
    '(org-block-begin-line ((t (:background "#282c34" :foreground "#98be65" :height 0.9))))
    '(org-block-end-line ((t (:background "#282c34" :foreground "#98be65" :height 0.9)))))
  (zerodark-setup-modeline-format)
  ;; (load-theme 'zerodark t)
  )

Other Themes

Make sure that other themes I like are downloaded and available

(defvar packages-appearance
  '(monokai-theme solarized-theme zenburn-theme molokai-theme darktooth-theme
                  tango-2-theme gotham-theme sublime-themes 
                  waher-theme ample-theme material-theme zerodark-theme
                  color-theme-modern leuven-theme spacemacs-theme gruvbox-theme
                  forest-blue-theme flatland-theme afternoon-theme
                  cyberpunk-theme madhat2r-theme kaolin-theme darkmine-theme tao-theme darkokai-theme jazz-theme suscolors-theme omtose-phellack-theme)
"A list of themes to ensure are installed at launch.")

(defun appearance-packages-installed-p ()
  (loop for p in packages-appearance
        when (not (package-installed-p p)) do (return nil)
        finally (return t)))

(unless (appearance-packages-installed-p)
  ;; check for new packages (package versions)
  (message "%s" "Emacs is now refreshing its package themes...")
  (package-refresh-contents)
  (message "%s" " done.")
  ;; install the missing packages
  (dolist (p packages-appearance)
    (when (not (package-installed-p p))
      (package-install p))))

(provide 'packages-appearance)

(use-package rees-themes
  :ensure nil
  :load-path "~/.emacs.d/elisp/rees-themes"
  :defer t
)

Highlight line numbers

;; line number spacing
(setq-default linum-format "%4d ")
;; Highlight current line number
(use-package hlinum
  :commands hlinum-mode
  :config
  (custom-set-faces
   '(linum-highlight-face ((t (:inherit default :foreground "goldenrod1")))))
  :init
  (add-hook 'linum-mode-hook 'hlinum-activate))

Highlight numbers

Highlight numbers in source code

(use-package highlight-numbers
  :ensure t
  :defer t 
  :init
  (add-hook 'prog-mode-hook #'highlight-numbers-mode))

Highlight TODOs

highlight TODO statements in comments

(use-package hl-todo
  :ensure t
  :defer t
  :config
  (setq global-hl-todo-mode t))

Diminish Modes

Tidy Up modeline modes.

(use-package diminish :defer 2)

Diminish minor modes

(diminish 'visual-line-mode)
(eval-after-load "flyspell" '(diminish 'flyspell-mode "")) 
(eval-after-load "abbrev" '(diminish 'abbrev-mode ""))
(eval-after-load "lispy" '(diminish 'lispy-mode "")) 
(eval-after-load "lispyville" '(diminish 'lispyville-mode "")) 
(eval-after-load "centered-window-mode" '(diminish 'centered-window-mode "⦿"))
(eval-after-load "org-indent" '(diminish 'org-indent-mode))
(eval-after-load "simple" '(diminish 'auto-fill-function "")) 
(eval-after-load "pandoc-mode" '(diminish 'pandoc-mode ""))
(eval-after-load "git-gutter+" '(diminish 'git-gutter+-mode))
(eval-after-load "company" '(diminish 'company-mode ""))
(eval-after-load "cm-mode" '(diminish 'cm-mode ""))
(eval-after-load "reftex" '(diminish 'reftex-mode ""))
(eval-after-load "autorevert" '(diminish 'auto-revert-mode ""))
(eval-after-load "simple" '(diminish 'auto-revert-mode ""))
(eval-after-load "aggressive-indent" '(diminish 'aggressive-indent-mode ""))
(eval-after-load "auto-indent-mode" '(diminish 'auto-indent-mode ""))
(eval-after-load "smartparens" '(diminish 'smartparens-mode ""))
(eval-after-load "org-zotxt" '(diminish 'org-zotxt-mode ""))
(eval-after-load "back-button" '(diminish 'back-button-mode ""))
;; (eval-after-load "undo-tree" '(diminish 'undo-tree-mode "Ⓤ"))
(eval-after-load "undo-tree" '(diminish 'undo-tree-mode ""))
(eval-after-load "projectile" '(diminish 'projectile-mode ""))
(eval-after-load "helm" '(diminish 'helm-mode ""))

All the icons

Like the title says…

(use-package all-the-icons :defer t :diminish "")
;; icons for dired
(use-package all-the-icons-dired
  :diminish ""
  :commands (deer deer-jump-other-window all-the-icons-dired-mode dired-mode ranger)
  :init
  (add-hook 'dired-mode-hook 'all-the-icons-dired-mode))

Beacon

Useful for letting you know where the cursor is

(use-package beacon
  :ensure t
  :diminish beacon-mode
  :init (beacon-mode 1)
  :config
  (add-to-list 'beacon-dont-blink-major-modes 'eshell-mode))

UI

Apropos

Use helm

(bind-key "C-h a" 'helm-apropos)

Centered Cursor Mode

Keep the cursor centered in the screen

(use-package centered-cursor-mode
  :diminish centered-cursor-mode
  :commands (centered-cursor-mode
             global-centered-cursor-mode)
  :config
  (progn
    (setq ccm-recenter-at-end-of-file t
          ccm-ignored-commands '(mouse-drag-region
                                 mouse-set-point
                                 widget-button-click
                                 scroll-bar-toolkit-scroll
                                 evil-mouse-drag-region))))

Namespaced Keybindings

I use a lot of keybindings, with <SPC> as my “leader” key.

Applications

(cpm-leader1 
"a"  '(:ignore t :which-key "Applications") 
"ac" '(:ignore t :which-key "Cmus")
"ad" 'deer
"ae" 'eshell
"am" 'multi-term
"ar" 'ranger
"as" 'sane-term
"aw" 'wttrin
)

Buffers

  (cpm-leader1
    "b"  '(:ignore t :which-key "Buffers")
    "bb" 'helm-mini
    "bc" 'spacemacs/new-empty-buffer
    "bD" 'kill-buffer-and-window
    "bd" 'kill-this-buffer
    "bf" 'browse-file-directory
    "bj" 'jump-in-buffer 
    "bk" 'evil-delete-buffer
    "bK" 'spacemacs/kill-other-buffers
    "bn" 'spacemacs/new-empty-buffer
    ;; "bN" 'crux-kill-other-buffers
    "br" 'revert-buffer
    "bR" 'spacemacs/rename-current-buffer-file
    "bt" 'open-dir-in-iterm
)

Commenting

(cpm-leader1
  "c"  '(:ignore t :which-key "Commenting")
  "cb" 'org-block-wrap
  "cc" 'evil-commentary
  "cl" 'evil-commentary-line
  "cy" 'evil-commentary-yank-line
 )

Config

(cpm-leader1
  "C"  '(:ignore t :which-key "Config")
  "Cc" 'goto-config.org
  "Cl" 'load-config
  "Ci" 'goto-init.el
  "Cs" 'goto-custom.el
  )

Files

(cpm-leader1
  "f"  '(:ignore t :which-key "Files")
  "fd" 'fzf-directory
  "ff" 'helm-find-files
  ;; "ff" 'counsel-find-files
  ;; "fl" 'counsel-locate
  "fl" 'helm-locate
  "fo" 'crux-open-with
  "fs" 'save-buffer
  "fr" 'helm-recentf
  ;; "fr" 'counsel-recentf
  "fy" 'spacemacs/show-and-copy-buffer-filename
  "fz" 'fzf
  )

General

(cpm-leader1
  "A" 'helm-apropos
  "?" 'helm-descbinds
  ;; "?" 'counsel-descbinds
  "<SPC>" 'helm-M-x
  ;; "<SPC>" 'counsel-M-x
  "d" 'deer
  "D" 'deer-jump-other-window
  "e" 'server-edit
  "G" 'general-describe-keybindings
  "h" 'helm-resume
  ;; "r" 'ivy-resume
  "j" 'avy-goto-char
  "k" 'helm-show-kill-ring
  "N" 'research-notes
  "n" 'big-notes
  "M" 'woman
  "'" 'shell-pop
  "." 'quick-commit
  ";" 'evil-commentary-line
  "[" 'spacemacs/previous-useful-buffer
  "]" 'spacemacs/next-useful-buffer
  "TAB" 'switch-to-previous-buffer)

Markdown

(defun my-markdown-config ()
  "Modify keymaps in markdown mode"
  (cpm-leader1
    "m"   '(:ignore t :which-key "Markdown")
    "mc"  '(:ignore t :which-key "command")
    "mh"  '(:ignore t :which-key "insert")
    "mi"  '(:ignore t :which-key "lists")
    "mx"  '(:ignore t :which-key "text")
    ;; Movement
    "m{"   'markdown-backward-paragraph
    "m}"   'markdown-forward-paragraph
    ;; Completion, and Cycling
    "m]"   'markdown-complete
    ;; Indentation
    "m>"   'markdown-indent-region
    "m<"   'markdown-exdent-region
    ;; Buffer-wide commands
    "mc]"  'markdown-complete-buffer
    "mcc"  'markdown-check-refs
    "mce"  'markdown-export
    "mcm"  'markdown-other-window
    "mcn"  'markdown-cleanup-list-numbers
    "mco"  'markdown-open
    "mcp"  'markdown-preview
    "mcv"  'markdown-export-and-preview
    "mcw"  'markdown-kill-ring-save
    ;; headings
    "mhi"  'markdown-insert-header-dwim
    "mhI"  'markdown-insert-header-setext-dwim
    "mh1"  'markdown-insert-header-atx-1
    "mh2"  'markdown-insert-header-atx-2
    "mh3"  'markdown-insert-header-atx-3
    "mh4"  'markdown-insert-header-atx-4
    "mh5"  'markdown-insert-header-atx-5
    "mh6"  'markdown-insert-header-atx-6
    "mh!"  'markdown-insert-header-setext-1
    "mh@"  'markdown-insert-header-setext-2
    ;; Insertion of common elements
    "m-"   'markdown-insert-hr
    "mif"  'markdown-insert-footnote
    "mii"  'markdown-insert-image
    "mik"  'spacemacs/insert-keybinding-markdown
    "miI"  'markdown-insert-reference-image
    "mil"  'markdown-insert-link
    "miL"  'markdown-insert-reference-link-dwim
    "miw"  'markdown-insert-wiki-link
    "miu"  'markdown-insert-uri
    ;; Element removal
    "mk"   'markdown-kill-thing-at-point
    ;; List editing
    "mli"  'markdown-insert-list-item
    ;; region manipulation
    "mxb"  'markdown-insert-bold
    "mxi"  'markdown-insert-italic
    "mxc"  'markdown-insert-code
    "mxC"  'markdown-insert-gfm-code-block
    "mxq"  'markdown-insert-blockquote
    "mxQ"  'markdown-blockquote-region
    "mxp"  'markdown-insert-pre
    "mxP"  'markdown-pre-region
    ;; Following and Jumping
    "mN"   'markdown-next-link
    "mf"   'markdown-follow-thing-at-point
    "mP"   'markdown-previous-link
    "<RET>" 'markdown-jump
   ))
 
;; (which-key-add-major-mode-key-based-replacements 'markdown-mode
;;     "C-c C-a" "insert"
;;     "C-c C-c" "export"
;;     "C-c TAB" "images"
;;     "C-c C-s" "text"
;;     "C-c C-t" "header"
;;     "C-c C-x" "move"
;;     )

Miscellaneous

;; Show which-key top-level bindings
(global-set-key (kbd "H-k") 'which-key-show-top-level)
;; override evil insert for kill line
(general-define-key :states '(insert) "C-k" 'kill-line)

Org Keybindings

Keybindings for org mode

(cpm-leader1 
  "o"  '(:ignore t :which-key "Org")
  "oh" '(:ignore t :which-key "headers")
  "oi" '(:ignore t :which-key "insert")
  "oS" '(:ignore t :which-key "subtree")
  "ot" '(:ignore t :which-key "tables")
  "or" '(:ignore t :which-key "org-reveal")
  "oj" 'cpm/org-journal
  "oc" 'org-capture
  "oe" '(:ignore t :which-key "export")
  "oep" 'org-pandoc-export-to-latex-pdf
  "oeP" 'org-pandoc-export-to-latex-pdf-and-open
  "of" 'org-footnote-action
  "oP" 'org-set-property
  ;; "P" 'org-publish-current-project
  "op" 'org-publish-current-file
  "o:" 'org-set-tags
  "oa" 'org-agenda
  "ob" 'org-tree-to-indirect-buffer
  "oA" 'org-archive-subtree
  "ol" 'org-open-at-point
  "oT" 'org-show-todo-tree

  "orr" 'org-reveal-export-to-html-and-browse
  "ors" 'org-reveal-export-current-subtree
  "orp" 'reveal-to-pdf

  "o." 'org-time-stamp
  "o!" 'org-time-stamp-inactive

  ;; headings
  "ohi" 'org-insert-heading-after-current
  "ohI" 'org-insert-heading

  ;; More cycling options (timestamps, headlines, items, properties)
  "oL" 'org-shiftright
  "oH" 'org-shiftleft
  "oJ" 'org-shiftdown
  "oK" 'org-shiftup

  ;; Subtree editing
  "oSl" 'org-demote-subtree
  "oSh" 'org-promote-subtree
  "oSj" 'org-move-subtree-down
  "oSk" 'org-move-subtree-up

  ;; tables
  "ota" 'org-table-align
  "otb" 'org-table-blank-field
  "otc" 'org-table-convert
  "otdc" 'org-table-delete-column
  "otdr" 'org-table-kill-row
  "ote" 'org-table-eval-formula
  "otE" 'org-table-export
  "oth" 'org-table-previous-field
  "otH" 'org-table-move-column-left
  "otic" 'org-table-insert-column
  "otih" 'org-table-insert-hline
  "otiH" 'org-table-hline-and-move
  "otir" 'org-table-insert-row
  "otI" 'org-table-import
  "otj" 'org-table-next-row
  "otJ" 'org-table-move-row-down
  "otK" 'org-table-move-row-up
  "otl" 'org-table-next-field
  "otL" 'org-table-move-column-right
  "otn" 'org-table-create
  "otN" 'org-table-create-with-table.el
  "otr" 'org-table-recalculate
  "ots" 'org-table-sort-lines
  "ottf" 'org-table-toggle-formula-debugger
  "otto" 'org-table-toggle-coordinate-overlays
  "otw" 'org-table-wrap-region

  ;; Multi-purpose keys
  ;; "o*" 'org-ctrl-c-star
  ;; "oRET" 'org-ctrl-c-ret
  "o-" 'org-ctrl-c-minus
  "o^" 'org-sort
  "o/" 'org-sparse-tree

  "oI" 'org-clock-in
  "on" 'org-narrow-to-subtree
  "oN" 'widen
  "oO" 'org-clock-out
  "oq" 'org-clock-cancel
  "oR" 'org-refile
  "os" 'org-schedule

  ;; insertion of common elements
  "oil" 'org-insert-link
  "oif" 'org-footnote-new
  )

Packages

Keybindings for managing packages

(cpm-leader1 
  "P" '(:ignore t :which-key "Packages")
  "Pl" 'paradox-list-packages
  "Pu" 'paradox-upgrade-packages
  )

Projects

(cpm-leader1 
  "p" '(:ignore t :which-key "Projects")
  "p!"  'projectile-run-shell-command-in-root
  "p&"  'projectile-run-async-shell-command-in-root
  "pa"  'projectile-toggle-between-implementation-and-test
  "pb"  'helm-projectile-switch-to-buffer
  "pc"  'projectile-compile-project
  "pd"  'helm-projectile-find-dir
  "pD"  'projectile-dired
  "pf"  'helm-projectile-find-file
  "pg"  'goto-projects
  "ph"  'helm-projectile
  "pG"  'projectile-regenerate-tags
  "pI"  'projectile-invalidate-cache
  "pk"  'projectile-kill-buffers
  "pl"  'desktop+-load
  "po"  'projectile-multi-occur
  "pp"  'helm-projectile-switch-project
  "pr"  'helm-projectile-recentf
  "pR"  'projectile-replace
  ;; "ps"  'bmkp-set-desktop-bookmark
  "ps"  'desktop+-create
  "pS"  'bmkp-desktop-jump
  "pT"  'projectile-find-test-file
  "pv"  'projectile-vc
  "py"  'projectile-find-tag
)

Quitting

(cpm-leader1 
    "q"  '(:ignore t :which-key "Quit")
    "qq" 'save-desktop-save-buffers-kill-emacs
    "qQ" 'evil-quit-all
    "qr" 'restart-emacs)

Search

(cpm-leader1
  "s" '(:ignore t :which-key "Search")
  "sd" 'helm-do-ag ;; search with directory prompt
  "sb" 'helm-ag-buffers
  "sf" 'helm-do-ag-this-file
  "sj" 'forward-or-backward-sexp
  "sk" 'helm-show-kill-ring
  "sl" 'last-search-buffer
  "so" 'helm-occur
  "sp" 'helm-ag-project-root
  "ss" 'helm-swoop-without-pre-input ;; search in file
  "/"  'helm-ag  ;; search in directory with word prompt
   )

Toggles

(cpm-leader1 
  "t"  '(:ignore t :which-key "Toggles")
  "ta" 'company-mode
  "tb" 'fancy-battery-mode
  "tB" 'beacon-mode
  "tc" 'centered-cursor-mode
  "tC" 'centered-window-mode
  "td" 'distraction-free
  "tf" 'toggle-serif
  "tF" 'toggle-frame-fullscreen
  "tg" 'git-gutter-mode
  "th" 'hl-line-mode
  "te" 'toggle-indicate-empty-lines
  "tE" 'eldoc-mode
  "tm" 'hidden-mode-line-mode
  "tM" 'spaceline-toggle-minor-modes
  "tn" 'linum-mode
  "to" 'org-toggle-link-display
  "tp" 'smartparens-mode
  "tP" 'show-paren-mode 
  "tr" 'rainbow-identifiers-mode
  "ts" 'toggle-dark-light-theme
  "tt" 'helm-themes
  "tT" 'neotree-toggle
  "tw" 'writeroom-mode
  "tz" 'zone
  ;; "tt" 'counsel-load-theme
)

User

(cpm-leader1 
  "u"  '(:ignore t :which-key "User")
  "um" 'cpm/org-to-markdown   
  "uc" 'pandoc-convert-to-pdf
  "uo" 'cpm/markdown-to-org
  "up" 'run-pandoc
  "uP" 'pandoc-pdf-open
  "us" 'sb-expand-current-file
  "uS" 'just-one-space
  "ud" 'distraction-free
  "uD" 'my-desktop
  "uj" 'goto-journal
  ;; "op" 'pandoc-convert-to-pdf
  "uw" 'count-words
  "uW" 'osx-dictionary-search-input
  "ux" 'helm-bibtex
  )

Version Control

(cpm-leader1
  "g"  '(:ignore t :which-key "Git")
  "gb" 'magit-blame
  "gc" 'magit-commit
  "gd" 'magit-diff
  "gl" 'magit-log
  "gn" 'git-gutter:next-hunk
  "gp" 'git-gutter:previous-hunk
  "gr" 'magit-reflog
  "gs" 'magit-status
  )

Windows

(cpm-leader1 
  "w"  '(:ignore t :which-key "Windows")
  "wc" 'delete-window
  "w-" 'evil-window-split
  "w_" 'split-window-below-and-focus
  "wr" 'rotate-windows
  "wR" 'rotate-windows-backward
  "wv" 'split-window-right-and-focus
  "wV" 'evil-window-vsplit
  "wm" 'delete-other-windows
  )

Wiki

(cpm-leader1
  "W" '(:ignore t :which-key "Wiki")
  "Wd" 'org-wiki-dired-all
  "Wk" 'org-wiki-close
  "Wh" 'org-wiki-helm
  "WH" 'org-wiki-help
  "WI" 'org-wiki-index
  "Wi" 'org-wiki-insert
  "Wl" 'org-wiki-link
  "Wv" 'org-wiki-server-toggle
  "We" 'org-wiki-export-html
  "Wp" 'org-wiki-panel
  "Ws" 'org-wiki-search
)

Which-key

(use-package which-key
  :defer 2
  :diminish ""
  :config
  (setq which-key-special-keys nil)
  ;; Set the time delay (in seconds) for the which-key popup to appear.
  (setq which-key-idle-delay .2)
  (which-key-mode))

Popup Windows

Package that puts an end to popped up buffers not behaving they way you’d like them to.

(use-package shackle
  :config
  ;; make helm pop-ups behave
  (setq helm-display-function #'pop-to-buffer)
  (setq shackle-rules '(("\\`\\*helm.*?\\*\\'" :regexp t :align t :ratio 0.46)))
  (shackle-mode 1))

Packages and Mode-Specific Settings

Media

Cmus

;;;; define commands for controlling cmus from emacs

;;; utility (non-interactive) functions
(defun cmus-status ()
  "Return the current cmus status."
  (split-string
   (shell-command-to-string "cmus-remote -Q")
   "\n"))

(defun cmus-get-status-property (status property)
  "Search the status for the requested property."
  (replace-regexp-in-string property ""
                            (car
                             (delq nil
                                   (mapcar (lambda (prop-line)
                                             (if (string-match property prop-line)
                                                 prop-line
                                               nil))
                                           status)))))

(defun cmus-get-artist (status)
  "Return the currently playing track."
  (cmus-get-tag status "artist"))

(defun cmus-get-album (status)
  "Return the album for the current track."
  (cmus-get-tag status "album"))

(defun cmus-get-title (status)
  "Return the track title for the current track"
  (cmus-get-tag status "title"))

(defun cmus-get-tag (status tag)
  "Return the matching tag from the status."
  (let ((tag-match (concat "^tag " tag " ")))
    (cmus-get-status-property status tag-match)))

(defun cmus-playingp ()
  "Returns true if cmus is currently playing."
  (let ((status (cmus-get-status-property (cmus-status) "status ")))
    (if (equal status "playing")
        (progn
          (message "playing")
          t)
      (progn
        (message "paused")
        nil))))

;;; interactive functions

(defun cmus-next-track ()
  "Play the next track in cmus."
  (interactive)
  (shell-command-to-string "cmus-remote -n"))

(defun cmus-prev-track ()
  "Go back a track in cmus."
  (interactive)
  (shell-command-to-string "cmus-remote -r"))

(defun cmus-play-pause ()
  "If cmus is playing, pause it. If it is paused or stopped, start playing."
  (interactive)
  (if (cmus-playingp)
      (progn
        (message "Pausing..")
        (shell-command-to-string "cmus-remote --pause"))
    (progn
      (message "Playing.")
      (shell-command-to-string "cmus-remote --play"))))

(defun cmus-stop ()
  "Stop cmus."
  (interactive)
  (shell-command-to-string "cmus-remote --stop"))

(defun cmus-now-playing ()
  "Show the currently playing track."
  (interactive)
  (let ((status (cmus-status)))
    (let ((artist (cmus-get-artist status))
          (album (cmus-get-album status))
          (title (cmus-get-title status))
          (status (cmus-get-status-property status "status ")))
      (message (concat artist " - " title " (" album ")")))))

(defun cmus-set-volume (volume)
  "Set the current volume in cmus"
  (interactive (let ((volume (read-string "Volume: ")))
                 (list volume)))
  (let ((volume (if (stringp volume) volume (car volume))))
    (shell-command-to-string (concat "cmus-remote -v " volume "%"))))

(defun cmus-toggle-shuffle ()
  "Toggle playing shuffle."
  (interactive)
  (shell-command-to-string "cmus-remote -S")
  (message
   (concat "shuffle is "
           (if (equal "true" (cmus-get-status-property (cmus-status) "set shuffle "))
               "on"
             "off"))))

(defun cmus-toggle-repeat ()
  "Toggle playing repeat."
  (interactive)
  (shell-command-to-string "cmus-remote -R")
  (message
   (concat "repeat is "
           (if (equal "true" (cmus-get-status-property (cmus-status) "set repeat "))
               "on"
             "off"))))

(defun cmus-toggle-mode ()
  "Toggle between artist, album and all modes."
  (interactive)
  (shell-command-to-string "cmus-remote -C \"toggle aaa_mode\"")
  (message
   (concat "current mode: "
           (cmus-get-status-property (cmus-status) "set aaa_mode "))))

(cpm-leader1
"acx" 'cmus-play-pause
"acn" 'cmus-next-track
"acp" 'cmus-prev-track
"ack" 'cmus-stop
"acs" 'cmus-now-playing
"acv" 'cmus-set-volume
"ach" 'cmus-toggle-shuffle
"acr" 'cmus-toggle-repeat
"acm" 'cmus-toggle-mode)

Url

(use-package url
  :ensure nil
  :defer t
  :config
  (setq url-configuration-directory
        (file-name-as-directory
         (concat user-cache-directory "url"))))

Navigation

Avy

(use-package avy
  :commands (avy-goto-char))

Bookmark

  (use-package bookmark+
    ;; :commands bmkp-set-desktop-bookmark
    :init
    (setq bookmark-default-file
             (concat user-cache-directory "bookmarks"))
    (setq bmkp-last-as-first-bookmark-file "~/.emacs.d/.cache/bookmarks")
)

Hydra

(use-package hydra
  :defer 4
  :config
  ;; hydra for TODOs
  (defhydra hydra-todo (:pre
                  (hl-todo-mode 1)
              :post
             (hl-todo-mode -1))
  "Todo"
  ("n" hl-todo-next "Next")
  ("p" hl-todo-previous "Previous")
  ("o" hl-todo-occur "Occur")
  ("q" nil "Quit" :color blue :exit t))
)

Neotree

(use-package neotree
  :commands (neotree neotree-toggle)
  :config 
  (setq neo-theme (if (display-graphic-p) 'icons 'arrow))
  (setq neo-window-fixed-size t)
  (setq neo-window-width 32)
  (cpm-leader1
    ;; "T"  '(:ignore t :which-key "Neotree") 
    "T"  'neotree-toggle)

  ;; (setq projectile-switch-project-action 'neotree-projectile-action)
  (add-hook 'neotree-mode-hook
    (lambda ()
      (define-key evil-normal-state-local-map (kbd "q") 'neotree-hide)
      (define-key evil-normal-state-local-map (kbd "I") 'neotree-hidden-file-toggle)
      (define-key evil-normal-state-local-map (kbd "z") 'neotree-stretch-toggle)
      (define-key evil-normal-state-local-map (kbd "R") 'neotree-refresh)
      (define-key evil-normal-state-local-map (kbd "m") 'neotree-rename-node)
      (define-key evil-normal-state-local-map (kbd "c") 'neotree-create-node)
      (define-key evil-normal-state-local-map (kbd "d") 'neotree-delete-node)

      (define-key evil-normal-state-local-map (kbd "s") 'neotree-enter-vertical-split)
      (define-key evil-normal-state-local-map (kbd "S") 'neotree-enter-horizontal-split)

      (define-key evil-normal-state-local-map (kbd "RET") 'neotree-enter)))
)

Recent files

(use-package recentf
:defer 2
:init
(setq recentf-save-file (expand-file-name "recentf" user-cache-directory)))
;; :config
;; (recentf-mode 1))

Saveplace

(use-package saveplace
  :init
  (save-place-mode 1)
  :config
  (setq save-place-file "~/.emacs.d/.cache/saved-places")
  ;; (setq save-place-forget-unreadable-files nil)
)

Speedbar

A file tree and outliner

(use-package sr-speedbar
  :commands sb-expand-current-file
  :config
    (progn 
      (setq sr-speedbar-width 60)
      (setq sr-speedbar-max-width 60)
      (setq sr-speedbar-right-side nil)
      ;; Auto expand
      (defun sb-expand-current-file ()
      "Expand current file in speedbar buffer"
      (interactive)
      (setq current-file (buffer-file-name))
      (sr-speedbar-toggle)
      (speedbar-find-selected-file current-file)
      (speedbar-toggle-line-expansion))
      ;; Switch to window
      (defun speedbar-edit-line-and-switch-to-window ()
      (interactive)
      (speedbar-edit-line)
      (other-window 1))

      ;; other settings
      (setq speedbar-hide-button-brackets-flag t
          speedbar-show-unknown-files t
          speedbar-directory-button-trim-method 'trim
          speedbar-use-images nil
          speedbar-indentation-width 2
          speedbar-use-imenu-flag t
          speedbar-tag-hierarchy-method nil  ;; No grouping
          speedbar-file-unshown-regexp "flycheck-.*"
          speedbar-directory-unshown-regexp "^\\(CVS\\|RCS\\|SCCS\\|\\.\\.*$\\)\\'"    
          speedbar-smart-directory-expand-flag t)
      ;; Add markdown support
      (speedbar-add-supported-extension ".md")
      (speedbar-add-supported-extension ".org")
      ;; More familiar keymap settings.
      (add-hook 'speedbar-reconfigure-keymaps-hook
              '(lambda ()
                  (define-key speedbar-mode-map [tab] 'speedbar-toggle-line-expansion)
                  (define-key speedbar-mode-map [return] 'speedbar-edit-line-and-switch-to-window)))))

Search

Ag

(use-package ag
:defer t
:config
(progn
  (defun ag/jump-to-result-if-only-one-match ()
    "Jump to the first ag result if that ag search came up with just one match."
    (let (only-one-match)
      (when (member "--stats" ag-arguments)
        (save-excursion
          (goto-char (point-min))
          (setq only-one-match (re-search-forward "^1 matches\\s-*$" nil :noerror)))
        (when only-one-match
          (next-error)
          (kill-buffer (current-buffer))
          (message (concat "ag: Jumping to the only found match and "
                           "killing the *ag* buffer."))))))
  (add-hook 'ag-search-finished-hook #'ag/jump-to-result-if-only-one-match)  
 
  ;; Set default ag arguments
  ;; It looks like the ~/.agignore is used when launching ag from emacs too.
  ;; So the ignores from ~/.agignore don't have to be set here again.

  (setq ag-highlight-search t)
  ;; By default, ag.el will open results in a different window in the frame, so
  ;; the results buffer is still visible. You can override this so the results
  ;; buffer is hidden and the selected result is shown in its place:
  (setq ag-reuse-window nil)
  ;; reuse the same *ag* buffer for all your searches
  (setq ag-reuse-buffers t)
  ;; ;; To save buffer automatically when `wgrep-finish-edit'
  ;; (setq wgrep-auto-save-buffer t)

  (with-eval-after-load 'projectile
    ;; Override the default function to use the projectile function instead
    (defun ag/project-root (file-path)
      (let ((proj-name (projectile-project-root)))
        (if proj-name
            proj-name ; return `projectile-project-root' if non-nil
          ;; Else condition is same as the `ag/project-root' definition
          ;; from ag.el
          (if ag-project-root-function
              (funcall ag-project-root-function file-path)
            (or (ag/longest-string
                 (vc-git-root file-path)
                 (vc-svn-root file-path)
                 (vc-hg-root file-path))
                file-path))))))))

Ripgrep (rg)

(use-package rg 
  :commands rg)

Shell

Sane term

Sane settings for ansi-term

(use-package sane-term
  :commands sane-term
  :init
  ;; shell to use for sane-term
  (setq sane-term-shell-command "/usr/bin/zsh")
  ;; sane-term will create first term if none exist
  (setq sane-term-initial-create t)
  ;; `C-d' or `exit' will kill the term buffer.
  (setq sane-term-kill-on-exit t)
  ;; After killing a term buffer, not cycle to another.
  (setq sane-term-next-on-kill nil))

Shell Pop

A popup shell

(use-package shell-pop
  :commands shell-pop
  :init
  (setq shell-pop-term-shell "/usr/bin/zsh")
  (setq shell-pop-shell-type '("eshell" "*eshell*" (lambda nil (eshell))))
  :config
    (defun ansi-term-handle-close ()
     "Close current term buffer when `exit' from term buffer."
     (when (ignore-errors (get-buffer-process (current-buffer)))
       (set-process-sentinel (get-buffer-process (current-buffer))
                             (lambda (proc change)
                               (when (string-match "\\(finished\\|exited\\)" change)
                                 (kill-buffer (when (buffer-live-p (process-buffer proc)))
                                 (delete-window))))))
   (add-hook 'shell-pop-out-hook 'kill-this-buffer)
   (add-hook 'term-mode-hook (lambda () (linum-mode -1) (ansi-term-handle-close)))))

Shell settings

Other useful shell settings

 ;; basic settings
 (setq explicit-shell-file-name "/usr/bin/zsh")
 ;; don't add newline in long lines
 (setq-default term-suppress-hard-newline t)
 ;; kill process buffers without query
 (setq kill-buffer-query-functions (delq 'process-kill-buffer-query-function kill-buffer-query-functions))
 (global-set-key (kbd "C-x k") 'kill-this-buffer) 
 ;; kill ansi-buffer on exit
 (defadvice term-sentinel (around my-advice-term-sentinel (proc msg))
   (if (memq (process-status proc) '(signal exit))
       (let ((buffer (process-buffer proc)))
          ad-do-it
          (kill-buffer buffer))
         ad-do-it))
       (ad-activate 'term-sentinel)

;; clickable links & no highlight of line
(defun my-term-hook ()
  (goto-address-mode) (global-hl-line-mode 0))
(add-hook 'term-mode-hook 'my-term-hook)
    
;; paste and navigation
(defun term-send-tab ()
"Send tab in term mode."
  (interactive)
  (term-send-raw-string "\t"))

;; Emacs doesn’t handle less well, so use cat instead for the shell pager 
(setenv "PAGER" "cat")

;; hack to fix pasting issue, the paste micro-state won't work in term
(general-define-key :states '(normal) :keymaps 'term-raw-map 
       "p" 'term-paste
       "C-k" 'term-send-up
       "C-j" 'term-send-down)

(general-define-key :states '(insert) :keymaps 'term-raw-map 
       "C-c C-d" 'term-send-eof
       "C-c C-z" 'term-stop-subjob
       "<tab>"   'term-send-tab
       "s-v"     'term-paste
       "C-k"     'term-send-up
       "C-j"     'term-send-down)

Compilation buffer

Whenever I run compile, the buffer stays even after a successful compilation. Let’s make it close automatically if the compilation is successful.

(setq compilation-finish-functions
      (lambda (buf str)
        (if (null (string-match ".*exited abnormally.*" str))
            ;;no errors, make the compilation window go away in a few seconds
            (progn
              (run-at-time "0.4 sec" nil
                           (lambda ()
                             (select-window (get-buffer-window (get-buffer-create "*compilation*")))
                             (switch-to-buffer nil)))
              (message "No Compilation Errors!")))))

Completion buffer

Kill the completion buffer

;; Remove completion buffer when done
(add-hook 'minibuffer-exit-hook 
'(lambda ()
         (let ((buffer "*Completions*"))
           (and (get-buffer buffer)
            (kill-buffer buffer)))))

Colors

Get 256 colors instead of 8

(use-package xterm-color
  :init
  ;; comint install
  (progn (add-hook 'comint-preoutput-filter-functions 'xterm-color-filter)
         (setq comint-output-filter-functions (remove 'ansi-color-process-output comint-output-filter-functions)))

  ;; comint uninstall
  (progn (remove-hook 'comint-preoutput-filter-functions 'xterm-color-filter)
         (add-to-list 'comint-output-filter-functions 'ansi-color-process-output))

;; For M-x shell, also set TERM accordingly (xterm-256color)



)

Virtualenvwrapper

(use-package virtualenvwrapper
  :defer 2
  :config
  (venv-initialize-interactive-shells) ;; if you want interactive shell support
  (venv-initialize-eshell) ;; if you want eshell support
  (setq venv-location "~/bin/virtualenvs")
  (setq venv-project-home "~/Dropbox/Work/projects/")
  (add-hook 'venv-postactivate-hook (lambda () (workon-venv))))

(defcustom venv-project-home
  (expand-file-name (or (getenv "PROJECT_HOME") "~/projects/"))
    "The location(s) of your virtualenv projects."
    :group 'virtualenvwrapper)

(defun workon-venv ()
 "change directory to project in eshell"
  (eshell/cd (concat venv-project-home venv-current-name)))

Eshell

Eshell is an elisp shell. It has its own configuration parameters, distinct from those of shell or ansi-terminal.

Eshell Settings

Basic settings

(use-package eshell
  :commands eshell
  ;; :bind ("C-x e" . eshell)
  :init
  ;; (use-package em-cmpl :ensure nil)
  ;; (use-package em-prompt :ensure nil)
  ;; (use-package em-term :ensure nil)
  (setq
        eshell-highlight-prompt nil
        eshell-buffer-shorthand t
        eshell-cmpl-ignore-case t
        eshell-cmpl-cycle-completions nil
        eshell-history-size 500
        ;; auto truncate after 12k lines
        eshell-buffer-maximum-lines 12000
        eshell-hist-ignoredups t
        eshell-error-if-no-glob t
        eshell-glob-case-insensitive t
        eshell-scroll-to-bottom-on-input 'all
        eshell-list-files-after-cd t
        eshell-aliases-file (concat user-emacs-directory "eshell/alias")
        eshell-banner-message ""
        ;; eshell-banner-message "What would you like to do?\n\n"
      )
      ;; Visual commands
  (setq eshell-visual-commands '("vi" "screen" "top" "less" "more" "lynx"
                                     "ncftp" "pine" "tin" "trn" "elm" "vim"
                                     "nmtui" "alsamixer" "htop" "el" "elinks"
                                     ))
  (setq eshell-visual-subcommands '(("git" "log" "diff" "show")))

      (defun my/truncate-eshell-buffers ()
        "Truncates all eshell buffers"
        (interactive)
        (save-current-buffer
          (dolist (buffer (buffer-list t))
            (set-buffer buffer)
            (when (eq major-mode 'eshell-mode)
              (eshell-truncate-buffer)))))

      ;; After being idle for 5 seconds, truncate all the eshell-buffers if
      ;; needed. If this needs to be canceled, you can run `(cancel-timer
      ;; my/eshell-truncate-timer)'
      (setq my/eshell-truncate-timer
            (run-with-idle-timer 5 t #'my/truncate-eshell-buffers))

      (when (not (functionp 'eshell/rgrep))
        (defun eshell/rgrep (&rest args)
          "Use Emacs grep facility instead of calling external grep."
          (eshell-grep "rgrep" args t)))
)

(defun my/setup-eshell ()
  (interactive)
  ;; turn off semantic-mode in eshell buffers
  (semantic-mode -1)
  ;; turn off hl-line-mode
  (hl-line-mode -1)
  (define-key eshell-mode-map (kbd "M-l")
    'helm-eshell-history))

(add-hook 'eshell-mode-hook
          (lambda ()
              (my/setup-eshell)
              (eshell-cmpl-initialize)))

Eshell Prompt

Make the prompt display more useful info. I got a lot of help from looking at bling’s eshell config as well as the package eshell-prompt-extras.

  (defcustom dotemacs-eshell/prompt-git-info
  t
  "Turns on additional git information in the prompt."
  :group 'dotemacs-eshell
  :type 'boolean)
  
;; (epe-colorize-with-face "abc" 'font-lock-comment-face)
(defmacro epe-colorize-with-face (str face)
  `(propertize ,str 'face ,face))
  
(defface epe-venv-face
  '((t (:inherit font-lock-comment-face)))
  "Face of python virtual environment info in prompt."
  :group 'epe)

  (setq eshell-prompt-function
      (lambda ()
        (concat (propertize (abbreviate-file-name (eshell/pwd)) 'face 'eshell-prompt)
                (when (and dotemacs-eshell/prompt-git-info
                           (fboundp #'vc-git-branches))
                  (let ((branch (car (vc-git-branches))))
                    (when branch
                      (concat
                       (propertize " [" 'face 'font-lock-keyword-face)
                       (propertize branch 'face 'font-lock-function-name-face)
                       (let* ((status (shell-command-to-string "git status --porcelain"))
                              (parts (split-string status "\n" t " "))
                              (states (mapcar #'string-to-char parts))
                              (added (count-if (lambda (char) (= char ?A)) states))
                              (modified (count-if (lambda (char) (= char ?M)) states))
                              (deleted (count-if (lambda (char) (= char ?D)) states)))
                         (when (> (+ added modified deleted) 0)
                           (propertize (format " +%d ~%d -%d" added modified deleted) 'face 'font-lock-comment-face)))
                       (propertize "]" 'face 'font-lock-keyword-face)))))
                (when (and (boundp #'venv-current-name) venv-current-name)
                  (concat 
                    (epe-colorize-with-face " [" 'epe-venv-face) 
                    (propertize venv-current-name 'face `(:foreground "#2E8B57" :slant italic))
                    (epe-colorize-with-face "]" 'epe-venv-face))) 
                (propertize " $ " 'face 'font-lock-constant-face))))

Shell Switcher

Useful for switching between multiple instances of eshell. But you can configure for any shell that you use.

(use-package shell-switcher
  :defer 2
  :init
  (add-hook 'eshell-mode-hook 'shell-switcher-manually-register-shell)
  :config
  (setq shell-switcher-mode t))

Clear Eshell

Make eshell act like a standard unix terminal.

  (defun eshell-clear-buffer ()
  "Clear terminal"
  (interactive)
  (let ((inhibit-read-only t))
    (erase-buffer)
    (eshell-send-input)))
(add-hook 'eshell-mode-hook
      '(lambda()
          (local-set-key (kbd "C-l") 'eshell-clear-buffer)))

Eshell Magit

(defun eshell/magit ()
"Function to open magit-status for the current directory"
  (interactive)
  (magit-status default-directory)
  nil)

Package Management

(use-package paradox
  :commands (paradox-list-packages paradox-upgrade-packages)
  :config
  (add-to-list 'evil-emacs-state-modes 'paradox-menu-mode)
  (setq paradox-execute-asynchronously nil
         ;; Show all possible counts
        paradox-display-download-count t
        paradox-display-star-count t
        ;; Don't star automatically
        paradox-automatically-star nil))

Programming

Alignment

This package provides gl and gL align operators: gl MOTION CHAR and right-align gL MOTION CHAR

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

Rainbow delimiters

(use-package rainbow-delimiters 
  :commands rainbow-delimiters-mode
  :init
  (add-hook 'prog-mode-hook 'rainbow-delimiters-mode))

Rainbow identifiers

(use-package rainbow-identifiers
  :commands rainbow-identifiers-mode
  :init
  (add-hook 'prog-mode-hook 'rainbow-identifiers-mode))

Rainbow mode

(use-package rainbow-mode
  :commands rainbow-mode)

Completion

Yasnippet

(use-package yasnippet                
  :commands (yas-expand yas-minor-mode)
  :diminish (yas-minor-mode . "")
  :init
  (progn
    (add-hook 'prog-mode-hook #'yas-minor-mode)
    (add-hook 'org-mode-hook #'yas-minor-mode)
    (add-hook 'markdown-mode-hook #'yas-minor-mode)
    ;; snippet directory
    (setq yas-snippet-dirs (concat user-cache-directory "snippets"))
    (unless (file-directory-p yas-snippet-dirs)
      (make-directory yas-snippet-dirs))
    ;; (add-hook 'term-mode-hook (lambda()
    ;;     (setq yas-dont-activate t)))
    )
   :config 
   (yas-reload-all))

Yankpad

(use-package yankpad
  :defer 10
  :init
  (setq yankpad-file (concat user-cache-directory "yankpad.org"))
  ;; create file if it does not exist
  (when (not (file-exists-p yankpad-file))
    (shell-command (concat "touch " yankpad-file)))
  :config
  ;; If you want to complete snippets using company-mode
  ;; (add-to-list 'company-backends #'company-yankpad)
)

Company

  (use-package company
      :commands (company-mode)
      :init
      (progn
        ;; (add-hook 'after-init-hook 'global-company-mode)
        (add-hook 'prog-mode-hook 'company-mode)
        (add-hook 'org-mode-hook 'company-mode)
        (add-hook 'markdown-mode-hook 'company-mode)  
        (setq company-idle-delay 0.3
              company-minimum-prefix-length 4
              company-require-match nil
              company-dabbrev-ignore-case nil
              company-dabbrev-downcase nil))
      :config
      (progn
        ;; latex
        (add-to-list 'company-backends #'company-latex-commands)

        ;; key bindings
        (let ((map company-active-map))
          (define-key map (kbd "C-/") 'company-search-candidates)
          (define-key map (kbd "C-M-/") 'company-filter-candidates)
          (define-key map (kbd "C-d") 'company-show-doc-buffer)
          (define-key map (kbd "C-j") 'company-select-next)
          (define-key map (kbd "C-k") 'company-select-previous)
          (define-key map (kbd "C-l") 'company-complete-selection))
        ;; Nicer looking faces
        (custom-set-faces
         '(company-tooltip-common
           ((t (:inherit company-tooltip :weight bold :underline nil))))
         '(company-tooltip-common-selection
           ((t (:inherit company-tooltip-selection :weight bold :underline nil)))))
))
Auc-tex
(use-package company-auctex
  :after latex-mode
 )
Company math
(use-package company-math
  :defer t
  :init 
  (with-eval-after-load 'company
    ;; Add backends for math characters
    (add-to-list 'company-backends 'company-math-symbols-unicode)
    (add-to-list 'company-backends 'company-math-symbols-latex))
)

Electric Pair (Autopair)

(use-package electric-pair
  :ensure nil
  :commands electric-pair-mode
  :init
  (add-hook 'prog-mode-hook 'electric-pair-mode)
  (add-hook 'org-mode-hook 'electric-pair-mode)
  (add-hook 'markdown-mode-hook 'electric-pair-mode)
)

Smartparens (Autopair)

Smarter autopairing

(use-package smartparens 
  :defer t
  :config
  (require 'smartparens-config)
  ;; :init 
  ;; (add-hook 'prog-mode-hook 'smartparens-mode)
  ;; (add-hook 'org-mode-hook 'smartparens-mode)
  ;; (add-hook 'markdown-mode-hook 'smartparens-mode)
  )

(use-package evil-smartparens
  :diminish ""
  :defer t
  ;; :init
  ;; (add-hook 'smartparens-enabled-hook #'evil-smartparens-mode)
)

Languages

Elisp

(use-package elisp-slime-nav
  :ensure t
  :defer t)

(use-package eldoc
  :diminish eldoc-mode
  :commands eldoc-mode)
  (add-hook 'emacs-lisp-mode-hook (lambda ()
              (setq show-trailing-whitespace t)
              (prettify-symbols-mode)
              (eldoc-mode)
              (yas-minor-mode)
              (company-mode)
              (rainbow-delimiters-mode)))
              

Haskell

(use-package haskell-mode
  :commands haskell-mode)

Html

(use-package web-mode
  :commands (web-mode)
  :ensure t
  :init
  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
  :config
  (setq web-mode-engines-alist
      '(("django"    . "\\.html\\'")))
  (setq web-mode-ac-sources-alist
      '(("css" . (ac-source-css-property))
  	   ("html" . (ac-source-words-in-buffer ac-source-abbrev))))

  (setq web-mode-enable-auto-closing t)
  (setq web-mode-enable-auto-quoting t)) ; this fixes the quote problem I mentioned

Lua

(use-package lua-mode
  :commands lua-mode
  :init
  (dolist (pattern '("\\.lua\\'"))
  (add-to-list 'auto-mode-alist (cons pattern 'lua-mode))))

PHP

(use-package php-mode
  :commands php-mode
  :init
  (dolist (pattern '("\\.php\\'"))
  (add-to-list 'auto-mode-alist (cons pattern 'php-mode))))

Shell script mode

(use-package sh-script
  :commands sh-script-mode
  :init
  (progn
    ;; Use sh-mode when opening `.zsh' files, and when opening Prezto runcoms.
    (dolist (pattern '("\\.zsh\\'"
                       "zlogin\\'"
                       "zlogout\\'"
                       "zpreztorc\\'"
                       "zprofile\\'"
                       "zshenv\\'"
                       "zshrc\\'"))
      (add-to-list 'auto-mode-alist (cons pattern 'sh-mode)))))

  (defun spacemacs//setup-shell ()
      (when (and buffer-file-name
                 (string-match-p "\\.zsh\\'" buffer-file-name))
        (sh-set-shell "zsh")))
    (add-hook 'sh-mode-hook 'spacemacs//setup-shell)

Yaml

(use-package yaml-mode
  :commands yaml-mode
  :config
  (add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
  (add-to-list 'auto-mode-alist '("\\.yaml$" . yaml-mode))
  (add-hook 'yaml-mode-hook (lambda () (run-hooks 'prog-mode-hook)))
)

Vim

(use-package vimrc-mode
  :commands vimrc-mode)

Version Control

Magit is a great interface for git projects. It’s much more pleasant to use than the standard git interface on the command line. I’ve set up some easy keybindings to access magit and related packages.

Magit

(use-package magit
  :commands 
  (magit-blame-mode
   magit-commit
   magit-diff
   magit-log
   magit-status)
  :init
  (add-hook 'git-commit-mode-hook 'turn-on-flyspell)
  :config
  (setq vc-follow-symlinks t)
  ;; make magit go fullscreen
  ;; (setq magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1)
  (setq magit-diff-refine-hunk 'all)
  (global-git-commit-mode t) ; use emacs as editor for git commits
  (setq magit-push-always-verify nil)
    )

Evil Magit

Evil bindings for magit

(use-package evil-magit
  :defer t
  :after magit
  ;; (with-eval-after-load 'magit (require 'evil-magit))
  )

Git timemachine

(use-package git-timemachine            ; Go back in Git time
  :commands git-timemachine
)

Fringe

(use-package git-gutter-fringe)

Git gutter

Git gutter is great for giving visual feedback on changes, but it doesn’t play well with org-mode using org-indent. So I don’t use it globally.

(use-package git-gutter
  :commands (git-gutter-mode)
  :diminish ""
  :init
  (add-hook! (markdown-mode prog-mode conf-mode) 'git-gutter-mode)
  :config
  (require 'git-gutter-fringe)
  (def-popup! "^\\*git-gutter.\\*$" :align below :size 15 :noselect t :regexp t)
  ;; NOTE If you want the git gutter to be on the outside of the margins (rather
  ;; than inside), `fringes-outside-margins' should be non-nil.

  ;; colored fringe "bars"
  (define-fringe-bitmap 'git-gutter-fr:added
    [224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224]
    nil nil 'center)
  (define-fringe-bitmap 'git-gutter-fr:modified
    [224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224 224]
    nil nil 'center)
  (define-fringe-bitmap 'git-gutter-fr:deleted
    [0 0 0 0 0 0 0 0 0 0 0 0 0 128 192 224 240 248]
    nil nil 'center)

  ;; Refreshing git-gutter
  (advice-add 'evil-force-normal-state :after 'git-gutter)
  (add-hook 'focus-in-hook 'git-gutter:update-all-windows))

Quick commits

(defun quick-commit ()
"make a quick commit from the mini-buffer"
(interactive)
(evil-ex '"!Git add % && Git commit -m '" ))

Writing & Research

I use emacs primarily for writing and doing research. These are some of the packages that are most helpful for this.

Distraction free mode

This simulates programs like writeroom that provide a distraction-free mode of writing.

(use-package writeroom-mode
  :commands (writeroom-mode)
  :config
  (setq writeroom-width 85)
)
    (defun distraction-free ()
    "distraction free writing"
      (interactive)
      (git-gutter-mode 0) 
      (linum-mode 0) 
      (centered-cursor-mode)
      (writeroom-mode)
      )

Org-mode

Org-mode is really why most people use emacs. Here are some basic settings and packages.

Org Base Settings

(use-package org 
  :defer t
  :config
  ;; Allow's electric-pair-mode to surround things with = and ~ in org-mode
  ;; (modify-syntax-entry ?~ "(~" org-mode-syntax-table)
  ;; (modify-syntax-entry ?= "(=" org-mode-syntax-table)
  ;; don't underline indents
  (defface org-dont-underline-indents '((t :underline nil))
    "Avoid underlining of indentation.")
  (defun org-dont-underline-indents ()
    "Remove underlining at indents."
    (add-to-list 'org-font-lock-extra-keywords '("^[[:space:]]+" 0 'org-dont-underline-indents t) 'append))
  (add-hook 'org-font-lock-set-keywords-hook #'org-dont-underline-indents 'append)
  (setq org-src-fontify-natively t ;; better looking source code
        org-return-follows-link t ;; make RET follow links
        org-list-allow-alphabetical t ;; allow alphabetical list
        org-hide-emphasis-markers t  ;; hide markers
        org-pretty-entities t ;; make latex look good
        org-fontify-quote-and-verse-blocks t ;; make quotes stand out
        org-table-export-default-format "orgtbl-to-csv" ;; export for org-tables to csv
        ;; org-ellipsis "↷" ;; nicer elipses "↴" "▼" 
        org-confirm-babel-evaluate nil  ;; evaluate src block without confirmation           
        org-startup-indented t ;; start in indent mode
        ; org-src-preserve-indentation nil 
        ; org-edit-src-content-indentation t
        org-imenu-depth 8
        imenu-auto-rescan t)
    :init
    (add-hook 'org-mode-hook
        (lambda () 
          (turn-on-auto-fill)
          (flyspell-mode 1)
          (global-git-gutter-mode 0)
          (imenu-add-to-menubar "Imenu")))
    ;; normal state shortcuts
    (general-define-key :states '(normal) :keymaps 'org-mode-map
      "RET" 'org-open-at-point     ;; Open with return in evil
      "gh" 'outline-up-heading
      "gp" 'outline-previous-heading
      "gj" (if (fboundp 'org-forward-same-level) ;to be backward compatible with older org version
     	       'org-forward-same-level
	             'org-forward-heading-same-level)
      "gk" (if (fboundp 'org-backward-same-level) 
                 'org-backward-same-level 'org-backward-heading-same-level)
      "gl" 'outline-next-visible-heading
      "L" 'org-shiftright
      "H" 'org-shiftleft
      "$" 'org-end-of-line
      "^" 'org-beginning-of-line
      "<" 'org-metaleft
      ">" 'org-metaright
      "-" 'org-cycle-list-bullet)
    ;; normal & insert state shortcuts.
    (general-define-key :states '(normal insert) :keymaps 'org-mode-map
      "TAB" 'org-cycle
      "s-l" 'org-metaright
      "s-h" 'org-metaleft
      "s-k" 'org-metaup
      "s-j" 'org-metadown
      "s-L" 'org-shiftmetaright
      "s-H" 'org-shiftmetaleft
      "s-K" 'org-shiftmetaup
      "s-J" 'org-shiftmetadown
      "s-o" '(lambda () (interactive)
                         (evil-org-eol-call
                          '(lambda()
                              (org-insert-heading)
                              (org-metaright))))
      "s-t" '(lambda () (interactive)
                        (evil-org-eol-call
                          '(lambda()
                              (org-insert-todo-heading nil)
                              (org-metaright)))))
    ;; Use tab in insert mode
    (general-define-key :states '(insert) :keymaps 'org-mode-map "\t" nil))

Org & Pandoc (Ox-pandoc)

(use-package ox-pandoc
  :defer 1
  :config
  ;; default options for all output formats
  ;; (setq org-pandoc-command (expand-file-name "~/.local/bin/pandoc"))
  (setq org-pandoc-options '((standalone . t)))
  ;; cancel above settings only for 'docx' format
  (setq org-pandoc-options-for-docx '((standalone . nil)))
  ;; special settings for beamer-pdf and latex-pdf exporters
  (setq org-pandoc-options-for-beamer-pdf '((latex-engine . "xelatex")))
  (setq org-pandoc-options-for-latex-pdf '((latex-engine . "xelatex"))))

Org Miscellaneous Packages

Other useful org packages

(use-package htmlize :after org :ensure t)
(use-package org-inlinetask :ensure nil :commands org-inlinetask-insert-task)
(use-package toc-org
  :init
  (progn
    (setq toc-org-max-depth 10)
    (add-hook 'org-mode-hook 'toc-org-enable)))
;; ignore export of headlines marked with :ignore: tag
(use-package ox-extra
  :ensure nil
  :after org
  :config
  (ox-extras-activate '(ignore-headlines)))

Org-Reveal

(use-package ox-reveal
:ensure t
:commands (org-reveal-export-current-subtree org-reveal-export-to-html-and-browse)
:config
(setq org-reveal-root (concat "file://" (getenv "HOME") "/bin/reveal.js")
      org-reveal-theme "moon"
      org-reveal-default-frag-style "roll-in"
      org-reveal-hlevel 2
      ))

Org Capture

(setq org-capture-templates
    '(
      ("j" "Journal entry" plain
       (file+datetree "~/Dropbox/journal.org")
       "**** %<%H:%M>\n%?")

      ;; other entries
      ))
(defun cpm/org-journal ()
(interactive) (org-capture nil "j"))

Journal

Org-journal
(use-package org-journal
:ensure t
:disabled t
:defer t
:init
 (setq org-journal-dir "~/Dropbox/journal/")
 (setq org-journal-date-format "%Y-%b-%d (%A)"))
Journal functions

I got all of these from Howard Abrams’ great config file.

Today’s entry
(defun get-journal-file-today ()
  "Return filename for today's journal entry."
  (let ((daily-name (format-time-string "%Y%m%d")))
    (expand-file-name (concat org-journal-dir daily-name))))
(defun journal-file-today ()
  "Create and load a journal file based on today's date."
  (interactive)
  (find-file (get-journal-file-today)))
Yesterday’s (new) entry
(defun get-journal-file-yesterday ()
  "Return filename for yesterday's journal entry."
  (let ((daily-name (format-time-string "%Y%m%d" (time-subtract (current-time) (days-to-time 1)))))
    (expand-file-name (concat org-journal-dir daily-name))))

(defun journal-file-yesterday ()
  "Creates and load a file based on yesterday's date."
  (interactive)
  (find-file (get-journal-file-yesterday)))
Last year
(defun journal-last-year-file ()
  "Returns the string corresponding to the journal entry that
happened 'last year' at this same time (meaning on the same day
of the week)."
(let* ((last-year-seconds (- (float-time) (* 365 24 60 60)))
       (last-year (seconds-to-time last-year-seconds))
       (last-year-dow (nth 6 (decode-time last-year)))
       (this-year-dow (nth 6 (decode-time)))
       (difference (if (> this-year-dow last-year-dow)
                       (- this-year-dow last-year-dow)
                     (- last-year-dow this-year-dow)))
       (target-date-seconds (+ last-year-seconds (* difference 24 60 60)))
       (target-date (seconds-to-time target-date-seconds)))
  (format-time-string "%Y%m%d" target-date)))

(defun journal-last-year ()
  "Loads last year's journal entry, which is not necessary the
same day of the month, but will be the same day of the week."
  (interactive)
  (let ((journal-file (concat org-journal-dir (journal-last-year-file))))
    (find-file journal-file)))

Org Publish

;;; Org-publish settings
    (setq org-publish-project-alist
      '(

      ("testing"
      :base-directory "~/test/source"
      :base-extension "org"
      :publishing-directory "~/test/output"
      :publishing-function (org-pandoc-publish-to-markdown)
      :org-pandoc-table-of-contents t
      :org-pandoc-bibliography "/Users/Roambot/Dropbox/Work/Master.bib"
      :org-pandoc-toc-depth 2)

        ("notebook"
         ;; Path to org files
         :base-directory "~/projects/notebook/content/org_notes"
         :base-extension "org"
         ;; Path to pelican project
         :publishing-directory "~/projects/notebook/content/notes" 
         ;; settings
         :author "Colin McLear"
         :email "mclear@unl.edu"
         :recursive t
         :auto-preamble nil ;; Don't add any kind of html before the content
         :export-with-tags nil
         :with-timestamps nil
         :time-stamp-file nil
         :with-creator nil
         :auto-postamble nil ;; Don't add any kind of html after the content
         :html-postamble nil ;; same thing
         ;; :publishing-function (org-html-publish-to-html)
         ;; :publishing-function (org-md-publish-to-md)
         :publishing-function (org-org-publish-to-org)
         :org-pandoc-bibliography "/Users/Roambot/Dropbox/Work/Master.bib"
         ;; :publishing-function (org-pandoc-publish-to-html)
         )
        ("big-notes"
         ;; Path to org files
         :base-directory "~/Dropbox/Notes/"
         :base-extension "org"
         ;; Path to pelican project
         :publishing-directory "~/projects/notebook/content/notes" 
         ;; settings
         :author "Colin McLear"
         :email "mclear@unl.edu"
         :recursive t
         :auto-preamble nil ;; Don't add any kind of html before the content
         :export-with-tags nil
         :with-timestamps nil
         :time-stamp-file nil
         :with-creator nil
         :auto-postamble nil ;; Don't add any kind of html after the content
         :html-postamble nil ;; same thing
         ;; :publishing-function (org-html-publish-to-html)
         ;; :publishing-function (org-md-publish-to-md)
         :publishing-function (org-org-publish-to-org)
         ;; :publishing-function (org-pandoc-publish-to-html)
         )
         ("test"
         :base-directory "~/test/source"
         :base-extension "org"
         :publishing-directory "~/test/output" 
         ;; settings
         :author "Colin McLear"
         :email "mclear@unl.edu"
         :publishing-function (org-org-publish-to-org)
         )
         ))

    ;; (defun org-pandoc-publish-to-html (plist filename pub-dir)
    ;;   "Publish an org file to html using ox-pandoc. Return output file name."
    ;;   (org-publish-org-to 'org-pandoc-export-to-html filename ".html" plist pub-dir))

      ;; Pandoc publishing functions 
      (defun org-pandoc-publish-to (format plist filename pub-dir)
        (setq org-pandoc-format format)
        (let ((tempfile
         (org-publish-org-to
          'pandoc filename (concat (make-temp-name ".tmp") ".org") plist pub-dir))
        (outfile (format "%s.%s"
		           (concat
		            pub-dir
		            (file-name-sans-extension (file-name-nondirectory filename)))
		           (assoc-default format org-pandoc-extensions))))
          (org-pandoc-put-options (org-pandoc-plist-to-alist plist))
          (let ((process
           (org-pandoc-run tempfile outfile format 'org-pandoc-sentinel
		             org-pandoc-option-table))
          (local-hook-symbol
           (intern (format "org-pandoc-after-processing-%s-hook" format))))
            (process-put process 'files (list tempfile))
            (process-put process 'output-file filename)
            (process-put process 'local-hook-symbol local-hook-symbol))))

      ;; helper functions
      (defun org-pandoc-publish-to-html5 (p f pd)
          (org-pandoc-publish-to 'html5 p f pd))

      (defun org-pandoc-publish-to-org (p f pd)
          (org-pandoc-publish-to 'org p f pd))

      (defun org-pandoc-publish-to-markdown (p f pd)
          (org-pandoc-publish-to 'markdown p f pd))

      (defun org-pandoc-pan-to-pub (o)
        (intern (format ":org-pandoc-%s" o)))

      (defun org-pandoc-pub-to-pan (o)
        (intern (substring (symbol-name o) 12)))

      ;; (defconst org-pandoc-publish-options
      ;;   (mapcar 'org-pandoc-pan-to-pub
	    ;;       (append org-pandoc-valid-options org-pandoc-colon-separated-options
	    ;;           org-pandoc-file-options)))

      (defun org-pandoc-plist-to-alist (plist)
        (let ((alist '()))
          (while plist
            (let ((p (car plist)) (v (cadr plist)))
	        (when (member p org-pandoc-publish-options)
	          (add-to-list 'alist (cons (org-pandoc-pub-to-pan p) v))))
            (setq plist (cddr plist)))
          alist))

Org Pomodoro

Helps with time tracking

(use-package org-pomodoro
  :commands org-pomodoro
  :ensure t
  :init
  (progn
    (setq org-pomodoro-audio-player "/usr/bin/afplay")))

Open Docx Files In Default Application (Ie Msword)

Open exported docx files in Word/Open Office rather than emacs

(setq org-file-apps
      '(("\\.docx\\'" . default)
        ("\\.mm\\'" . default)
        ("\\.x?html?\\'" . default)
        ("\\.pdf\\'" . default)
        (auto-mode . emacs)))

Org Appearance

Appearance settings for Org-mode

Org bullets
(use-package org-bullets
  :defer t
  :ensure t
  :init (add-hook 'org-mode-hook 'org-bullets-mode)
  :config 
  (setq org-bullets-bullet-list '("" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ))
  )
Org Prettify blocks

Make source blocks look better.

(with-eval-after-load 'org
  (defvar-local rasmus/org-at-src-begin -1
    "Variable that holds whether last position was a ")

  (defvar rasmus/ob-header-symbol ?☰
    "Symbol used for babel headers")

  (defun rasmus/org-prettify-src--update ()
    (let ((case-fold-search t)
          (re "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*")
          found)
      (save-excursion
        (goto-char (point-min))
        (while (re-search-forward re nil t)
          (goto-char (match-end 0))
          (let ((args (org-trim
                       (buffer-substring-no-properties (point)
                                                       (line-end-position)))))
            (when (org-string-nw-p args)
              (let ((new-cell (cons args rasmus/ob-header-symbol)))
                (cl-pushnew new-cell prettify-symbols-alist :test #'equal)
                (cl-pushnew new-cell found :test #'equal)))))
        (setq prettify-symbols-alist
              (cl-set-difference prettify-symbols-alist
                                 (cl-set-difference
                                  (cl-remove-if-not
                                   (lambda (elm)
                                     (eq (cdr elm) rasmus/ob-header-symbol))
                                   prettify-symbols-alist)
                                  found :test #'equal)))
        ;; Clean up old font-lock-keywords.
        (font-lock-remove-keywords nil prettify-symbols--keywords)
        (setq prettify-symbols--keywords (prettify-symbols--make-keywords))
        (font-lock-add-keywords nil prettify-symbols--keywords)
        (while (re-search-forward re nil t)
          (font-lock-flush (line-beginning-position) (line-end-position))))))

  (defun rasmus/org-prettify-src ()
    "Hide src options via `prettify-symbols-mode'.

  `prettify-symbols-mode' is used because it has uncollpasing. It's
  may not be efficient."
    (let* ((case-fold-search t)
           (at-src-block (save-excursion
                           (beginning-of-line)
                           (looking-at "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*"))))
      ;; Test if we moved out of a block.
      (when (or (and rasmus/org-at-src-begin
                     (not at-src-block))
                ;; File was just opened.
                (eq rasmus/org-at-src-begin -1))
        (rasmus/org-prettify-src--update))
      ;; Remove composition if at line; doesn't work properly.
      ;; (when at-src-block
      ;;   (with-silent-modifications
      ;;     (remove-text-properties (match-end 0)
      ;;                             (1+ (line-end-position))
      ;;                             '(composition))))
      (setq rasmus/org-at-src-begin at-src-block)))

  (defun rasmus/org-prettify-symbols ()
    (mapc (apply-partially 'add-to-list 'prettify-symbols-alist)
          (cl-reduce 'append
                     (mapcar (lambda (x) (list x (cons (upcase (car x)) (cdr x))))
                             `(("#+begin_src" . ?╦) ;; ➤ 🖝 ➟ ➤ ✎ ✎
                               ("#+end_src"   . ?╩) ;; □
                               ("#+header:" . ,rasmus/ob-header-symbol)
                               ("#+begin_comment" . ?✎)
                               ("#+end_comment" . ?✎)
                               ("#+begin_notes" . ?➤)
                               ("#+end_notes" . ?➤)
                               ("#+begin_quote" . )
                               ("#+end_quote" . )))))
    (turn-on-prettify-symbols-mode)
    (add-hook 'post-command-hook 'rasmus/org-prettify-src t t))
  (add-hook 'org-mode-hook #'rasmus/org-prettify-symbols))

Org Seek

Searching Org-mode with search tools.

(use-package org-seek
  :ensure t
  :commands (org-seek-string org-seek-regexp org-seek-headlines)
  )

Org-Wiki

  (use-package org-wiki
    :ensure nil
    :commands (org-wiki-open org-wiki-helm org-wiki-dired org-wiki-index)
    :init 
    (setq org-wiki-location "~/Dropbox/Work/wiki")
  )

(defun org-wiki-export-html-sync ()
  "Export all pages to html in synchronous mode."
  (interactive)
  (let ((org-html-htmlize-output-type 'css)
        (org-html-htmlize-font-prefix "org-")
        )
    (org-publish
     `("html"
       :base-directory       ,org-wiki-location
       :base-extension        "org"
       :publishing-directory  "~/Dropbox/Work/wiki/html"
       ;; :publishing-function    org-html-publish-to-html
       :publishing-function (org-pandoc-publish-to-html5)
       :org-pandoc-table-of-contents t
       :org-pandoc-bibliography "/Users/Roambot/Dropbox/Work/Master.bib"

       )
     t
     )))
   
(defun org-wiki-header ()
  "Insert a header at the top of the file."
  (interactive)
  (save-excursion
     (goto-char (point-min))
     (insert (format
              (string-trim "
#+TITLE: %s
#+DESCRIPTION:
#+KEYWORDS:
#+SETUPFILE: ~/.emacs.d/elisp/org-html-themes/setup/theme-bigblow.setup
#+STARTUP:  overview

Related:

[[wiki:index][Index]]")
               (file-name-base (buffer-file-name))
                     ))))
  ;; (defun org-wiki-export-html-sync ()
  ;;   "Export all pages to html in synchronous mode."
  ;;   (interactive)
  ;;   (let ((org-html-htmlize-font-prefix "org-")
  ;;         )

  ;; (defun org-wiki-export-html-sync ()
  ;;   "Export all pages to html in synchronous mode."
  ;;   (interactive)
  ;;   (let ((org-html-htmlize-output-type 'css)
  ;;         (org-html-htmlize-font-prefix "org-")
  ;;         )

      ;; (org-publish
      ;;  `("html"
      ;;    :base-directory       ,org-wiki-location
      ;;    :base-extension        "org"
      ;;    :publishing-directory  "~/Dropbox/work/wiki/html"
      ;;    :publishing-function   org-twbs-publish-to-html
      ;;    ;; settings
      ;;    :author "Colin McLear"
      ;;    :email "mclear@unl.edu"
      ;;    :toc nil
      ;;    :with-timestamps nil
      ;;    :time-stamp-file nil
      ;;    :timestamp nil
      ;;    ;; :org-pandoc-bibliography "~/Dropbox/Work/Master.bib"
      ;;    ;; :org-pandoc-csl "~/.pandoc/styles/chicago-author-date.csl"
      ;;    )
      ;;  t
      ;;  )))

  ;; (defun org-wiki-export-html ()
  ;;   "Export all pages to html.
  ;; Note: This function doesn't freeze Emacs since it starts another Emacs process."
  ;;   (interactive)
  ;;   (compile (mapconcat 'identity
  ;;                       `(,org-wiki-emacs-path
  ;;                         "--batch"
  ;;                         "-l" ,user-init-file
  ;;                         "-f" "org-wiki-export-html-sync"
  ;;                         "--kill"
  ;;                         )
  ;;                       " "
  ;;                       )))

Org-Brain

A knowledge base using org-mode

(use-package org-brain
  :ensure nil
  :load-path "~/.emacs.d/elisp/org-brain"
  :config
  (setq org-brain-path "~/projects/notebook/content/org_notes")
)

Org-Twitter-Bootstrap

Publish using twitter bootstrap css

(use-package ox-twbs
  :commands org-twbs-export-to-html)

Org Template Expansions

(add-to-list 'org-structure-template-alist
  '("E" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC"))
(add-to-list 'org-structure-template-alist
  '("n" "#+BEGIN_NOTES\n?\n#+END_NOTES"))
(add-to-list 'org-structure-template-alist
  '("t" "#+BEGIN_COMMENT TODO: ?  #+END_COMMENT"))
(add-to-list 'org-structure-template-alist
  '("b" "#+REVEAL: split?"))
(add-to-list 'org-structure-template-alist
  '("f" "#+ATTR_REVEAL: :frag (appear)?"))

Org Indirect Buffer

Some advice to automatically switch to a new indirect buffer upon creation

(defadvice org-tree-to-indirect-buffer (after org-tree-to-indirect-buffer-after activate) (other-window 1))

Org Functions

Some useful org-specific functions

Org-Fill Functions

Functions to calculate apt offsets and call regular org fill stuff. There’s a useful stack overflow thread on this.

(defun calc-offset-on-org-level ()
  "Calculate offset (in chars) on current level in org mode file."
  (* (or (org-current-level) 0) org-indent-indentation-per-level))

(defun my-org-fill-paragraph (&optional JUSTIFY)
  "Calculate apt fill-column value and fill paragraph."
  (let* ((fill-column (- fill-column (calc-offset-on-org-level))))
    (org-fill-paragraph JUSTIFY)))

(defun my-org-auto-fill-function ()
  "Calculate apt fill-column value and do auto-fill"
  (let* ((fill-column (- fill-column (calc-offset-on-org-level))))
    (org-auto-fill-function)))
    
(defun my-org-mode-hook ()
  (setq fill-paragraph-function   'my-org-fill-paragraph
        normal-auto-fill-function 'my-org-auto-fill-function))

(add-hook 'org-load-hook 'my-org-mode-hook)
(add-hook 'org-mode-hook 'my-org-mode-hook)
Narrow & Advance/Retreat

Functions to advance forwards or backwards through narrowed tree

(defun org-advance ()
  (interactive)
  (when (buffer-narrowed-p)
    (beginning-of-buffer)
    (widen)
    (org-forward-heading-same-level 1))
  (org-narrow-to-subtree))

(defun org-retreat ()
  (interactive)
  (when (buffer-narrowed-p)
    (beginning-of-buffer)
    (widen)
    (org-backward-heading-same-level 1))
  (org-narrow-to-subtree))

Helm-Bibtex

Great for managing citations and notes

(use-package helm-bibtex
  :ensure t
  :commands helm-bibtex
  :config
  (setq bibtex-completion-bibliography "/Users/roambot/Dropbox/Work/Master.bib" 
        bibtex-completion-library-path "/Users/roambot/Dropbox/Work/MasterLib/"
        bibtex-completion-pdf-field nil
        bibtex-completion-notes-path "/Users/Roambot/projects/notebook/content/org_notes"
        bibtex-completion-additional-search-fields '(keywords)
        bibtex-completion-notes-extension ".org"
        helm-bibtex-full-frame nil) 
        ;; Set insert citekey with markdown citekeys for org-mode
  (setq bibtex-completion-format-citation-functions
        '((org-mode    . bibtex-completion-format-citation-pandoc-citeproc)
        (latex-mode    . bibtex-completion-format-citation-cite)
        (markdown-mode . bibtex-completion-format-citation-pandoc-citeproc)
        (default       . bibtex-completion-format-citation-default)))
  (setq bibtex-completion-display-formats
        '((t . "${author:36} ${title:*} ${year:4} ${=has-pdf=:1}${=has-note=:1} ${=type=:7}")))
  ;; Set default action for helm-bibtex as inserting citation
  (helm-delete-action-from-source "Insert citation" helm-source-bibtex)
  (helm-add-action-to-source "Insert citation" 'helm-bibtex-insert-citation helm-source-bibtex 0)
  (setq bibtex-completion-pdf-symbol "")
  (setq bibtex-completion-notes-symbol "")
  )

;; Set global shortcut for calling helm-bibtex
 (general-define-key "H-b" 'helm-bibtex)

Markdown mode

Markdown settings

(use-package markdown-mode
  :defer t
  :mode (("\\.markdown\\'" . markdown-mode)
         ("\\.md\\'"       . markdown-mode))
  :init
  ;; markdown hooks
  (add-hook 'markdown-mode-hook
        '(lambda ()
           (turn-on-auto-fill) (linum-mode) (centered-cursor-mode) (set-fill-column 78) (flyspell-mode 1) (pandoc-mode) (hl-todo-mode) (git-gutter-mode t)))
  (setq markdown-command "pandoc"
          markdown-enable-math t
          markdown-nested-imenu-heading-index t
          markdown-open-command "/Users/Roambot/bin/scripts/mark.sh"
          )
     ;; add keybindings to hook
   :config
   ;; remove strikout comment face
   (set-face-attribute 'markdown-comment-face nil 
   :weight 'bold :strike-through nil)
   ;; Header navigation in normal state movements
   (general-define-key :states '(normal) :keymaps 'markdown-mode-map
        "TAB" 'markdown-cycle
        "gj"  'outline-forward-same-level
        "gk"  'outline-backward-same-level
        "gh"  'outline-up-heading
        ;; next visible heading is not exactly what we want but close enough
        "gl"  'outline-next-visible-heading)
        ;; "<return>" 'markdown-jump

     ;; Promotion, Demotion
   (general-define-key :states '(normal insert emacs) :keymaps 'markdown-mode-map
     "M-h" 'markdown-promote
     "M-j" 'markdown-move-down
     "M-k" 'markdown-move-up
     "M-l" 'markdown-demote
     ;; fix wrong emacs keybindings
     "C-c C-j" 'markdown-jump
     "C-c C-l" 'markdown-insert-list-item
     )
     (add-hook 'markdown-mode-hook #'my-markdown-config)
)

Pandoc

Pandoc mode for markdown conversion

(use-package pandoc-mode
  :defer t  
  :config
  (progn
    (defun run-pandoc ()
      "Start pandoc for the buffer and open the menu"
      (interactive)
      (pandoc-mode)
      (pandoc-main-hydra/body))
    (add-hook 'pandoc-mode-hook 'pandoc-load-default-settings)

    (defun pandoc-pdf-open ()
      "Open created PDF file"  
      (interactive)
      (find-file (concat (file-name-sans-extension buffer-file-name) ".pdf")))
      )
  :init
  (progn
    (setq pandoc-data-dir "~/.emacs.d/pandoc-mode/")
    ;; help pandoc find xelatex
    (setenv "PATH" (concat (getenv "PATH") ":/Library/TeX/texbin"))))

Critic markup

(use-package cm-mode
  :defer t
  :ensure t
  :disabled t ;; causes font-lock error in markdown mode
  :init
  (add-hook 'markdown-mode-hook 'cm-mode))

Deft Notes

(use-package deft
  :commands (deft deft-find-file cpm/deft)
  :init
  (progn
    ;; start in insert mode
    (add-to-list 'evil-insert-state-modes 'deft-mode)
    (setq deft-extensions '("org" "md" "txt")
          deft-directory "~/projects/notebook/content/org_notes"
          deft-text-mode 'org-mode
          deft-use-filter-string-for-filename t ;; use filter string as filename
          deft-org-mode-title-prefix t ;; add #+TITLE prefix
          deft-recursive t  ;; search recursively in folders
          deft-use-filename-as-title t)
  :config
  (progn
    (general-define-key :states '(insert) :keymaps 'deft-mode-map
      "C-j" 'next-line
      "C-k" 'previous-line)
    (general-define-key :states '(normal) :keymaps 'deft-mode-map
      "d" 'deft-delete-file
      "I" 'deft-toggle-incremental-search
      "n" 'deft-new-file
      "r" 'deft-rename-file))))
;; Make sure titles have no spaces: from [[http://pragmaticemacs.com/category/deft/][pragmaticemacs]]
;;advise deft-new-file-named to replace spaces in file names with -
(defun bjm-deft-strip-spaces (args)
  "Replace spaces with - in the string contained in the first element of the list args. Used to advise deft's file naming function."
  (list (replace-regexp-in-string " " "-" (car args)))
  )
(advice-add 'deft-new-file-named :filter-args #'bjm-deft-strip-spaces)

;;function to run deft in specified directory
(defun any-deft (dir)
  "Run deft in directory DIR"
  (setq deft-directory dir)
  (switch-to-buffer "*Deft*")
  (kill-this-buffer)
  (require 'org)
  (deft)
  )
(defun big-notes ()
  "Goto main notes with deft"
  (interactive)
  (any-deft "~/Dropbox/Notes")
  (kill-this-buffer)
  (any-deft "~/Dropbox/Notes")
)
(defun research-notes ()
  "Goto research notes"
  (interactive)
  (any-deft "~/projects/notebook/content/org_notes"))

Interleave

Useful when taking notes

(use-package interleave
  :commands interleave)

Lorem ipsum

Make arbitrary blocks or sentences of text.

(use-package lorem-ipsum
  :ensure t
  :defer t
  :config 
  (lorem-ipsum-use-default-bindings)
  )

Palimpsest mode

(use-package palimpsest
  :defer t
  :diminish palimpsest-mode
  :init 
  (add-hook 'markdown-mode-hook 'palimpsest-mode)
  (add-hook 'org-mode-hook 'palimpsest-mode))

LaTeX

;; Basic settings
(use-package auctex
  :ensure t
  :defer t
  :mode ("\\.tex\\'" . latex-mode)
  :commands (latex-mode LaTeX-mode plain-tex-mode)
  :init
  (progn
    (add-hook 'LaTeX-mode-hook #'LaTeX-preview-setup)
    (add-hook 'LaTeX-mode-hook #'flyspell-mode)
    (add-hook 'LaTeX-mode-hook #'turn-on-reftex)
    (setq-default TeX-engine 'xetex)
    (setq TeX-auto-save t
          TeX-parse-self t
          TeX-save-query nil
          TeX-PDF-mode t)
    (setq-default TeX-master nil)))

(use-package preview
  :ensure nil
  :after auctex
  :commands LaTeX-preview-setup
  :init
  (progn
    (setq-default preview-scale 1.4
      preview-scale-function '(lambda () (* (/ 10.0 (preview-document-pt)) preview-scale)))))

(use-package reftex
  :commands turn-on-reftex
  :init
  (progn
    (setq reftex-plug-into-AUCTeX t)))

(use-package bibtex
  :defer t
  :mode ("\\.bib" . bibtex-mode)
  :init
  (progn
    (setq bibtex-align-at-equal-sign t)
    (add-hook 'bibtex-mode-hook (lambda () (set-fill-column 120)))))


;; Auto-fill for LaTeX
(defun schnouki/latex-auto-fill ()
  "Turn on auto-fill for LaTeX mode."
  (turn-on-auto-fill)
  (set-fill-column 80)
  (setq default-justification 'left))
(add-hook 'LaTeX-mode-hook #'schnouki/latex-auto-fill)

;; Compilation command
(add-hook 'LaTeX-mode-hook (lambda () (setq compile-command "latexmk -pdflatex=xelatex -f -pdf %f")))

;; Prevent ispell from verifying some LaTeX commands
;; http://stat.genopole.cnrs.fr/dw/~jchiquet/fr/latex/emacslatex
(defvar schnouki/ispell-tex-skip-alists
      '("cite" "nocite"
  "includegraphics"
  "author" "affil"
  "ref" "eqref" "pageref"
  "label"))
(setq ispell-tex-skip-alists
      (list
       (append (car ispell-tex-skip-alists)
         (mapcar #'(lambda (cmd) (list (concat "\\\\" cmd) 'ispell-tex-arg-end)) schnouki/ispell-tex-skip-alists))
       (cadr ispell-tex-skip-alists)))

;; Indentation with align-current in LaTeX environments
(defvar schnouki/LaTeX-align-environments '("tabular" "tabular*"))
(add-hook 'LaTeX-mode-hook
    (lambda ()
      (require 'align)
      (setq LaTeX-indent-environment-list
      ;; For each item in the list...
      (mapcar (lambda (item)
          ;; The car is an environment
          (let ((env (car item)))
            ;; If this environment is in our list...
            (if (member env schnouki/LaTeX-align-environments)
          ;; ...then replace this item with a correct one
          (list env 'align-current)
        ;; else leave it alone
        item)))
        LaTeX-indent-environment-list))))

;; Use dvipdfmx to convert DVI files to PDF in AUCTeX
(eval-after-load 'tex
  '(add-to-list 'TeX-command-list
                '("DVI to PDF" "dvipdfmx %d" TeX-run-command t t) t))

;; SyncTeX (http://www.emacswiki.org/emacs/AUCTeX#toc19)
(defun synctex/un-urlify (fname-or-url)
  "A trivial function that replaces a prefix of file:/// with just /."
  (if (string= (substring fname-or-url 0 8) "file:///")
      (substring fname-or-url 7)
    fname-or-url))

Doc View Mode

(use-package doc-view
    :defer t
    :init
    (fset 'doc-prev "\C-xo\C-x[\C-xo")
    (fset 'doc-next "\C-xo\C-x]\C-xo")
    (global-set-key (kbd "M-[") 'doc-prev)
    (global-set-key (kbd "M-]") 'doc-next)
    (evil-set-initial-state 'doc-view-mode 'normal)
    (evil-define-key 'normal doc-view-mode-map
      "/"  'spacemacs/doc-view-search-new-query
      "?"  'spacemacs/doc-view-search-new-query-backward
      "gg" 'doc-view-first-page
      "G"  'doc-view-last-page
      "gt" 'doc-view-goto-page
      "h"  'doc-view-previous-page
      "j"  'doc-view-next-line-or-next-page
      "k"  'doc-view-previous-line-or-previous-page
      "K"  'doc-view-kill-proc-and-buffer
      "l"  'doc-view-next-page
      "n"  'doc-view-search
      "N"  'doc-view-search-backward
      (kbd "C-d") 'doc-view-scroll-up-or-next-page
      (kbd "C-k") 'doc-view-kill-proc
      (kbd "C-u") 'doc-view-scroll-down-or-previous-page)
    :config
    (progn
      (defun spacemacs/doc-view-search-new-query ()
        "Initiate a new query."
        (interactive)
        (doc-view-search 'newquery))

      (defun spacemacs/doc-view-search-new-query-backward ()
        "Initiate a new query."
        (interactive)
        (doc-view-search 'newquery t))

(defcustom doc-view-autofit-timer-start 1.0
"Initial value (seconds) for the timer that delays the fitting when
`doc-view-autofit-fit' is called (Which is when a window
configuration change occurs and a document needs to be fitted)."
:type 'number
:group 'doc-view)

(defcustom doc-view-autofit-timer-inc 0.02
"Value to increase (seconds) the timer (see `doc-view-autofit-timer-start')
by, if there is another window configuration change occuring, before
it runs out."
:type 'number
:group 'doc-view)

(defcustom doc-view-autofit-default-fit 'width
"The fitting type initially used when mode is enabled.
Valid values are: width, height, page."
:type 'symbol
:group 'doc-view)

(defvar doc-view-autofit-mode-map
(let ((map (make-sparse-keymap)))
    (define-key map (kbd "C-c W") 'doc-view-autofit-width)
    (define-key map (kbd "C-c H") 'doc-view-autofit-height)
    (define-key map (kbd "C-c P") 'doc-view-autofit-page)
    map)
"Keymap used by `doc-view-autofit-mode'.")

(defun doc-view-autofit-set (type)
"Set autofitting to TYPE for current buffer."
(when doc-view-autofit-mode
    (setq doc-view-autofit-type type)
    (doc-view-autofit-fit)))

(defun doc-view-autofit-width ()
"Set autofitting to width for current buffer."
(interactive) (doc-view-autofit-set 'width))

(defun doc-view-autofit-height ()
"Set autofitting to height for current buffer."
(interactive) (doc-view-autofit-set 'height))

(defun doc-view-autofit-page ()
"Set autofitting to page for current buffer."
(interactive) (doc-view-autofit-set 'page))

(defun doc-view-autofit-fit ()
"Fits the document in the selected window's buffer
delayed with a timer, so multiple calls in succession
don't cause as much overhead."
(lexical-let
    ((window (selected-window)))
    (if (equal doc-view-autofit-timer nil)
        (setq doc-view-autofit-timer
            (run-with-timer
            doc-view-autofit-timer-start nil
            (lambda ()
                (if (window-live-p window)
                    (save-selected-window
                    (select-window window)
                    (cancel-timer doc-view-autofit-timer)
                    (setq doc-view-autofit-timer nil)
                    (cond
                        ((equal 'width doc-view-autofit-type)
                        (doc-view-fit-width-to-window))
                        ((equal 'height doc-view-autofit-type)
                        (doc-view-fit-height-to-window))
                        ((equal 'page doc-view-autofit-type)
                        (doc-view-fit-page-to-window))))))))
    (timer-inc-time doc-view-autofit-timer doc-view-autofit-timer-inc))))

(define-minor-mode doc-view-autofit-mode
"Minor mode for automatic (timer based) fitting in DocView."
:lighter " AFit" :keymap doc-view-autofit-mode-map :group 'doc-view
(when doc-view-autofit-mode
    (set (make-local-variable 'doc-view-autofit-type)
        doc-view-autofit-default-fit)
    (set (make-local-variable 'doc-view-autofit-timer) nil)
    (add-hook 'window-configuration-change-hook
            'doc-view-autofit-fit nil t)
    (doc-view-autofit-fit))
(when (not doc-view-autofit-mode)
    (remove-hook 'window-configuration-change-hook
                'doc-view-autofit-fit t)
    (when doc-view-autofit-timer
    (cancel-timer doc-view-autofit-timer)
    (setq doc-view-autofit-timer nil))
    (setq doc-view-autofit-type nil)))

(add-hook 'doc-view-mode-hook 'doc-view-autofit-mode)
;; reload when file changes
(add-hook 'doc-view-mode-hook 'auto-revert-mode)
;; continuous scroll mode
(setq doc-view-continuous t)
))

PDF-Tools

Better than doc-view, but doesn’t render well on retina screens :(

  (use-package pdf-tools
    :ensure t
    :defer t
    :mode (("\\.pdf$" . pdf-view-mode))
    :config
    (progn
      (pdf-tools-install)
      (evil-set-initial-state 'pdf-view-mode 'normal)
      (evil-set-initial-state 'pdf-outline-buffer-mode 'normal)
      (evil-define-key 'normal pdf-view-mode-map
          ;; Navigation
          "j"  'pdf-view-next-line-or-next-page
          "k"  'pdf-view-previous-line-or-previous-page
          "l"  'pdf-view-next-page 
          "h"  'pdf-view-previous-page
          "J"  'image-forward-hscroll
          "K"  'image-backward-hscroll
          "gg"  'pdf-view-first-page
          "G"  'pdf-view-last-page
          "gt"  'pdf-view-goto-page
          "gl"  'pdf-view-goto-label
          "u" 'pdf-view-scroll-down-or-previous-page
          "d" 'pdf-view-scroll-up-or-next-page
          "-"  'pdf-view-shrink
          "+"  'pdf-view-enlarge
          "="  'pdf-view-fit-page-to-window
          (kbd "C-u") 'pdf-view-scroll-down-or-previous-page
          (kbd "C-d") 'pdf-view-scroll-up-or-next-page
          (kbd "``")  'pdf-history-backward
          ;; Search
          "/" 'isearch-forward
          "?" 'isearch-backward
          ;; Actions
          "r"   'pdf-view-revert-buffer
          "o"   'pdf-links-action-perform
          "O"   'pdf-outline
          )
      (evil-define-key 'insert pdf-view-mode-map
          "y" 'pdf-view-kill-ring-save )

))      

;; for annotation and jumping to file
;; (add-to-list 'org-file-apps '("\\.pdf\\'" . org-pdfview-open))
;; (add-to-list 'org-file-apps '("\\.pdf::\\([[:digit:]]+\\)\\'" . org-pdfview-open)))
;; (eval-after-load 'org '(require 'org-pdfview))

Extract annotations

;; (use-package org-pdfview
;;   ;; :commands (org-pdfview-open)
;;   :after org
;;   :ensure t
;;   :config
;;   (add-to-list 'org-file-apps 
;;        '("\\.pdf\\'" . (lambda (file link)
;;                           (org-pdfview-open link)))))

(use-package pdf-tools-org 
  :ensure nil
  :commands (pdf-tools-org-export-to-org pdf-tools-org-import-from-org)
  :init
  (add-to-list 'load-path "/Users/Roambot/.emacs.d/pdf-tools-org/"))

    ;; Extracting annotations using pdf-tools
    ;; modified from https://github.com/politza/pdf-tools/pull/133 
    ;; taken from http://matt.hackinghistory.ca/2015/11/11/note-taking-with-pdf-tools/

    (defun mwp/pdf-multi-extract (sources)
    "Helper function to print highlighted text from a list of pdf's, with one org header per pdf, 
    and links back to page of highlight."
    (let (
          (output ""))
      (dolist (thispdf sources)
        (setq output (concat output (pdf-annot-markups-as-org-text thispdf nil level ))))
      (princ output))
    )

    (defun cpm/pdf-summary-extract (sources)
    "Helper function to print underlined text from a list of pdf's, with one org header per pdf, 
    and links back to page of highlight."
    (let (
          (output ""))
      (dolist (thispdf sources)
        (setq output (concat output (pdf-annot-summary-as-org-text thispdf nil level ))))
      (princ output))
    )

    ;; this is stolen from https://github.com/pinguim06/pdf-tools/commit/22629c746878f4e554d4e530306f3433d594a654
    (defun pdf-annot-edges-to-region (edges)
    "Attempt to get 4-entry region \(LEFT TOP RIGHT BOTTOM\) from several edges.
    We need this to import annotations and to get marked-up text, because annotations
    are referenced by its edges, but functions for these tasks need region."

    (let ((left0 (nth 0 (car edges)))
          (top0 (nth 1 (car edges)))
          (bottom0 (nth 3 (car edges)))
          (top1 (nth 1 (car (last edges))))
          (right1 (nth 2 (car (last edges))))
          (bottom1 (nth 3 (car (last edges))))
          (n (safe-length edges)))
      ;; we try to guess the line height to move
      ;; the region away from the boundary and
      ;; avoid double lines
      (list left0
            (+ top0 (/ (- bottom0 top0) 2))
            right1
            (- bottom1 (/ (- bottom1 top1) 2 )))))

    (defun pdf-annot-markups-as-org-text (pdfpath &optional title level)
    "Acquire highligh annotations as text, and return as org-heading"

    (interactive "fPath to PDF: ")  
    (let* ((outputstring "") ;; the text to be returned
            (title (or title (replace-regexp-in-string "-" " " (file-name-base pdfpath ))))
            (level (or level (1+ (org-current-level)))) ;; I guess if we're not in an org-buffer this will fail
            (levelstring (make-string level ?*)) ;; set headline to proper level
            (annots (sort (pdf-info-getannots nil pdfpath)  ;; get and sort all annots
                          'pdf-annot-compare-annotations)))
      ;; create the header
      (setq outputstring (concat levelstring " Quotes From " title "\n\n")) ;; create heading

      ;; extract text
      (mapc
        (lambda (annot) ;; traverse all annotations
          (if (eq 'highlight (assoc-default 'type annot))
              (let* ((page (assoc-default 'page annot))
                    ;; use pdf-annot-edges-to-region to get correct boundaries of annotation
                    (real-edges (pdf-annot-edges-to-region
                                  (pdf-annot-get annot 'markup-edges)))
                    (text (or (assoc-default 'subject annot) (assoc-default 'content annot)
                              (replace-regexp-in-string "\n" " " (pdf-info-gettext page real-edges nil pdfpath))))

                    (height (nth 1 real-edges)) ;; distance down the page
                    ;; use pdfview link directly to page number
                    (linktext (concat "[[pdfview:" pdfpath "::" (number-to-string page) 
                                      "++" (number-to-string height) "][" title  "]]" )))
                (setq outputstring (concat outputstring text " ("
                                          linktext ", " (number-to-string page) ")\n\n"))
                ))

          (if (eq 'text (assoc-default 'type annot))
              (let* ((page (assoc-default 'page annot))
                    ;; use pdf-annot-edges-to-region to get correct boundaries of annotation
                    (real-edges (pdf-annot-edges-to-region
                                  (pdf-annot-get annot 'markup-edges)))
                    (text (or (assoc-default 'subject annot) (assoc-default 'content annot)
                              (replace-regexp-in-string "\n" " " (pdf-info-gettext page real-edges nil pdfpath))))

                    (height (nth 1 real-edges)) ;; distance down the page
                    ;; use pdfview link directly to page number
                    (linktext (concat "[[pdfview:" pdfpath "::" (number-to-string page) 
                                      "++" (number-to-string height) "][" title  "]]" )))
                (setq outputstring (concat outputstring text " ("
                                          linktext ", " (number-to-string page) ")\n\n"))
                ))

            (if (eq 'underline (assoc-default 'type annot))
                (let* ((page (assoc-default 'page annot))
                      ;; use pdf-annot-edges-to-region to get correct boundaries of highlight
                      (real-edges (pdf-annot-edges-to-region
                                    (pdf-annot-get annot 'markup-edges)))
                      (text (or (assoc-default 'subject annot) (assoc-default 'content annot)
                                (replace-regexp-in-string "\n" " " (pdf-info-gettext page real-edges nil pdfpath))))

                      (height (nth 1 real-edges)) ;; distance down the page
                      ;; use pdfview link directly to page number
                      (linktext (concat "[[pdfview:" pdfpath "::" (number-to-string page) 
                                        "++" (number-to-string height) "][" title  "]]" )))
                  (setq outputstring (concat outputstring text " ("
                                            linktext ", " (number-to-string page) ")\n\n"))
                  ))
                )
        annots)
      outputstring ;; return the header
      )
    )

    (defun pdf-annot-summary-as-org-text (pdfpath &optional title level)
    "Acquire underlined annotations as text, and return as org-heading"

    (interactive "fPath to PDF: ")  
    (let* ((outputstring "") ;; the text to be returned
            (title (or title (replace-regexp-in-string "-" " " (file-name-base pdfpath ))))
            (level (or level (1+ (org-current-level)))) ;; I guess if we're not in an org-buffer this will fail
            (levelstring (make-string level ?*)) ;; set headline to proper level
            (annots (sort (pdf-info-getannots nil pdfpath)  ;; get and sort all annots
                          'pdf-annot-compare-annotations)))
      ;; create the header
      (setq outputstring (concat levelstring " Summary from " title "\n\n")) ;; create heading

      ;; extract text
      (mapc
        (lambda (annot) ;; traverse all annotations
            (if (eq 'underline (assoc-default 'type annot))
                (let* ((page (assoc-default 'page annot))
                      ;; use pdf-annot-edges-to-region to get correct boundaries of annotation
                      (real-edges (pdf-annot-edges-to-region
                                    (pdf-annot-get annot 'markup-edges)))
                      (text (or (assoc-default 'subject annot) (assoc-default 'content annot)
                                (replace-regexp-in-string "\n" " " (pdf-info-gettext page real-edges nil pdfpath))))

                      (height (nth 1 real-edges)) ;; distance down the page
                      ;; use pdfview link directly to page number
                      (linktext (concat "[[pdfview:" pdfpath "::" (number-to-string page) 
                                        "++" (number-to-string height) "][" title  "]]" )))
                  (setq outputstring (concat outputstring text " ("
                                            linktext ", " (number-to-string page) ")\n\n"))
                  ))
                )
        annots)
      outputstring ;; return the header
      )
    )

Zotero

Interface with Zotero.

(use-package zotxt
  :diminish (org-zoxt zotxt org-zotxt-mode)
  :config
  ;; (setq zotxt-default-bibliography-style "mkbehr-short")
  ;; Activate org-zotxt-mode in org-mode buffers
  (add-hook 'org-mode-hook (lambda () (org-zotxt-mode 1)))
  ;; Activate in markdown
  (add-hook 'markdown-mode-hook (lambda () (zotxt-easykey-mode 0))))

Proselint

(defun proselint ()
  (interactive)
  (flycheck-mode)
  (flycheck-select-checker 'proselint))

Serif Fonts

(defvar serif-preserve-default-list nil
  "A list holding the faces that preserve the default family and
  height when TOGGLE-SERIF is used.")
(setq serif-preserve-default-list
      '(;; LaTeX markup
        font-latex-math-face
        font-latex-sedate-face
        font-latex-warning-face
        ;; org markup
        org-latex-and-related
        org-meta-line
        org-verbatim
        org-block-begin-line
        ;; syntax highlighting using font-lock
        font-lock-builtin-face
        font-lock-comment-delimiter-face
        font-lock-comment-face
        font-lock-constant-face
        font-lock-doc-face
        font-lock-function-name-face
        font-lock-keyword-face
        font-lock-negation-char-face
        font-lock-preprocessor-face
        font-lock-regexp-grouping-backslash
        font-lock-regexp-grouping-construct
        font-lock-string-face
        font-lock-type-face
        font-lock-variable-name-face
        font-lock-warning-face))

(defun toggle-serif ()
  "Change the default face of the current buffer to use a serif family."
  (interactive)
  (when (display-graphic-p)  ;; this is only for graphical emacs
    ;; the serif font familiy and height, save the default attributes
    (let ((serif-fam "Minion Pro")
          (serif-height 150)
          (default-fam (face-attribute 'default :family))
          (default-height (face-attribute 'default :height)))
      (if (not (bound-and-true-p default-cookie))
          (progn (make-local-variable 'default-cookie)
                 (make-local-variable 'preserve-default-cookies-list)
                 (setq preserve-default-cookies-list nil)
                 ;; remap default face to serif
                 (setq default-cookie
                       (face-remap-add-relative
                        'default :family serif-fam :height serif-height))
                 ;; keep previously defined monospace fonts the same
                 (dolist (face serif-preserve-default-list)
                   (add-to-list 'preserve-default-cookies-list
                                (face-remap-add-relative
                                 face :family default-fam :height default-height)))
                 (message "Turned on serif writing font."))
        ;; undo changes
        (progn (face-remap-remove-relative default-cookie)
               (dolist (cookie preserve-default-cookies-list)
                 (face-remap-remove-relative cookie))
               (setq default-cookie nil)
               (setq preserve-default-cookies-list nil)
               (message "Restored default fonts."))))))

Private

(let ((private (expand-file-name "private.el" user-cache-directory))) 
(if (file-exists-p private)
	  (load-file private)))

Startup

Page Breaks

Dashboard depends on this.

(use-package page-break-lines
  :diminish "")

Dashboard

Startup with a dashboard listing recent files, bookmarks, and projects.

(use-package dashboard
  :config
  (setq dashboard-items '((recents  . 10)
                          (bookmarks . 10)
			                (projects . 10)))
  (setq dashboard-startup-banner "/home/mclear/.emacs.d/icons/128x128.png")
  ;; Set the title
  ;; (setq dashboard-banner-logo-title "The past is a foreign country. They do things differently there. -- L.P. Hartly, The Go-Between")
  (setq dashboard-banner-logo-title (message "Emacs initialized in %.2fs" (float-time (time-subtract (current-time) my-start-time))))
  (dashboard-setup-startup-hook)
  (general-define-key :states '(normal) :keymaps 'dashboard-mode-map
    "TAB" 'widget-forward
    "C-i" 'widget-forward
    "backtab" 'widget-backward
    "RET" 'widget-button-press
    "down-mouse-1" 'widget-button-click
    "g" #'dashboard-insert-startupify-lists
    "r" (dashboard-insert-shortcut "r" "Recent Files:")
    "m" (dashboard-insert-shortcut "m" "Bookmarks:")
    "p" (dashboard-insert-shortcut "p" "Projects:")
    ))

Server

Start server

(use-package server
  :defer 2
  :config
  (if (display-graphic-p)
      (unless (or (daemonp) (server-running-p))
         (message "Starting server..")
         (server-start)))
  )

Things to run at startup

;; (eshell)

Goals

Below are various things I want to perfect or try out in the config.

  • [X] Fix load time of config.org file
  • [X] Fix visual surround delete/change of various characters (org markup, dollar signs)
  • [X] Fix bookmark/desktop save
  • [X] Fix Helm locate so it loads faster (problem with bash alias setting)
  • [X] Fix load time of Projectile (make cache persist across sessions)