Lexical binding
;; -*- lexical-binding: t -*-
Packages
Use-package setup
(unless (package-installed-p 'use-package)
(package-install 'use-package))
try
(use-package try
:ensure t)
pretty-symbols
(use-package pretty-symbols
:ensure t
:config
(global-prettify-symbols-mode))
(defun add-pretty-symbols-list (symbols)
"Add a list of prettified symbol-pairs to the buffer-local prettify-symbols-alist"
(setq-local prettify-symbols-alist (append prettify-symbols-alist
symbols)))
(defun add-pretty-symbols-hook (mode-hook symbols)
"Add a list of prettified symbol-pairs to a given mode."
(add-hook mode-hook `(lambda ()
(add-pretty-symbols-list (quote ,symbols)))))
(defvar double-struck-letters
'(("|A|" . ?𝔸)
("|B|" . ?𝔹)
("|C|" . ?ℂ)
("|D|" . ?𝔻)
("|E|" . ?𝔼)
("|F|" . ?𝔽)
("|G|" . ?𝔾)
("|H|" . ?ℍ)
("|I|" . ?𝕀)
("|J|" . ?𝕁)
("|K|" . ?𝕂)
("|L|" . ?𝕃)
("|M|" . ?𝕄)
("|N|" . ?ℕ)
("|O|" . ?𝕆)
("|P|" . ?ℙ)
("|Q|" . ?ℚ)
("|R|" . ?ℝ)
("|S|" . ?𝕊)
("|T|" . ?𝕋)
("|U|" . ?𝕌)
("|V|" . ?𝕍)
("|W|" . ?𝕎)
("|X|" . ?𝕏)
("|Y|" . ?𝕐)
("|Z|" . ?ℤ)
("|gamma|" . ?ℽ)
("|Gamma|" . ?ℾ)
("|pi|" . ?ℼ)
("|Pi|" . ?ℿ)))
(defvar arrows
'(("->" . ?→)
("-->" . ?⟶)
("<-" . ?←)
("<--" . ?⟵)
("<->" . ?↔)
("<-->" . ?⟷)
("=>" . ?⇒)
("==>" . ?⟹)
("<==" . ?⟸)
("<=>" . ?⇔)
("<==>" . ?⟺)
("|->" . ?↦)
("|-->" . ?⟼)
("<-|" . ?↤)
("<--|" . ?⟻)
("|=>" . ?⤇)
("|==>" . ?⟾)
("<=|" . ?⤆)
("<==|" . ?⟽)
("~>" . ?⇝)
("<~" . ?⇜)
(">->" . ?↣)
("<-<" . ?↢)
("->>" . ?↠)
("<<-" . ?↞)
(">->>" . ?⤖)
("<<-<" . ?⬻)
("<|-" . ?⇽)
("-|>" . ?⇾)
("<|-|>" . ?⇿)
("<-/-" . ?↚)
("-/->" . ?↛)
("<-|-" . ?⇷)
("-|->" . ?⇸)
("<-|->" . ?⇹)
("<-||-" . ?⇺)
("-||->" . ?⇻)
("<-||->" . ?⇼)
("-o->" . ?⇴)
("<-o-" . ?⬰)))
(defvar mathematical-symbols
'(("forall" . ?∀)
("exists" . ?∃)
("not" . ?¬)
("&&" . ?∧)
("||" . ?∨)
("==" . ?≡)
("/=" . ?≠)
("!=" . ?≠)
("<=" . ?≤)
(">=" . ?≥)
("/<" . ?≮)
("/>" . ?≯)
("++" . ?⧺)
("+++" . ?⧻)
("|||" . ?⫴)
("empty" . ?∅)
("elem" . ?∈)
("notElem" . ?∉)
("member" . ?∈)
("notMember" . ?∉)
("union" . ?∪)
("intersection" . ?∩)
("subsetOf" . ?⊆)
("properSubsetOf" . ?⊂)
("<<" . ?≪)
(">>" . ?≫)
("<<<" . ?⋘)
(">>>" . ?⋙)
("<|" . ?⊲)
("|>" . ?⊳)
("><" . ?⋈)
(":=" . ?≔)
("=:" . ?≕)
("<+>" . ?⊕)
("<*>" . ?⊛)))
(defvar greek-letters
'(("alpha" . ?α)
("beta" . ?β)
("gamma" . ?γ)
("delta" . ?δ)
("epsilon" . ?ε)
("zeta" . ?ζ)
("eta" . ?η)
("theta" . ?θ)
("iota" . ?ι)
("kappa" . ?κ)
("lambda" . ?λ)
("mu" . ?μ)
("nu" . ?ν)
("xi" . ?ξ)
("omicron" . ?ο)
("pi" . ?π)
("rho" . ?ρ)
("sigma_final" . ?ς)
("sigma" . ?σ)
("tau" . ?τ)
("upsilon" . ?υ)
("phi" . ?φ)
("chi" . ?χ)
("psi" . ?ψ)
("omega" . ?ω)))
which-key
(use-package which-key
:ensure t
:config
(which-key-mode))
web-mode
(use-package web-mode
:ensure t
:mode (("\\.html?\\'" . web-mode)
("\\.php?\\'" . web-mode)
("\\.js?\\'" . web-mode)
("\\.css?\\'" . web-mode)))
magit
(use-package magit
:ensure t
:config
(defun my-magit-status ()
(interactive)
(if (string= (buffer-name) "jetbrains-idea-ce")
(magit-status-internal "~/data/programming/Terasology/")
(magit-status-internal default-directory)))
:bind
(("C-c g" . my-magit-status)))
evil
(use-package evil
:ensure t
:config
;; Make Evil's point behave more like Emacs'
(setq evil-want-change-word-to-end nil)
(setq evil-move-cursor-back nil)
(evil-mode))
evil-surround
(use-package evil-surround
:ensure t
:config
(global-evil-surround-mode))
evil-cleverparens
(defun global-evil-cleverparens-mode ()
"Custom wrapper to enable evil-cleverparens-mode globally."
(interactive)
(add-hook 'evil-local-mode-hook #'evil-cleverparens-mode))
(use-package evil-cleverparens
:ensure t
:config
(global-evil-cleverparens-mode))
exwm
(use-package exwm
:ensure t
:config
(require 'exwm)
(require 'exwm-config)
;; Set the initial workspace number.
(setq exwm-workspace-number 0)
;; Make class name the buffer name
(add-hook 'exwm-update-class-hook
(lambda ()
(exwm-workspace-rename-buffer exwm-class-name)))
;; Don't use evil-mode in exwm buffers
(add-to-list 'evil-emacs-state-modes 'exwm-mode)
;; 's-w': Switch workspace
(exwm-input-set-key (kbd "s-w") #'exwm-workspace-switch)
;; 's-N': Switch to certain workspace
(dotimes (i 10)
(exwm-input-set-key (kbd (format "s-%d" i))
`(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
;; 's-r': Launch application
(exwm-input-set-key (kbd "s-r")
(lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
;; Better window management
(exwm-input-set-key (kbd "s-h") 'windmove-left)
(exwm-input-set-key (kbd "s-j") 'windmove-down)
(exwm-input-set-key (kbd "s-k") 'windmove-up)
(exwm-input-set-key (kbd "s-l") 'windmove-right)
(exwm-input-set-key (kbd "s-s") 'split-window-right)
(exwm-input-set-key (kbd "s-v") 'split-window-vertically)
(advice-add 'split-window-right :after 'windmove-right)
(advice-add 'split-window-vertically :after 'windmove-down)
(exwm-input-set-key (kbd "s-d") 'delete-window)
(exwm-input-set-key (kbd "s-q") '(lambda ()
(interactive)
(kill-buffer (current-buffer))))
;; Save my hands
(exwm-input-set-key (kbd "s-f") 'find-file)
(exwm-input-set-key (kbd "s-b") 'ido-switch-buffer)
(exwm-input-set-key (kbd "s-w") 'save-buffer)
;; Swap between qwerty and Dvorak with the same keyboard key
(exwm-input-set-key (kbd "s-;") '(lambda ()
(interactive)
(start-process-shell-command "aoeu" nil "aoeu")
(message "Qwerty")))
(exwm-input-set-key (kbd "s-z") '(lambda ()
(interactive)
(start-process-shell-command "asdf" nil "asdf")
(message "Dvorak")))
;; Line-editing shortcuts
(exwm-input-set-simulation-keys
'(([?\C-b] . left)
([?\C-f] . right)
([?\M-f] . C-right)
([?\M-b] . C-left)
([?\C-y] . S-insert)
([?\C-p] . up)
([?\C-n] . down)
([?\C-a] . home)
([?\C-e] . end)
([?\M-v] . prior)
([?\C-v] . next)
([?\C-d] . delete)
([?\C-k] . (S-end delete))))
;; Configure Ido
(exwm-config-ido)
;; Other configurations
(exwm-config-misc)
;; Allow switching buffers between workspaces
(setq exwm-workspace-show-all-buffers t)
(setq exwm-layout-show-all-buffers t)
(call-process-shell-command "~/data/scripts/startup.sh"))
smex
(use-package smex
:ensure t
:bind
(("M-x" . smex)))
zenburn-theme
(use-package zenburn-theme
:ensure t
:config
(load-theme 'zenburn t))
;; Lots of improvements from https://gist.github.com/belak/ca1c9ae75e53324ee16e2e5289a9c4bc
;; TODO: add moree, and check out other configs, starter packs, etc.
;; TODO: maybe configure fonts?
;; TODO: properly setup evil-mode bindingsido
ido
(use-package ido
:ensure t
:config
(ido-mode 1)
(ido-everywhere t)
(setq ido-enable-flex-matching t)
(setq ido-create-new-buffer 'always))
ido-ubiquitous
(use-package ido-ubiquitous
:ensure t
:config
(ido-ubiquitous-mode))
ido-vertical-mode
(use-package ido-vertical-mode
:ensure t
:config
(setq ido-vertical-define-keys 'C-n-C-p-up-down-left-right
ido-vertical-show-count t)
(ido-vertical-mode 1))
flx-ido
(use-package flx-ido
:ensure t
:config
(flx-ido-mode 1))
org
(use-package org
:ensure t
:config
(setq org-refile-use-outline-path 'file)
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(setq org-agenda-span 21)
(setq org-directory "~/data/org")
(setq org-agenda-files '("~/data/org/inbox.org"
"~/data/org/waiting.org"
"~/data/org/calendar.org"
"~/data/org/actions.org"
"~/data/org/projects.org"
"~/data/org/someday.org"
"~/data/org/review.org"
"~/data/org/reference.org"))
(setq org-refile-targets '((org-agenda-files :maxlevel . 2)
("~/data/org/archive/archive-projects.org" :level . 1)
("~/data/org/archive/archive-actions.org" :level . 1)))
(setf org-blank-before-new-entry '((heading . nil) (plain-list-item . nil)))
(setq org-capture-templates
'(("i" "Capture to inbox"
entry (file "~/data/org/inbox.org") "* %?")
("f" "Capture to inbox with a link to the current file"
entry (file "~/data/org/inbox.org") "* %?\n %a")))
(setq org-default-notes-file (concat org-directory "/inbox.org"))
(defun find-org-directory () (interactive) (find-file org-directory))
(defun my-org-capture () (interactive) (org-capture nil "i"))
(defun my-org-time-stamp ()
"Add a timestamp to an org-mode heading.
Put the timestamp on a newline, like org-schedule."
(interactive)
(let ((inhibit-quit t))
(save-excursion
(evil-open-below 1)
(unless (with-local-quit (org-time-stamp nil))
(call-interactively 'evil-delete-whole-line)))
(evil-normal-state)))
(add-pretty-symbols-hook 'org-mode-hook double-struck-letters)
(add-pretty-symbols-hook 'org-mode-hook mathematical-symbols)
(add-pretty-symbols-hook 'org-mode-hook arrows)
(add-pretty-symbols-hook 'org-mode-hook greek-letters)
:bind
(("C-c c" . my-org-capture)
("C-c a" . org-agenda)
("C-c o" . find-org-directory)
("C-c d" . my-org-time-stamp)))
auto-complete
(use-package auto-complete
:ensure t
:config
(ac-config-default)
(global-auto-complete-mode))
eclim
(use-package eclim
:ensure t
:config
(setq eclim-executable "/home/mitch/programs/eclipse-neon/eclim")
(add-hook 'java-mode-hook 'eclim-mode)
;; Fixes a problem with multi-project eclim projects adding the project name twice
(defun my-eclim-fix-relative-path (path)
(replace-regexp-in-string "^.*src/" "src/" path))
(advice-add 'eclim--project-current-file :filter-return #'my-eclim-fix-relative-path))
ace-jump-mode
(use-package ace-jump-mode
:ensure t
:config
;; Only search in the current frame
;; Might need to be adjusted if I want multi-monitor jumping
;; Currently exwm frames are always marked as visible, so 'visible won't work
;; (mapcar 'frame-visible-p (frame-list)) => (t t t t t t t)
(setq ace-jump-mode-scope 'frame)
:init
(evil-define-key '(normal motion) global-map "s" 'evil-ace-jump-word-mode)
:bind
(("C-l" . ace-jump-word-mode)))
relative line numbers
If I’m using the experimental line-numbers build, use the line-number features from that build. Otherwise, use linum-relative.
(if (boundp 'display-line-numbers)
(setq-default display-line-numbers 'relative)
(use-package linum-relative
:ensure t
:config
(setq linum-relative-current-symbol "")
(setq linum-relative-format "%3s ")
(linum-relative-global-mode)))
rainbow-delimiters
(use-package rainbow-delimiters
:ensure t
:config
(rainbow-delimiters-mode 1))
paredit
(use-package paredit
:ensure t
:config
(add-hook 'evil-cleverparens-mode-hook #'enable-paredit-mode))
gnus
(use-package gnus
:ensure t
:config
(org-babel-load-file (concat user-emacs-directory "gnus.el.org")))
gpg
(setq epa-pinentry-mode 'loopback)
(pinentry-start)
haskell
(use-package haskell-mode
:ensure t
:config
(add-pretty-symbols-hook 'haskell-mode-hook '(("::" . ?∷))))
Custom loads
(add-to-list 'load-path (concat user-emacs-directory "sources/exlb"))
(add-to-list 'load-path (concat user-emacs-directory "sources/exwm"))
General settings
UI
(blink-cursor-mode -1)
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(setq inhibit-startup-message t)
(display-time)
Consistent prompts
(fset 'yes-or-no-p 'y-or-n-p)
Don’t ask about creating new buffer
(setq confirm-nonexistent-file-or-buffer nil)
Use the primary clipboard for emacs
(setq select-enable-primary t)
(setq-default indent-tabs-mode nil)
Make tab try to autocomplete
(setq tab-always-indent 'complete)
Scroll by one line at a time
;; But on big jumps, re-center ponit
(setq scroll-conservatively 5)
Put all backup files into ~/tmp/backups
(setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
(setq backup-by-copying t)
Show the matching paren
(show-paren-mode 1)
(setq show-paren-delay 0)
Help at point
(setq help-at-pt-display-when-idle t)
(setq help-at-pt-timer-delay 0)
(help-at-pt-set-timer)
Set the font
(set-face-attribute 'default nil :height 135 :weight 'normal)
(setq-default line-spacing 4)
Automatically revert files if their contents changes on disk
Todo: make Emacs ask whether to revert modified buffer when it is modified on disk
(global-auto-revert-mode 1)
Show trailing whitespace
Todo: make trailing whitespace only show when you have left Evil insert state
(setq-default show-trailing-whitespace t)
Minibuffer
;; Allow to read from minibuffer while in minibuffer.
(setq enable-recursive-minibuffers t)
;; Show the minibuffer depth (when larger than 1)
(minibuffer-depth-indicate-mode 1)
Server start
(server-start)
Custom functions
eval-current-sexp
(defun eval-current-sexp (arg)
"Evaluate the current sexp (or the last sexp, if immediately following a )"
(interactive "P")
(save-excursion
(unless (looking-at ")")
(backward-char))
(paredit-forward-up)
(eval-last-sexp arg)))
(define-key global-map (kbd "C-c e") 'eval-current-sexp)
rename-file-and-buffer
(defun rename-file-and-buffer (new-name)
"Renames both current buffer and file it's visiting to NEW-NAME.
Taken from Steve Yegge's config (https://sites.google.com/site/steveyegge2/my-dot-emacs-file)."
(interactive "sNew name: ")
(let ((name (buffer-name))
(filename (buffer-file-name)))
(cond ((not filename)
(message "Buffer '%s' is not visiting a file!" name))
((get-buffer new-name)
(message "A buffer named '%s' already exists!" new-name))
(t
(rename-file filename new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil)))))
move-buffer-file
(defun move-buffer-file (dir)
"Moves both current buffer and file it's visiting to DIR.
Taken from Steve Yegge's config (https://sites.google.com/site/steveyegge2/my-dot-emacs-file)."
(interactive "DNew directory: ")
(let* ((name (buffer-name))
(filename (buffer-file-name))
(dir
(if (string-match dir "\\(?:/\\|\\\\)$")
(substring dir 0 -1) dir))
(newname (concat dir "/" name)))
(if (not filename)
(message "Buffer '%s' is not visiting a file!" name)
(copy-file filename newname 1)
(delete-file filename)
(set-visited-file-name newname)
(set-buffer-modified-p nil))))
auto-sharp-quote
(defun auto-sharp-quote ()
"Insert #' unless in a string or comment.
From http://endlessparentheses.com/get-in-the-habit-of-using-sharp-quote.html"
(interactive)
(call-interactively #'self-insert-command)
(let ((ppss (syntax-ppss)))
(unless (or (elt ppss 3))
(elt ppss 4)
(eq (char-after) ?')
(insert "'"))))
(evil-define-key 'normal-state 'emacs-lisp-mode-map "#" #'auto-sharp-quote)
(define-key emacs-lisp-mode-map "#" #'auto-sharp-quote)