This is my Emacs configuration, a literate configuration.
A lot of this code (like too much to both sourcing for each block) is adapted from Spacemacs. You should use their configuration, not mine.
This should be in the appearance section of the org file, however doing that causes an unsightly flashing as they are first visible and then not visible. I’ll disable them here instead of that.
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(require 'package)
(setq package-archives
'(("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")
("org" . "http://orgmode.org/elpa/")))
(package-initialize)
Quelpa is a decentralized package management solution for emacs. I use it because I’m not good enough for my own packages to be on melpa.
(if (require 'quelpa nil t)
(quelpa-self-upgrade)
(with-temp-buffer
(url-insert-file-contents "https://raw.github.com/quelpa/quelpa/master/bootstrap.el")
(eval-buffer)))
I also employ use-package, which is the sane package configuration macro. I use a quelpa skew that allows me to get all the modular goodness of use-package in tandem with the decentralized freedom of quelpa.
(quelpa
'(quelpa-use-package
:fetcher github
:repo "quelpa/quelpa-use-package"))
(require 'quelpa-use-package)
Custom.el shouldn’t junk up this file
(setq custom-file "~/.emacs.d/custom.el")
A few packages are so essential to the main config that they deserve a top level heading. Core editor functionality, keybindings, etc, are included here.
package-enabled-p
is a function that returns true if the passed
package PKG
is not a member of the list disabled-packages
.
(defvar disabled-packages '())
(defun package-enabled-p (pkg)
(not (memq pkg disabled-packages)))
The package!
macro wraps use-package
with feature toggles that allow
easy enabling and disabling of packages. It also automatically adds
:quelpa t
unless another :quelpa
binding is specified.
(defmacro package! (pkg &rest forms)
(let ((forms (if (memq :quelpa forms)
forms
(append '(:quelpa t) forms))))
`(when (package-enabled-p ',pkg)
(use-package ,pkg
,@forms))))
I am among the stars aboard the Evil flagship to quote the spacemacs setup process. Vim keybindings are the only part of vim I want in my configuration.
(use-package evil
:quelpa t
:config (evil-mode 1))
evil-iedit-state
gives me sublime text multiple cursors editing
powers, and then some.
(package! evil-iedit-state
:commands (evil-iedit-state evil-iedit-state/iedit-mode)
:init
(progn
(setq iedit-current-symbol-default t
iedit-only-at-symbol-boundaries t
iedit-toggle-key-default nil)
(general-define-key :keymaps 'global :states '(normal visual)
"se" 'evil-iedit-state/iedit-mode)))
Rainbow delimiters so that I can read the parenthesis a little easier.
(package! rainbow-delimiters
:commands (rainbow-delimiters-mode)
:init (add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
General is the most generic name for a suitably general package. It provides a high level keybinding interface to ease the relative pain of binding keys in Evil.
(use-package general
:quelpa t
:init (setq general-default-keymaps 'evil-normal-state-map
general-default-prefix "SPC")
:config (general-evil-setup t))
which-key
provides functionality to discover keybindings.
(package! which-key
:diminish which-key-mode
:init (setq which-key-special-keys nil
which-key-use-C-h-for-paging t
which-key-prevent-C-h-from-cycling t
which-key-echo-keystrokes 0.02
which-key-max-description-length 32
which-key-sort-order 'which-key-key-order-alpha
which-key-idle-delay 0.4
which-key-allow-evil-operators t)
:config (which-key-mode))
I also like to have prefixes declared, to provide documentation of the bindings.
The prefix system I have hashed out works in a simple, but predictable
manor. When you call add-prefix
with a prefix and name, it looks up
which-key-replacement-alist
to find any prior prefixes declared with a
description. If it finds a previous prefix description, it appends to
that, otherwise creating a new prefix. This way, in calling
(add-prefix "f" "files")
and then (add-prefix "f" "find")
, which-key
will show “f → files/find”.
(defun prefix-description (key-seq)
(let* ((regexp-sequence (concat "\\`" (regexp-quote key-seq) "\\'"))
(replacement (cl-find-if (lambda (el) (equal (caar el) regexp-sequence)) which-key-replacement-alist)))
(if replacement
(cddr replacement)
"")))
(defun add-prefix (prefix name &optional mode)
(let* ((key-sequence (format "%s %s"
(if mode
","
"SPC")
prefix))
(previous-description (prefix-description key-sequence))
(replacement (if (equal previous-description "")
name
(concat previous-description "/" name))))
(if mode
(which-key-add-major-mode-key-based-replacements key-sequence replacement)
(which-key-add-key-based-replacements key-sequence replacement))))
Too many packages rely on this to not have it in core.
(package! company
:defer t
:diminish (company-mode . "λac")
:init (add-hook 'after-init-hook 'global-company-mode))
Basic keybindings to help the average evil/vim user feel at home
(defun jake/goto-config ()
(interactive)
(find-file "~/.emax"))
(cl-loop for (prefix . name) in '(("a" . "applications")
("b" . "buffers")
("c" . "compiling")
("e" . "syntax")
("E" . "emacs")
("f" . "find")
("f" . "file")
("i" . "information")
("n" . "narrow")
("s" . "search")
("q" . "quit")
("w" . "window")
("x" . "formatting")
("z" . "spelling"))
do (add-prefix prefix name))
(general-define-key :keymaps 'global :states '(normal visual emacs)
":" 'execute-extended-command
"ac" 'calculator-dispatch
"ad" 'dired
"ap" 'list-processes
"aP" 'proced
"au" 'undo-tree-visualize
"bd" 'kill-this-buffer
"bk" 'kill-buffer
"bw" 'read-only-mode
"bb" 'ivy-switch-buffer
"cC" 'compile
"ck" 'kill-compilation
"cr" 'recompile
"Ed" 'jake/goto-config
"fg" 'rgrep
"ff" 'counsel-find-file
"fl" 'find-file-literally
"fL" 'counsel-locate
"fr" 'counsel-recentf
"fS" 'evil-write-all
"fvd" 'add-dir-local-variable
"fvf" 'add-file-local-variable
"fvp" 'add-file-local-variable-prop-line
"im" 'counsel-woman
"nr" 'narrow-to-region
"np" 'narrow-to-page
"nf" 'narrow-to-defun
"nw" 'widen
"ss" 'swiper
"sj" 'counsel-imenu
"/" 'counsel-rg
"fs" 'save-buffer
"qq" 'delete-frame
"qz" 'evil-save-and-quit
"w2" 'split-window-vertically
"w3" 'split-window-horizontally
"wc" 'delete-window
"wH" 'evil-window-move-far-left
"wh" 'evil-window-left
"wJ" 'evil-window-move-very-bottom
"wj" 'evil-window-down
"wK" 'evil-window-move-very-top
"wk" 'evil-window-up
"wL" 'evil-window-move-far-right
"wl" 'evil-window-right
"wm" 'delete-other-windows
"wo" 'other-frame
"w-" 'split-window-below
"ww" 'other-window
"w/" 'split-window-right
"w=" 'balance-windows
"xaa" 'align)
(setq evil-want-Y-yank-to-eol t)
(general-define-key :keymaps 'global :prefix "" :states '(normal)
"J" 'join-line
;; Other bindings will end up here in time
)
I like the idea of splitting configuration into modules very much. Spacemacs has at least shown me a way to do this with directories, but the same principle can apply to directories. Ultimately I would like to use tags to toggle modules on and off.
Ivy is my preferred completion system of choice, (but helm is a close second).
(package! ivy
:diminish (ivy-mode . "")
:init (ivy-mode 1))
Counsel greatly expands the capabilities of ivy, to allow completion anywhere.
(package! counsel
:after ivy
:diminish (counsel-mode . "")
:config (counsel-mode))
I don’t like the jarring experience of having an entire page jump from bottom to top when I scroll by default. So instead I prefer to have smooth scrolling have lines faze out one by one off the screen.
(package! smooth-scrolling
:config (if (daemonp)
(add-hook 'after-make-frame-functions (lambda (frame)
(select-frame frame)
(smooth-scrolling-mode 1)))
(smooth-scrolling-mode 1)))
I hold this in the appearance category even though it could also be consider functional in some respects. It forces window splits to adhere to the golden ratio. For instance in a two window split the left window is 1/φ (0.618…) of the frame. This could be considered functional as it can greatly reduce the clutter that a 50:50 split sometimes generates.
(package! golden-ratio
:diminish (golden-ratio-mode . "")
:config (progn
(setq golden-ratio-exclude-modes '("bs-mode"
"calc-mode"
"ediff-mode"
"dired-mode"
"gud-mode"
"gdb-locals-mode"
"gdb-registers-mode"
"gdb-breakpoints-mode"
"gdb-threads-mode"
"gdb-frames-mode"
"gdb-inferior-io-mode"
"gud-mode"
"gdb-inferior-io-mode"
"gdb-disassembly-mode"
"gdb-memory-mode"
"restclient-mode"
"speedbar-mode"
))
(setq golden-ratio-extra-commands
(append golden-ratio-extra-commands
'(ace-window
ace-delete-window
ace-select-window
ace-swap-window
ace-maximize-window
avy-pop-mark
evil-avy-goto-word-or-subword-1
evil-avy-goto-line
windmove-left
windmove-right
windmove-up
windmove-down
evil-window-delete
evil-window-split
evil-window-vsplit
evil-window-left
evil-window-right
evil-window-up
evil-window-down
evil-window-bottom-right
evil-window-top-left
evil-window-mru
evil-window-next
evil-window-prev
evil-window-new
evil-window-vnew
evil-window-rotate-upwards
evil-window-rotate-downwards
evil-window-move-very-top
evil-window-move-far-left
evil-window-move-far-right
evil-window-move-very-bottom
select-window-0
select-window-1
select-window-2
select-window-3
select-window-4
select-window-5
select-window-6
select-window-7
select-window-8
select-window-9
buf-move-left
buf-move-right
buf-move-up
buf-move-down
ess-eval-buffer-and-go
ess-eval-function-and-go
ess-eval-line-and-go))
)
(golden-ratio-mode 1)
))
A lot of commands are added to the variable
golden-ratio-extra-commands
. After any of those commands are called,
golden-ratio recalculates the splits.
Base16 is love, base16 is life.
(package! base16-theme
:config (load-theme 'base16-ocean t))
Not gonna lie, this one is mostly superficial.
(package! powerline
;; 1.5 tends to be the only height airline renders well at.
)
This one is especially superficial but damn good looking. The monkeying around with daemon specific settings is from the fix for issue #25 on the github for airline-themes.
(package! airline-themes
:after powerline
:init (setq
airline-utf-glyph-separator-left #xe0b0
airline-utf-glyph-separator-right #xe0b2
airline-utf-glyph-subseparator-left #xe0b1
airline-utf-glyph-subseparator-right #xe0b3)
:config (if (daemonp)
(add-hook 'after-make-frame-functions (lambda (frame)
(select-frame frame)
(setq powerline-height (truncate (* 1.5 (frame-char-height))))
(load-theme 'airline-base16-gui-dark t)))
(load-theme 'airline-base16-gui-dark t)))
(package! spaceline-config
:quelpa spaceline
:init
(setq powerline-height (* 1.5 (frame-char-height)))
:config
(spaceline-spacemacs-theme))
My own package! No functionality, all glamour. Adds a centered splashscreen replacement for the default splashscreen.
(defun get-string-from-file (file)
(with-temp-buffer
(insert-file-contents file)
(buffer-substring-no-properties (point-min) (point-max))))
(package! cl-lib)
(package! pretty-splashscreen-mode
:quelpa (pretty-splashscreen-mode :repo "Triagle/pretty-splashscreen-mode" :fetcher github)
:config (progn
(setq
;; Set the splashscreen buffer name
pretty-splashscreen-buffer-name "*emax*"
;; Set the contents of the splashscreen
pretty-splashscreen-center-text t
pretty-splashscreen-buffer-contents (get-string-from-file "~/.emacs.d/boot.txt"))
;; Add a startup hook to swap to the splashscreen. `get-string-from-file' is an external, unrelated function
(setq initial-buffer-choice #'pspl/goto-splash)))
Smartparens is very, well, smart.
(package! smartparens
:diminish (smartparens-mode . "")
:config
(smartparens-global-strict-mode 1)
(require 'smartparens-config))
Evil surround can surround text in pairs (like brackets and such). I am fully aware that this functionality is replicated in smartparens, but I am used to evil surround, and so that is how it shall stay.
(package! evil-surround
:init
(global-evil-surround-mode 1))
I like my lisps.
Most lisps come with s-expressions, so any packages that deal with those in the general sense are initialized here.
(package! evil-lisp-state
:init (setq evil-lisp-state-global t)
:general (:keymaps 'global :states '(normal visual)
"k" 'evil-lisp-state))
Less useful right now, but every now and then some project grabs me and clojure becomes the goto choice.
Standard clojure mode.
(package! clojure-mode
:mode ("\\.clj$" . clojure-mode)
:config
(define-clojure-indent
;; Compojure
(ANY 2)
(DELETE 2)
(GET 2)
(HEAD 2)
(POST 2)
(PUT 2)
(context 2)
(defroutes 'defun)
;; Cucumber
(After 1)
(Before 1)
(Given 2)
(Then 2)
(When 2)
;; Schema
(s/defrecord 2)
;; test.check
(for-all 'defun)))
Cider might as well be included in the deal. Second best repl environment on earth (first being slime 🙌).
(package! cider
:general
( :prefix "," :keymaps 'clojure-mode-map :states '(normal)
"hh" 'cider-doc
"hg" 'cider-grimoire
"hj" 'cider-javadoc
"eb" 'cider-eval-buffer
"ee" 'cider-eval-last-sexp
"ef" 'cider-eval-defun-at-point
"er" 'cider-eval-region
"ew" 'cider-eval-last-sexp-and-replace
"fb" 'cider-format-buffer
"gb" 'cider-pop-back
"ge" 'cider-jump-to-compilation-error
"gg" 'cider-find-var
"gr" 'cider-jump-to-resource
"sb" 'cider-load-buffer
"sc" 'cider-connect
"si" 'cider-jack-in
"sI" 'cider-jack-in-clojurescript
"sq" 'cider-quit
"ss" 'cider-switch-to-repl-buffer
"sx" 'cider-refresh
"di" 'cider-inspect)
(general-evil-define-key 'normal cider-stacktrace-mode-map
"C-j" 'cider-stacktrace-next-cause
"C-k" 'cider-stacktrace-previous-cause
"TAB" 'cider-stacktrace-cycle-current-cause
"0" 'cider-stacktrace-cycle-all-causes
"1" 'cider-stacktrace-cycle-cause-1
"2" 'cider-stacktrace-cycle-cause-2
"3" 'cider-stacktrace-cycle-cause-3
"4" 'cider-stacktrace-cycle-cause-4
"5" 'cider-stacktrace-cycle-cause-5
"a" 'cider-stacktrace-toggle-all
"c" 'cider-stacktrace-toggle-clj
"d" 'cider-stacktrace-toggle-duplicates
"J" 'cider-stacktrace-toggle-java
"r" 'cider-stacktrace-toggle-repl
"T" 'cider-stacktrace-toggle-tooling)
:init
(progn
(setq cider-stacktrace-default-filters '(tooling dup)
cider-repl-pop-to-buffer-on-connect nil
cider-prompt-save-file-on-load nil
cider-repl-use-clojure-font-lock t)
(add-hook 'clojure-mode-hook 'cider-mode)
(add-hook 'cider-repl-mode-hook #'company-mode)
(add-hook 'cider-mode-hook #'company-mode)))
Common Lisp is my first lisp, is lisp senpai.
I wish all repls were of the same quality of slime
(package! slime
:commands slime-mode
:diminish (slime-mode . "λsl")
:general (:prefix "," :keymaps 'lisp-mode-map
"cc" 'slime-compile-file
"cC" 'slime-compile-and-load-file
"cl" 'slime-load-file
"cf" 'slime-compile-defun
"cr" 'slime-compile-region
"cn" 'slime-remove-notes
"eb" 'slime-eval-buffer
"ef" 'slime-eval-defun
"eF" 'slime-undefine-function
"ee" 'slime-eval-last-sexp
"er" 'slime-eval-region
"gg" 'slime-inspect-definition
"gb" 'slime-pop-find-definition-stack
"gn" 'slime-next-note
"gN" 'slime-previous-note
"ha" 'slime-apropos
"hA" 'slime-apropos-all
"hd" 'slime-disassemble-symbol
"hh" 'slime-describe-symbol
"hH" 'slime-hyperspec-lookup
"hp" 'slime-apropos-package
"ht" 'slime-toggle-trace-fdefinition
"hT" 'slime-untrace-all
"h<" 'slime-who-calls
"h>" 'slime-calls-who
"hr" 'slime-who-references
"hm" 'slime-who-macroexpands
"hs" 'slime-who-specializes
"ma" 'slime-macroexpand-all
"mo" 'slime-macroexpand-1
"se" 'slime-eval-last-expression-in-repl
"si" 'slime
"sq" 'slime-quit-lisp
"tf" 'slime-toggle-fancy-trace)
:init (progn
(setq
inferior-lisp-program "sbcl" ;; Should change if another lisp is used
slime-complete-symbol*-fancy t
slime-complete-symbol-function 'slime-fuzzy-complete-symbol
slime-contribs '(slime-fancy slime-indentation slime-sbcl-exts slime-scratch))
(add-hook 'lisp-mode-hook #'slime-mode))
:config (progn
(slime-setup)
(define-key slime-mode-map [(tab)] 'slime-fuzzy-complete-symbol)))
Company completion for that too plz.
(package! slime-company
:after company
:init (add-to-list 'slime-contribs 'slime-company))
Eldoc!
(package! eldoc
:defer t
:diminish (eldoc-mode . "λel") )
I’ve always been described as a schemer… (mmm scheme puns).
Uses the significantly less awesome geiser as it’s repl. I say less awesome because it frequently freezes whilst running chicken scheme sessions for any length of time.
(package! geiser
:general (:keymaps 'scheme-mode-map :prefix "," :states '(normal)
"si" 'run-geiser
"'" 'geiser-mode-switch-to-repl
"," 'lisp-state-toggle-lisp-state
"cc" 'geiser-compile-current-buffer
"cp" 'geiser-add-to-load-path
"eb" 'geiser-eval-buffer
"ee" 'geiser-eval-last-sexp
"ef" 'geiser-eval-definition
"el" 'lisp-state-eval-sexp-end-of-line
"er" 'geiser-eval-region
"gb" 'geiser-pop-symbol-stack
"gm" 'geiser-edit-module
"gn" 'next-error
"gN" 'previous-error
"hh" 'geiser-doc-symbol-at-point
"hd" 'geiser-doc-look-up-manual
"hm" 'geiser-doc-module
"h<" 'geiser-xref-callers
"h>" 'geiser-xref-callees
"il" 'geiser-insert-lambda
"me" 'geiser-expand-last-sexp
"mf" 'geiser-expand-definition
"mx" 'geiser-expand-region
"si" 'geiser-mode-switch-to-repl
"sb" 'geiser-eval-buffer
"sB" 'geiser-eval-buffer-and-go
"sf" 'geiser-eval-definition
"sF" 'geiser-eval-definition-and-go
"se" 'geiser-eval-last-sexp
"sr" 'geiser-eval-region
"sR" 'geiser-eval-region-and-go
"ss" 'geiser-set-scheme))
Don’t really use python too often on my own, but it’s handy to have around to bash out simple scripts (I normally use scheme for that though). Also uni uses it, so I don’t really gave a choice.
The standard python mode config is ripped straight from spacemacs
(package! python
:defer t
:init
(progn
(defun inferior-python-setup-hook ()
(setq indent-tabs-mode t))
(add-hook 'inferior-python-mode-hook #'inferior-python-setup-hook)
(general-evil-define-key '(normal visual) python-mode-map :prefix ","
"sB" 'python-shell-send-buffer-switch
"sb" 'python-shell-send-buffer
"sF" 'python-shell-send-defun-switch
"sf" 'python-shell-send-defun
"si" 'python-start-or-switch-repl
"sR" 'python-shell-send-region-switch
"sr" 'python-shell-send-region))
:config
(progn
;; add support for `ahs-range-beginning-of-defun' for python-mode
(with-eval-after-load 'auto-highlight-symbol
(add-to-list 'ahs-plugin-bod-modes 'python-mode))
(defun python-shell-send-buffer-switch ()
"Send buffer content to shell and switch to it in insert mode."
(interactive)
(python-shell-send-buffer)
(python-shell-switch-to-shell)
(evil-insert-state))
(defun python-shell-send-defun-switch ()
"Send function content to shell and switch to it in insert mode."
(interactive)
(python-shell-send-defun nil)
(python-shell-switch-to-shell)
(evil-insert-state))
(defun python-shell-send-region-switch (start end)
"Send region content to shell and switch to it in insert mode."
(interactive "r")
(python-shell-send-region start end)
(python-shell-switch-to-shell)
(evil-insert-state))
(defun python-start-or-switch-repl ()
"Start and/or switch to the REPL."
(interactive)
(let ((shell-process
(or (python-shell-get-process)
;; `run-python' has different return values and different
;; errors in different emacs versions. In 24.4, it throws an
;; error when the process didn't start, but in 25.1 it
;; doesn't throw an error, so we demote errors here and
;; check the process later
(with-demoted-errors "Error: %S"
;; in Emacs 24.5 and 24.4, `run-python' doesn't return the
;; shell process
(call-interactively #'run-python)
(python-shell-get-process)))))
(unless shell-process
(error "Failed to start python shell properly"))
(pop-to-buffer (process-buffer shell-process))
(evil-insert-state)))))
Anaconda mode for the docs and such.
(package! anaconda-mode
:defer t
:after python
:init
(add-hook 'python-mode-hook 'anaconda-mode)
:config
(progn
(general-evil-define-key '(normal visual) python-mode-map
:prefix ","
"hh" 'anaconda-mode-show-doc
"ga" 'anaconda-mode-find-assignments
"gb" 'anaconda-mode-go-back
"gu" 'anaconda-mode-find-references)
(diminish 'anaconda-mode "")))
Company complete for that as well.
(package! company-anaconda
:after company
:config (add-to-list 'company-backends '(company-anaconda)))
OCaml is a newcomer to my language swiss army knife, which changes very often (I mean at one point I wrote Java code).
Tuareg fixes innumerable problems with the default OCaml mode.
(package! tuareg
:mode ("\\.ml(i|y)?$" . taureg-mode)
:init (add-hook 'tuareg-mode-hook
(lambda ()
(when (functionp 'prettify-symbols-mode)
(prettify-symbols-mode)))))
Merlin is for the autocomplete. These OCaml names are brilliant.
(package! merlin
:diminish (merlin-mode . "λm")
:commands (merlin-mode)
:init (progn
(add-hook 'tuareg-mode-hook #'merlin-mode)
(add-hook 'caml-mode-hook #'merlin-mode)))
OCaml syntax is a hairy yeti of a problem (ironic for a language that enjoys excellent parsing tools), let’s have ocp-indent deal with that one.
(package! ocp-indent
:defer t
:init
(progn
(add-hook 'tuareg-mode-hook 'ocp-indent-caml-mode-setup)
(general-evil-define-key '(normal visual) tuareg-mode-map
"=" 'ocp-indent-buffer)))
Utop is on top of the OCaml repl game.
(package! utop
:diminish (utop-minor-mode . "")
:after tuareg
:general
(:keymaps 'utop-mode-map :states '(normal insert) :prefix ""
"C-<up>" 'utop-history-goto-prev
"C-<down>" 'utop-history-goto-next)
(general-define-key :keymaps 'tuareg-mode-map :prefix "," :states '(normal visual)
"si" 'utop
"sr" 'utop-eval-region)
:init
(add-hook 'tuareg-mode-hook 'utop-minor-mode)
:config
(setq utop-command "opam config exec -- utop -emacs"))
Please write my configuration :(
Needs it’s own special header. Would use emacs even if it only poorly implemented half of org mode.
Gotta get the org mode contrib package too, to really live the org mode lifestyle.
(package! org
:quelpa org-plus-contrib
:init (progn
(setq org-log-done t
org-startup-with-inline-images t
org-src-fontify-natively t)
(general-evil-define-key '(normal visual) org-mode-map
:prefix ","
"'" 'org-edit-special
"c" 'org-capture
"d" 'org-deadline
"D" 'org-insert-drawer
"e" 'org-export-dispatch
"f" 'org-set-effort
"P" 'org-set-property
":" 'org-set-tags
"a" 'org-agenda
"b" 'org-tree-to-indirect-buffer
"A" 'org-archive-subtree
"l" 'org-open-at-point
"T" 'org-show-todo-tree
"." 'org-time-stamp
"!" 'org-time-stamp-inactive
;; headings
"hi" 'org-insert-heading-after-current
"hI" 'org-insert-heading
;; More cycling options (timestamps, headlines, items, properties)
"L" 'org-shiftright
"H" 'org-shiftleft
"J" 'org-shiftdown
"K" 'org-shiftup
;; Change between TODO sets
"C-S-l" 'org-shiftcontrolright
"C-S-h" 'org-shiftcontrolleft
"C-S-j" 'org-shiftcontroldown
"C-S-k" 'org-shiftcontrolup
;; Subtree editing
"Sl" 'org-demote-subtree
"Sh" 'org-promote-subtree
"Sj" 'org-move-subtree-down
"Sk" 'org-move-subtree-up
;; tables
"ta" 'org-table-align
"tb" 'org-table-blank-field
"tc" 'org-table-convert
"tdc" 'org-table-delete-column
"tdr" 'org-table-kill-row
"te" 'org-table-eval-formula
"tE" 'org-table-export
"th" 'org-table-previous-field
"tH" 'org-table-move-column-left
"tic" 'org-table-insert-column
"tih" 'org-table-insert-hline
"tiH" 'org-table-hline-and-move
"tir" 'org-table-insert-row
"tI" 'org-table-import
"tj" 'org-table-next-row
"tJ" 'org-table-move-row-down
"tK" 'org-table-move-row-up
"tl" 'org-table-next-field
"tL" 'org-table-move-column-right
"tn" 'org-table-create
"tN" 'org-table-create-with-table.el
"tr" 'org-table-recalculate
"ts" 'org-table-sort-lines
"ttf" 'org-table-toggle-formula-debugger
"tto" 'org-table-toggle-coordinate-overlays
"tw" 'org-table-wrap-region
;; Multi-purpose keys
"," 'org-ctrl-c-ctrl-c
"*" 'org-ctrl-c-star
"RET" 'org-ctrl-c-ret
"-" 'org-ctrl-c-minus
"^" 'org-sort
"/" 'org-sparse-tree
"I" 'org-clock-in
"n" 'org-narrow-to-subtree
"N" 'widen
"O" 'org-clock-out
"q" 'org-clock-cancel
"R" 'org-refile
"s" 'org-schedule
;; insertion of common elements
"il" 'org-insert-link
"if" 'org-footnote-new
)))
Agenda mode too. I use use-package
rather than the package!
macro to avoid potential problems when
quelpa goes looking for a package that doesn’t exist.
(use-package org-agenda
:after org-plus-contrib
:config (general-evil-define-key '(normal visual) org-agenda-mode-map
"j" 'org-agenda-next-line
"k" 'org-agenda-previous-line))
Org indent mode for life.
(use-package org-indent
:commands org-indent-mode
:diminish (org-indent-mode . "")
:init (add-hook 'org-mode-hook 'org-indent-mode))
evil-org for keybinds I’m too lazy to work out.
(package! evil-org
:commands evil-org-mode
:diminish (evil-org-mode . "")
:init (add-hook 'org-mode-hook 'evil-org-mode))
Bullets for those sweet utf-8 bullet headers
(package! org-bullets
:defer t
:after org-plus-contrib
:init
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
Org pomodoro for the productivity nerd within me.
(package! org-pomodoro
:commands org-pomodoro
:defer t
:init
(general-evil-define-key '(normal visual) org-mode-map
:prefix ","
"p" 'org-pomodoro))
Undo tree is a cool little tool to navigate through a files history. However it’s lighter is ugly.
(diminish 'undo-tree-mode "")
Trailing whitespace is balrog spawn. Kill it in the thousand flaming pits of mordor.
(add-hook 'before-save-hook 'delete-trailing-whitespace)
Magit is the git porcelain I didn’t know I needed, and now I can’t live without it.
(package! magit
:general
(general-define-key :keymaps 'global :prefix "SPC" :states '(normal visual emacs)
"gc" 'magit-commit-popup
"gC" 'magit-checkout
"gd" 'magit-diff-popup
"gD" 'spacemacs/magit-diff-head
"ge" 'magit-ediff-compare
"gE" 'magit-ediff-show-working-tree
"gf" 'magit-fetch-popup
"gF" 'magit-pull-popup
"gi" 'magit-init
"gl" 'magit-log-popup
"gL" 'magit-log-buffer-file
"gP" 'magit-push-popup
"gs" 'magit-status
"gS" 'magit-stage-file
"gU" 'magit-unstage-file)
:init (add-prefix "g" "git")
:config (diminish 'magit-auto-revert-mode))
Make magit play a litter nicer with evil with evil-magit.
(package! evil-magit :after magit)
How on earth I pass high school English is beyond me.
No one wants to manually configure the dictionary you’re using.
(package! auto-dictionary
:defer t
:init (add-hook 'flypsell-mode-hook 'auto-dictionary-mode))
Spelling on the fly.
(package! flyspell
:defer t
:diminish (flyspell-mode "λfs")
:init
(progn
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)))
100% keen for narrowing my spelling corrections down with ivy. That is if the keybinding will work.
(package! flyspell-correct-ivy
:quelpa flyspell-correct
:after flyspell
:general ("z=" 'flyspell-correct-word-generic))
I make mistakes all the time.
In a shock move flycheck checks my syntax
(package! flycheck
:diminish (flycheck-mode . "λfl")
:commands (flycheck-mode flycheck-list-errors flycheck-buffer)
:general ("el" 'flycheck-list-errors
"en" 'flycheck-next-error
"ep" 'flycheck-previous-error)
:init (progn (setq ;; Removed checks on idle/change for snappiness
flycheck-check-syntax-automatically '(save mode-enabled)
flycheck-highlighting-mode 'symbols
flycheck-disabled-checkers '(emacs-lisp-checkdoc make))
(general-evil-define-key '(normal) flycheck-error-list-mode-map
"C-n" #'flycheck-error-list-next-error
"C-p" #'flycheck-error-list-previous-error
"j" #'flycheck-error-list-next-error
"k" #'flycheck-error-list-previous-error
"RET" #'flycheck-error-list-goto-error)
(add-hook 'prog-mode-hook #'global-flycheck-mode)))
Flycheck pos tip for those good contextual under point error messages
(package! flycheck-pos-tip
:after flycheck
:config
(progn (setq flycheck-pos-tip-timeout 10
flycheck-display-errors-delay 0.5)
(flycheck-pos-tip-mode +1)))
Whereas modules were about generic setup for languages, tooling, etc. The configuration itself is about personal changes I might make.
Source Code Pro is pro.
(add-to-list 'default-frame-alist '(font . "Source Code Pro-9"))
Lets clear up a few of those ugly defaults
Taken from buildfunthings. I like sensible saving defaults.
(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
kept-old-versions 6 ; oldest versions to keep when a new numbered backup is made (default: 2)
kept-new-versions 9 ; newest versions to keep when a new numbered backup is made (default: 2)
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)
)
Get those backup outta here
(setq
backup-directory-alist `(("." . ,(concat user-emacs-directory
"backups"))))
Ring no more.
(defun no-bell-plz ())
(setq ring-bell-function 'no-bell-plz)
(setq visible-bell nil)
Auto revert from files changed in buffer.
(auto-revert-mode)
(diminish 'auto-revert-mode)
(setq load-prefer-newer t)
Save millions of keystrokes with this one simple trick!
(fset 'yes-or-no-p 'y-or-n-p)
Uniquify makes buffers of the same name not of the same name
(use-package uniquify
;; Buffers get numerically unique identifiers appended
;; e.g buffer<2>
:init (setq uniquify-buffer-name-style 'forward))
Saveplace stores the place I was last at when I open a buffer.
(use-package saveplace
:init (progn
(setq-default save-place t)
(setq save-place-file (concat user-emacs-directory "places"))))
Bye fringe
(add-to-list 'default-frame-alist '(left-fringe . 0))
(add-to-list 'default-frame-alist '(right-fringe . 0))
Auto fill mode is cool too I guess.
(add-hook 'text-mode-hook 'turn-on-auto-fill)
(add-hook 'auto-fill-mode-hook (lambda ()
(diminish 'auto-fill-function "")))
I have an email that I use as a primary point of contact, and a name (shocker).
(setq user-mail-address "[email protected]"
user-full-name "Jake Faulkner")
Whilst not as massive as some, this may take a while.
Idle time is personal to me, 5 minutes is the average break after a pomodoro and a good amount of time for the computer to consider me afk.
(setq org-clock-ide-time 5)
I like my agenda customized quite specifically, and the code is from
many different places at once. gtd.org
is my personal organization org
file, so it needs to be an agenda file.
(setq org-agenda-files '("~/gtd.org")
;; ~/gtd.org is symlinked to a file of the same name in ~/Sync/org
org-directory "~/Sync/org")
I have a few more todo keywords that fit sort of inline with the getting things done methodology
- TODO
- A todo item that can be done
- NEXT
- A todo item that could be done in the future (it may depend on other todo items)
- PROJ
- A project header
- INBOX
- An item that has been added to the inbox
- WAITING
- An item waiting on some external factor to change (say other people). Requires explanation.
- DONE
- Completed item
- CANCELED
- An item that couldn’t be completed for some reason (requires explanation).
(setq org-todo-keywords '((sequence "TODO(t)" "NEXT(n)" "PROJ(p)" "INBOX(i)" "WAITING(w@/!)" "|" "DONE(d!)" "CANCELED(c@)")))
I have two main capture templates, an inbox template and a note template.
An example of an inbox item
\* INBOX Clean garage
An example of a note
\* Ideas for project :project: - maybe make a UI - what project was this anyway?
I use both frequently.
(setq org-capture-templates '(("i" "Inbox" entry (file+headline "~/gtd.org" "Inbox") "* INBOX %?\nCaptured: %t ")
("n" "Note" entry (file+headline "~/gtd.org" "Notes") "* %? %^g\nEntered: %t\n")))
My todo items get nested deeply, so I like to have the refile targets reach deeply as well.
(setq org-refile-targets '((nil . (:maxlevel . 6))))
A few of the most useful/common tags I use.
(setq org-tag-alist '(("@home" . ?h)
("@school" . ?s)
("hide" . ?a)
("@phone" . ?p)))
I hate unchecking checklists when completing a recurring task, org-checlist does this automatically among other things.
(setq org-modules '(org-checklist))
To avoid clogging up my org mode files with log entries, I pack them away in a drawer.
(setq org-log-into-drawer t)
Globally enable prettify symbols mode and also make my todo states a single unicode character.
(global-prettify-symbols-mode)
(add-hook 'org-mode-hook (lambda ()
(cl-loop for pair in '(("NEXT" . ?⇨)
("TODO" . ?✘)
("DONE" . ?✓)
("PROJ" . ?⇶)
("INBOX" . ?★)
("CANCELED" . ?⚐)
("WAITING" . ?✋))
do (push pair prettify-symbols-alist))))
Hide emphasis markers, I know what italics looks like.
(setq org-hide-emphasis-markers t)
Add a few hooks to notify me of when a pomodoro starts, ends, and when a break ends.
(defun jake/notify-send (title body)
(call-process "notify-send" nil 0 nil title body))
(add-hook 'org-pomodoro-finished-hook (lambda ()
(jake/notify-send "Pomodoro" "Break Start")))
(add-hook 'org-pomodoro-started-hook (lambda ()
(jake/notify-send "Pomodoro" "Pomodoro Started")))
(add-hook 'org-pomodoro-break-finished-hook (lambda ()
(jake/notify-send "Pomodoro" "Break Over")))
Finally, lets get those classy unicode org bullets.
(setq org-bullets-bullet-list '("•"))
My agenda is split into a few views
I need a couple of helper functions that help me create the agenda views I need.
zin/org-agenda-skip-tag
is a stackoverflow stolen function to skip org
agenda items with a given tag.
(defun zin/org-agenda-skip-tag (tag &optional others)
"Skip all entries that correspond to TAG.
If OTHERS is true, skip all entries that do not correspond to TAG."
(let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))
(current-headline (or (and (org-at-heading-p)
(point))
(save-excursion (org-back-to-heading)))))
(if others
(if (not (member tag (org-get-tags-at current-headline)))
next-headline
nil)
(if (member tag (org-get-tags-at current-headline))
next-headline
nil))))
org-agenda-skip-deadline-if-not-today
skips an org agenda item if it
isn’t today.
(defun org-agenda-skip-deadline-if-not-today ()
"If this function returns nil, the current match should not be skipped.
Otherwise, the function must return a position from where the search
should be continued."
(ignore-errors
(let ((subtree-end (save-excursion (org-end-of-subtree t)))
(deadline-day
(time-to-days
(org-time-string-to-time
(org-entry-get nil "DEADLINE"))))
(now (time-to-days (current-time))))
(and deadline-day
(not (= deadline-day now))
subtree-end))))
Finally set the agenda list to '()
to prevent an error when we try to add to the list later.
(setq org-agenda-custom-commands '())
Daily Action List
, bound to D
, displays a spread of my tasks in order
or priority-down
, deadline-up
, time-up
, effort-down
, and
tag-up
. Underneath this is a list of my active projects (indicated by
the PROJ keyword). Below the active projects section is the week at a
glance, a week’s worth of tasks and events for me to reflect on when
choosing which task to complete next. Finally below this is a list of
chores (marked with the procedure tag) that need to be done regularly
like cleaning my room, exercising and other menial tasks. Tasks marked
with the :hide: are excluded from the regular task lists.
Next Actions: gtd: [#B] Task A english: [#C] Task B ============ Active Projects: PROJ Complete english assignment ============ Week at a Glance: Monday 1 May 2017 english: Task B ... Sunday 7 May 2017 =========== Chores to do: gtd: Sched. 2x: Clean room :procedure:
(add-to-list 'org-agenda-custom-commands '("D" "Daily Action List" ((todo "TODO"
((org-agenda-overriding-header "Next Actions:")
(org-agenda-sorting-strategy
(quote ((agenda priority-down deadline-up time-up effort-down tag-up) )))
(org-agenda-skip-function
'(zin/org-agenda-skip-tag "hide"))))
(todo "PROJ" ((org-agenda-overriding-header "Active Projects:")))
(agenda "" ((org-agenda-ndays 1)
(org-agenda-overriding-header "Week at a glance:")
(org-agenda-skip-function
'(zin/org-agenda-skip-tag "hide"))
(org-agenda-sorting-strategy
(quote ((agenda priority-down deadline-down time-up effort-down tag-up) )))
(org-deadline-warning-days 0)))
(agenda "procedure"
((org-agenda-span 'day)
(org-agenda-skip-function '(org-agenda-skip-deadline-if-not-today))
(org-agenda-overriding-header "Chores to do:"))))))
Priority Reconciliation
, bound to P
, is a list of all tasks due
relatively soon. This is useful to remind me to bump certain tasks
priority if they are coming up in the next couple of days.
Day-agenda (W18): Friday 5 May 2017 gtd: In 2 d.: TODO [#A] Buy new laptop charger :@home:@phone:
(add-to-list 'org-agenda-custom-commands '("P" "Priority Reconciliation" ((agenda "" ((org-deadline-warning-days 2)
(org-agenda-span 'day)
(org-agenda-skip-function '(zin/org-agenda-skip-tag "concrete")))))))
A simple view showing only INBOX items.
(add-to-list 'org-agenda-custom-commands '("I" "Inbox Items" ((todo "INBOX"))))
Make the output more human readable, include all files.
(setq dired-listing-switches "-alh")
Omit \.*
and .*~
until I specifically wish to show them
(use-package dired-x
:after dired
:general (:keymaps 'dired-mode-map :states '(normal)
"_" 'dired-omit-mode)
:init (progn
(setq dired-omit-files "^\\(?:\\..*\\|.*~\\)$")
(setq-default dired-omit-files t)))
Lets make our user feel at home
(defun display-startup-echo-area-message ()
(message "EMAX has started, welcome home %s!" (user-login-name)))