40 KiB
- Packaging
- Keybinds
- Vim Emulation
- Emacs
- Organization
- Communication
- Web
- Tools
- Programming
Packaging
Package.el
Package.el is the built-in package manager in Emacs. This is where the fun begins.
(require 'package)
(setq package-archives
'(("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")
("melpa-stable" . "https://stable.melpa.org/packages/")
("marmalade" . "https://marmalade-repo.org/packages/")
("org" . "https://orgmode.org/elpa/")))
(setq package-enable-at-startup nil)
(package-initialize)
use-package
use-package is a nifty macro that interfaces with Package.el
, keeping package-specific
configuration all in once place. It's pretty much the basis of this entire config.
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
(setq use-package-compute-statistics t)
(setq use-package-always-ensure t)
(setq use-package-always-pin "melpa")
(setq use-package-verbose t)
Custom Keywords
A few useful :keyword
macros that extend the vanilla use-package
functionality.
:company
(require 'derived)
(defun use-package-company-normalize (name keyword args)
"Normalize the KEYWORD with NAME :company with arguments ARGS into a list of pairs for the handler."
(use-package-as-one (symbol-name keyword) args
(lambda (label arg)
(unless (or (consp arg) (use-package-non-nil-symbolp arg))
(use-package-error
(concat
label
"<symbol> or "
"(<symbol or list of symbols> . <symbol or function>) or "
"a list of these")))
(use-package-normalize-pairs
(lambda (k)
(or (use-package-non-nil-symbolp k)
(and (consp k)
(not (cdr (last k)))
(seq-every-p 'use-package-non-nil-symbolp k))))
#'use-package-recognize-function
name label arg))))
;;;###autoload
(defun use-package-company-handler (name _keyword args rest state)
"Generate a function and hook from each pair in NAME ARGS for the keyword with NAME :company, appending the forms to the ‘use-package’ declaration specified by REST and STATE."
(use-package-concat
(use-package-process-keywords name rest state)
(mapcan
(lambda (def)
(let ((modes (car def))
(backend (cdr def))
(fun (intern (concat "use-package-company-add-" (symbol-name (cdr def))))))
(when backend
(append
`((defun ,fun ()
(setq-local company-backends
(append company-backends '(,backend)))))
(mapcar
(lambda (mode)
`(add-hook
',(derived-mode-hook-name mode)
#',fun))
(if (use-package-non-nil-symbolp modes) (list modes) modes))))))
(use-package-normalize-commands args))))
(defalias 'use-package-normalize/:company 'use-package-company-normalize)
(defalias 'use-package-handler/:company 'use-package-company-handler)
(defalias 'use-package-autoloads/:company 'use-package-autoloads-mode)
(setq use-package-keywords
(let ((idx (+ 1 (cl-position :hook use-package-keywords))))
(append
(seq-subseq use-package-keywords 0 idx)
(list :company)
(nthcdr idx use-package-keywords))))
Keybinds
which-key
which-key displays a popup in the minibuffer that shows keybindings following incomplete commands.
(use-package which-key
:diminish
:config
(which-key-mode))
General
General is an excellent keybind manager that adds tons of useful macros.
Also set up a leader key and prefixes, like \
in Vim.
(use-package general
:config
(general-create-definer jf-leader-def
:keymaps 'override
:states '(normal motion insert emacs)
:prefix "SPC"
:non-normal-prefix "M-SPC")
(defun jf-create-wk-prefix (desc)
"Helper for creating which-key prefix descriptions.
Bind to a key with general to make which-key show DESC
as the prefix's description"
`(:ignore t :wk ,desc))
(defmacro jf-create-definers (definitions)
"A wrapper for general-create-definer.
For every pair in DEFINITIONS, creates a leader
with name jf-NAME-def and keybind SPC KEY or M-SPC KEY in normal mode."
`(progn
,@(mapcan
(lambda (def)
(let ((key (car def))
(name (cdr def)))
`((general-create-definer ,(intern (concat "jf-" name "-def"))
:keymaps 'override
:states '(normal insert emacs)
:prefix ,(concat "SPC " key)
:non-normal-prefix ,(concat "M-SPC " key))
(jf-leader-def ,key ',(jf-create-wk-prefix name)))))
definitions)))
(jf-create-definers
(("a" . "apps")
("b" . "buffers")
("f" . "files")
("g" . "git")
("h" . "help")
("m" . "major")
("o" . "org")
("p" . "projects")
("w" . "windows"))))
Macros
A helper for defining procedural keyboard macros
(defun jf-replace-regexps-in-string (str regexps)
"Replace all pairs of (regex . replacement) defined by REGEXPS in STR."
(if (null regexps)
str
(jf-replace-regexps-in-string
(replace-regexp-in-string (caar regexps) (cdar regexps) str t)
(cdr regexps))))
(defun jf-kbd (str)
"Convert STR into a keyboard macro string by replacing terminal key sequences with GUI keycodes."
(let ((jf-kbd-regex '(("ESC" . "<escape>")
("DEL" . "<delete>")
("BS" . "<backspace>")
("RET" . "<return>")
("SPC" . "<SPC>")
("TAB" . "<tab>"))))
(jf-replace-regexps-in-string str jf-kbd-regex)))
(defun jf-kbd-exec (str)
"Execute the key sequence defined by STR. Terminal based keys are expanded to their graphical counterparts."
(let ((minibuffer-message-timeout 0))
(execute-kbd-macro (read-kbd-macro (jf-kbd str)))))
(defmacro jf-kbd-defmacro (name &rest forms)
"Create an interactive function NAME with body FORMS, where the evaluation of each form is executed as a keyboard macro."
`(defun ,name ()
(interactive)
,@(mapcan (lambda (form) `((jf-kbd-exec ,form))) forms)))
Vim Emulation
Evil
Evil is pretty much the entirety of Vim in Emacs.
(use-package evil
:diminish undo-tree-mode
:preface
(defun jf-window-split ()
(interactive)
(evil-window-split)
(evil-window-down 1))
(defun jf-window-vsplit ()
(interactive)
(evil-window-vsplit)
(evil-window-right 1))
:config
(evil-mode t)
(jf-windows-def
"-" #'jf-window-split
"=" #'jf-window-vsplit
"b" #'balance-windows
"H" #'evil-window-far-left
"J" #'evil-window-bottom
"K" #'evil-window-top
"L" #'evil-window-far-right
"h" #'evil-window-left
"j" #'evil-window-right
"k" #'evil-window-down
"l" #'evil-window-right
"o" #'other-frame)
:custom
(evil-want-integration t)
(evil-want-keybinding nil)
(evil-want-fine-undo t))
Evil Collection
Evil Collection adds Evil bindings for all the parts of Emacs that Evil doesn't cover properly by default.
(use-package evil-collection
:after evil
:config
(evil-collection-init
'(calendar
cmake-mode
company
compile
custom
debug
dired
doc-view
elisp-mode
elisp-refs
eshell
eval-sexp-fu
flycheck
flymake
grep
help
ibuffer
image
image-dired
info
ivy
js2-mode
log-view
man
neotree
python
racer
realgud
which-key)))
Evil Extensions
Avy
An enhanced version of f
in Vim.
(use-package avy
:general
(:keymaps 'override
:states 'normal
"C-f" 'avy-goto-char-in-line
"C-F" 'avy-goto-char))
Subword
Make boundaries between words in camelCase act as separate words for evil motions.
(use-package subword
:init
(define-category ?U "Uppercase")
(define-category ?u "Lowercase")
(modify-category-entry (cons ?A ?Z) ?U)
(modify-category-entry (cons ?a ?z) ?u)
:config
(push '(?u . ?U) evil-cjk-word-separating-categories))
evil-surround
Use S
and a delimiter to surround in visual mode.
(use-package evil-surround
:after evil
:diminish
:config
(global-evil-surround-mode 1))
evil-goggles
Visual highlighting on evil motions
(use-package evil-goggles
:config
(evil-goggles-mode))
Emacs
Defaults
Configuration Editing
Add functions for editing and reloading the Emacs config files.
(defun jf-edit-config ()
(interactive)
(find-file jf-config-file))
(defun jf-edit-init ()
(interactive)
(find-file jf-init-file))
(defun jf-reload-config ()
(interactive)
(org-babel-load-file jf-config-file))
(jf-files-def
"e" (jf-create-wk-prefix "emacs files")
"ec" #'jf-edit-config
"ei" #'jf-edit-init
"er" #'jf-reload-config)
Add to Load Path
Create and add a folder to the load path for local lisp files. The folder itself and all descendants will be added to the path. These packages will take precedence over other libraries with the same name.
(unless (file-exists-p jf-load-path)
(make-directory jf-load-path))
(let ((default-directory jf-load-path))
(setq load-path
(append
(let ((load-path (copy-sequence load-path)))
(append
(copy-sequence (normal-top-level-add-to-load-path '(".")))
(normal-top-level-add-subdirs-to-load-path)))
load-path)))
File Not Found Functions
Offer to create parent folders when a file is opened Offer to create nonexistant parent directories.
(defun jf-create-nonexistant-directories ()
(let ((parent-directory (file-name-directory buffer-file-name)))
(when (and (not (file-exists-p parent-directory))
(y-or-n-p (format "Directory `%s' does not exist. Create it?" parent-directory)))
(make-directory parent-directory t)))) ; last argument specifies to behave like `mkdir -p'
(add-to-list 'find-file-not-found-functions #'jf-create-nonexistant-directories)
Customize Location
Make changes in M-x customize
go somewhere other than being schlunked into init.el
.
(setq custom-file (concat user-emacs-directory "_customize.el"))
(load custom-file t)
Disable Bell
Shut up, emacs.
(setq ring-bell-function #'ignore)
Shorter Prompts
Make yes-or-no
prompts ask for y-or-n
instead. Saves loads of time™.
(defalias 'yes-or-no-p #'y-or-n-p)
Move Backup Files
By default, emacs gunks up every folder with file~
backups
and #file#
lockfiles. Schlunk them all in /tmp
instead.
(setq backup-directory-alist
`((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
`((".*" ,temporary-file-directory t)))
Secure auth-source
GPG encrypt stored auth tokens from auth-source instead of storing them in plaintext.
(setq auth-sources '("~/.emacs.d/authinfo.gpg"))
Use UTF-8
Pleeeease default to UTF-8, Emacs.
(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)
Trash when Deleting
Don't permanently delete stuff unless asked.
(setq delete-by-moving-to-trash t)
Open Compressed Files
…automatically.
(setq auto-compression-mode t)
Save Minibuffer History
(savehist-mode 1)
(setq history-length 1000)
Double Spaces
Why sentences would need double spaces to end I do not know.
(set-default 'sentence-end-double-space nil)
Eval Print Level
Print more stuff when running C-x C-e
or (eval-last-sexp)
(setq eval-expression-print-level 100)
GC in Minibuffer
Don't garbage collect while the minibuffer is open, as heavy things like completion and searches are happening and will slow down with many garbage collections.
(add-hook 'minibuffer-setup-hook #'jf-inhibit-gc)
(add-hook 'minibuffer-exit-hook #'jf-resume-gc)
UI
Font
Engage a nice coding font.
(add-to-list 'default-frame-alist '(font . "Fira Code 12"))
(set-face-attribute 'default t :font "Fira Code 12")
Menu Bar
Disable the useless cruft at the top of the screen.
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
Modeline
Diminish
Adds support for :diminish
in use-package declarations, which hides a mode from the modeline.
(use-package diminish)
Column Number
Show line and column numbers in the modeline.
(setq line-number-mode t)
(setq column-number-mode t)
Line Numbers
Use the default emacs relative line numbers, but switch to absolute lines when in insert mode.
(use-package nlinum-relative
:config
(nlinum-relative-setup-evil)
:hook (prog-mode . nlinum-relative-mode))
Show Matching Parens
Shows matching parenthesis
(require 'paren)
(setq show-paren-delay 0)
(show-paren-mode)
Scrolling
Scroll smooth-ish-ly instead of jarring jumps.
(use-package smooth-scroll
:config
(smooth-scroll-mode t))
Dashboard
Show a cool custom dashboard buffer on startup.
(use-package dashboard
:diminish page-break-lines-mode
:config
(dashboard-setup-startup-hook)
(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
:custom
(dashboard-startup-banner 'logo)
(dashboard-banner-logo-title "Welcome to Electronic Macs.")
(dashboard-items
'((recents . 5)
(agenda)
(bookmarks . 5)
(registers . 5))))
Themes
pywal
Fancy dynamic color scheme generation from desktop wallpapers. Requires additional setup on the machine itself.
(defvar jf-theme-pywal-path "~/.cache/wal/colors.el" "Path to the colorscheme generated by pywal.")
(defun jf-theme-pywal ()
(load-file jf-theme-pywal-path))
spacemacs
This theme is pretty fancy and has lots of supported modes.
(unless (package-installed-p 'spacemacs-theme)
(package-install 'spacemacs-theme))
(defun jf-theme-spacemacs ()
(load-theme 'spacemacs-dark))
Transparency
Sets the window's transparency, to better admire choice wallpapers. The first number in the alpha section applies when the window is active, the second when it's inactive.
(set-frame-parameter (selected-frame) 'alpha 85)
(add-to-list 'default-frame-alist '(alpha . 85))
Helpers
(defvar jf-theme #'jf-theme-spacemacs "Theme function to call.")
(defun jf-apply-theme ()
"Apply the current theme as set by jf-theme."
(funcall jf-theme))
(jf-apply-theme)
Organization
Capture Templates
All capture templates, from tasks to bookmarks.
Tasks
(setq jf-org-capture-task-templates
'(("t" "Todo")
("tg" "General" entry
(file "refile.org")
"**** TODO %^{task}\n%U\n%a\n%?\n")
("tt" "General (Date)" entry
(file "refile.org")
"**** TODO %^{task}\n%U\n%a\nDue: %^t\n%?\n")
("tT" "General (Date+Time)" entry
(file "refile.org")
"**** TODO %^{task}\n%U\n%a\nDue: %^T\n%?\n")
("tst" "School" entry
(file "refile.org")
"**** TODO %^{task}\n%U\n%a\nDue: %^t\nClass: %^{class}\n%?\n")
("tss" "School (Date)" entry
(file "refile.org")
"**** TODO %^{todo}\n%U\n%a\nDue: %^t\nClass: %^{class}\n%?\n")
("tsS" "School (Date+Time)" entry
(file "refile.org")
"**** TODO %^{todo}\n%U\n%a\nDue: %^T\nClass: %^{class}\n%?\n")
("n" "Note" entry
(file "refile.org")
"** %? :NOTE:\n%U\n%a\n")))
Bookmarks
(setq jf-org-capture-bookmark-templates
'(("b" "Bookmark" entry
(file "refile.org")
"** [[%^{link}][%^{name}]] :LINK:\n%U\n%?")))
Personal
(setq jf-org-capture-personal-templates
'(("j" "Journal")
("jj" "Journal Entry" entry
(file+olp+datetree "journal.org")
"**** Today's Events\n%?")
("jt" "Thoughts" entry
(file+olp+datetree "journal.org")
"**** Thought\n%^g%^{summary}\n%U\n%?")
("jd" "Dream Journal Entry" entry
(file+olp+datetree "journal.org")
"**** Today's Dreams %^g\n%?")))
Protocol
(setq jf-org-capture-protocol-templates
'(("w" "Website" entry
(file "refile.org")
"** [[%:link][%:description%?]] :LINK:\n%U\n%a\n%i\n%?")))
All
Tie it all together.
(setq jf-org-capture-templates
(append
jf-org-capture-task-templates
jf-org-capture-personal-templates
jf-org-capture-bookmark-templates
jf-org-capture-protocol-templates))
Hooks
Temporarily widens the capture mode buffer and loads the tag completion alist with the full buffer tags.
(defun jf-update-capture-tags ()
(save-restriction
(widen)
(setq-local org-tag-alist (org-get-buffer-tags))))
Structure Templates
Defines expansions with <
followed by a string in org-mode.
Source Blocks
(setq jf-org-source-structure-templates
'(("el" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC")))
All
Tie it all together.
(setq jf-org-structure-templates
(append
jf-org-source-structure-templates))
Structure Editing
Refile/Copy Targets
Goodize the refiling targets to allow refiling and copying to arbitrary subtrees.
(defun jf-org-deep-refile ()
(interactive)
(setq-local org-refile-targets '((nil :maxlevel . 5)
(org-agenda-files :maxlevel . 3)))
(setq-local org-refile-use-outline-path t)
(org-refile))
(defun jf-org-deep-copy ()
(interactive)
(setq-local org-refile-targets '((nil :maxlevel . 5)
(org-agenda-files :maxlevel . 3)))
(setq-local org-refile-use-outline-path t)
(org-copy))
TODOs
States
(setq jf-org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
(sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "MEETING")))
(setq jf-org-todo-faces
'(("TODO" :foreground "red" :weight bold)
("NEXT" :foreground "blue" :weight bold)
("DONE" :foreground "forest green" :weight bold)
("WAITING" :foreground "orange" :weight bold)
("HOLD" :foreground "magenta" :weight bold)
("CANCELLED" :foreground "forest green" :weight bold)
("MEETING" :foreground "forest green" :weight bold)
("PHONE" :foreground "forest green" :weight bold)))
Tags and Triggers
- Moving a task to CANCELLED adds a CANCELLED tag
- Moving a task to WAITING adds a WAITING tag
- Moving a task to HOLD adds WAITING and HOLD tags
- Moving a task to a done state removes WAITING and HOLD tags
- Moving a task to TODO removes WAITING, CANCELLED, and HOLD tags
- Moving a task to NEXT removes WAITING, CANCELLED, and HOLD tags
- Moving a task to DONE removes WAITING, CANCELLED, and HOLD tags
(setq jf-org-todo-state-tags-triggers
'((("CANCELLED" ("CANCELLED" . t))
("WAITING" ("WAITING" . t))
("HOLD" ("WAITING") ("HOLD" . t))
(done ("WAITING") ("HOLD"))
("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
("NEXT" ("WAITING") ("CANCELLED") ("HOLD"))
("DONE" ("WAITING") ("CANCELLED") ("HOLD")))))
Org-mode
Keep org-mode up to date straight from the cow's utters. If the manual is not on your computer, it's here.
(use-package org
:pin org
:mode ("\\.org\\'" . org-mode)
:hook ((org-mode . org-indent-mode)
(org-capture-mode . evil-insert-state)
(org-capture-mode . jf-update-capture-tags))
:config
(org-clock-persistence-insinuate)
:general
(jf-major-def
:keymaps 'org-mode-map
"e" 'org-export-dispatch
"a" 'org-attach)
(jf-org-def
"a" 'org-agenda
"c" 'org-capture
"C i" 'org-clock-in
"C o" 'org-clock-out
"C c" 'org-clock-cancel
"l" 'org-insert-link
"L" 'org-store-link
"b" 'org-switchb
"r" 'jf-org-deep-refile
"R" 'jf-org-deep-copy)
:custom
(org-directory "~/Sync/org")
(org-agenda-files '("~/Sync/org/"))
(org-default-notes-file "notes.org")
(org-agenda-include-diary t)
(org-src-window-setup 'current-window "Edit source code in the current window")
(org-src-fontify-natively t "Highlight syntax in source blocks")
(org-latex-to-pdf-process '("latexmk -f pdf %f") "Use pdflatex for export")
(org-capture-templates jf-org-capture-templates)
(org-structure-template-alist (append org-structure-template-alist jf-org-structure-templates))
(org-clock-persist 'history)
(org-todo-keywords jf-org-todo-keywords)
(org-todo-keyword-faces jf-org-todo-faces)
(org-todo-state-tags-triggers jf-org-todo-state-tags-triggers)
(org-use-fast-todo-selection t)
(org-treat-S-cursor-todo-selection-as-state-change nil))
Evil Org-mode
(use-package evil-org
:after (evil org)
:hook (org-mode . evil-org-mode)
:config
(evil-org-set-key-theme '(navigation insert textobjects additional calendar))
(require 'evil-org-agenda)
(evil-org-agenda-set-keys))
Pretty org-mode bullets
Make bullets look choice
(use-package org-bullets
:hook (org-mode . org-bullets-mode))
Communication
Web
Tools
Fuzzy Matching
Most facilities are provided by Ivy and friends, which build on existing emacs commands.
Smex
While the actual smex command is not in use, counsel-M-x will use it for sorting by usage.
(use-package smex)
Ivy
(use-package ivy
:init
(defun jf-kill-current-buffer ()
(interactive)
(kill-buffer (current-buffer)))
(defun jf-kill-all-buffers ()
(interactive)
(seq-do 'kill-buffer (buffer-list)))
:general
(jf-buffers-def
"b" 'ivy-switch-buffer
"v" 'ivy-push-view
"V" 'ivy-pop-view
"c" 'jf-kill-current-buffer
"C" 'jf-kill-all-buffers)
:custom
(ivy-use-virtual-buffers t)
(ivy-count-format "%d/%d"))
Counsel
A collection of ivy enhanced versions of common Emacs commands.
(use-package counsel
:general
("M-x" 'counsel-M-x)
(jf-leader-def
:states 'normal
"x" 'counsel-M-x)
(jf-files-def
"f" 'counsel-find-file)
(jf-help-def
"a" 'counsel-apropos
"f" 'counsel-describe-function
"k" 'counsel-descbinds
"l" 'counsel-find-library
"s" 'counsel-info-lookup-symbol
"u" 'counsel-unicode-char
"v" 'counsel-describe-variable))
Swiper
An ivy-ified replacement for isearch.
(use-package swiper
:after evil
:general
(:keymaps 'override
:states 'normal
"/" 'swiper
"n" 'evil-search-previous
"N" 'evil-search-next))
Neotree
A cool toggleable directory structure sidebar.
It needs icon fonts, installed with M-x all-the-icons-install-fonts
.
(use-package all-the-icons)
(use-package neotree
:after all-the-icons
:general
(jf-apps-def
"t" 'neotree-toggle)
:custom
(neo-theme (if (display-graphic-p) 'icons 'arrow)))
Ranger
Brings the glory of Ranger to Emacs.
(use-package ranger
:commands (ranger deer))
Sunshine
Allows retrieving OpenWeatherMap forecasts in the minibuffer.
(use-package sunshine
:commands sunshine-forecast
:general
(jf-apps-def
"w" #'sunshine-forecast)
:custom
(sunshine-location "Piscataway, US")
(sunshine-units 'metric)
(sunshine-appid "7caf100277f14845e7f354c6590a09cb")
(sunshine-show-icons t))
Programming
Formatting
Word Wrap
(defun jf-word-wrap (column)
"Enable auto refill mode at COLUMN."
(interactive "nFill column: ")
(setq-local fill-column column)
(refill-mode))
(defun jf-nowrap ()
"Disable auto refill mode."
(interactive)
(refill-mode))
Indentation
Set some sane defaults
(setq jf-tab-width 4)
(setq-default python-indent-offset jf-tab-width)
(setq-default evil-shift-width jf-tab-width)
(setq-default c-basic-offset jf-tab-width)
; Disable annoying electric indent of previous lines
(setq-default electric-indent-inhibit t)
; Eat the whole tab when I press backspace
(setq backward-delete-char-untabify-method 'hungry)
Define some useful helper functions
(defun jf-indent-tabs (width)
(interactive "nTab width: ")
(setq tab-width width)
(local-set-key (kbd "TAB") 'tab-to-tab-stop)
(setq indent-tabs-mode t))
(defun jf-indent-spaces (num)
(interactive "nNumber of spaces: ")
(setq tab-width num)
(setq indent-tabs-mode nil))
;; Default to 4 spaces
(add-hook 'prog-mode-hook #'jf-indent-4-spaces)
;; Define functions for every level of indent that might need hooking
(cl-macrolet
((jf-define-indent-funs (widths)
`(progn
,@(mapcan
(lambda (num)
`((defun ,(intern (concat "jf-indent-" (number-to-string num) "-spaces")) ()
(jf-indent-spaces ,num))
(defun ,(intern (concat "jf-indent-tabs-" (number-to-string num))) ()
(jf-indent-tabs ,num))))
widths))))
(jf-define-indent-funs (2 4 8)))
;; TODO: Replace with dedicated whitespace config
(setq whitespace-style '(face tabs tab-mark trailing))
(custom-set-faces
'(whitespace-tab ((t (:foreground "#636363")))))
;; Make tabs visible
(setq whitespace-display-mappings
'((tab-mark 9 [124 9] [92 9])))
(add-hook 'prog-mode-hook #'whitespace-mode)
Parentheses
Smartparens
Smartparens handles parens for languages that aren't lispy.
(use-package smartparens
:diminish
:commands smartparens-mode
:config
(require 'smartparens-config))
ParEdit
And ParEdit handles the rest.
(use-package paredit
:diminish
:commands enable-paredit-mode)
Lispyville
And now Lispyville handles the rest.
(use-package lispyville
:commands lispyville-mode
:config
(lispyville-set-key-theme
'(operators
c-w
slurp/barf-cp
commentary
(escape insert)
(additional-movement normal visual motion))))
Evil-Cleverparens
Evil-Cleverparens adds additional features to Evil all about
working with sexps, including keeping parens balanced when
using commands like dd
.
(use-package evil-cleverparens
:diminish
:commands evil-cleverparens-mode)
Activation
Add a hook to enable paren helper modes for any prog-mode buffer
(defun jf-paren-mode ()
"Pick a suitable parenthesis mode for the current major mode."
(electric-pair-mode)
(if (member major-mode '(emacs-lisp-mode
lisp-mode
lisp-interaction-mode
scheme-mode))
(lispyville-mode)
(smartparens-mode)))
(add-hook 'prog-mode-hook #'jf-paren-mode)
Helpers
Helpers for wrangling sexps
(jf-kbd-defmacro jf-wrap-fn-inline
"ESC i C-q { RET TAB ESC jI} SPC ESC k^")
(jf-kbd-defmacro jf-wrap-fn-line
"ESC kA SPC C-q { ESC jjI} SPC ESC k^")
(jf-kbd-defmacro jf-wrap-fn-sexp
"ESC i C-q { RET TAB ESC )i} ESC i RET ESC k^")
Whitespace
ws-butler
Unobtrusively cleans up whitespace before EOLs as you edit, stopping the noisy commits generated from blanket trimming entire files.
(use-package ws-butler
:hook (prog-mode . ws-butler-mode))
pretty-mode
pretty-mode redisplays parts of the Emacs buffer as pretty symbols.
(use-package pretty-mode
:hook (prog-mode . pretty-mode)
:config
(pretty-deactivate-groups '(:arithmetic
:sub-and-superscripts))
(pretty-activate-groups '(:equality
:ordering
:ordering-double
:ordering-triple
:arrows
:arrows-twoheaded
:punctuation
:logic
:sets)))
Prettify-Symbols-Mode
Allows custom unicode replacement of symbols. Fill in the gaps where pretty-mode left off.
Python
(defun jf-prettify-python ()
(dolist (pair '(;; Syntax
("in" . #x2208)
("not in" . #x2209)
("return" . #x27fc)
("yield" . #x27fb)
("for" . #x2200)
;; Base Types
("int" . #x2124)
("float" . #x211d)
("str" . #x1d54a)
("True" . #x1d54b)
("False" . #x1d53d)))
(push pair prettify-symbols-alist)))
(add-hook 'python-mode-hook #'prettify-symbols-mode)
(add-hook 'python-mode-hook #'jf-prettify-python)
Checkers
Flycheck
Flycheck highlights syntax errors in a few languages.
(use-package flycheck
:hook (prog-mode . flycheck-mode)
:custom (flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
Column 80 Highlight
Add a hotkey for highlighting column 80
and activate it in prog-mode
(use-package fill-column-indicator
:init
(setq fci-rule-use-dashes t)
(setq fci-rule-column 80)
:general
(jf-major-def
:keymaps 'prog-mode-map
"8" 'fci-mode))
Completion
Company
Company auto-completes stuff in the buffer, and company-quickhelp shows documentation popups when idling on a completion candidate.
(use-package company
:hook (prog-mode . company-mode)
:general
(:keymaps 'company-active-map
"C-SPC" 'company-abort)
:custom
(company-maximum-prefix-length 2)
(company-idle-delay 0.2 "Decrease idle delay"))
(use-package company-quickhelp
:after company
:hook (company-mode . company-quickhelp-mode))
Snippets
Yasnippet adds support for custom snippets
(use-package yasnippet
:hook (prog-mode . yas-minor-mode)
:custom
(yas-snippet-dirs
'("~/.emacs.d/snippets"
"~/.emacs.d/elpa/yasnippet-snippets-0.6/snippets")))
Debugging
Realgud
Realgud is a modular frontend for many debuggers, right in Emacs.
(use-package realgud
:commands
(realgud:gdb
realgud:lldb
realgud:node-inspect
realgud:pdb
realgud:trepan3k))
RMSbolt
RMSbolt Shows disassembly in a buffer next to code, highlighting relevant regions.
(use-package rmsbolt
:commands rmsbolt-mode)
Git
Magit
It's magic git! Keybinds here
(use-package magit
:general
(jf-git-def
"b" 'magit-blame-addition
"B" 'magit-blame-reverse
"s" 'magit-status))
It's evil magic git!
(use-package evil-magit
:after (evil magit))
Forge
Magic GitHub facilities for git forges such as GitHub and GitLab!
(use-package forge
:after magit)
Smeargle
Highlights regions in files by last update time. Older regions are more whitey and newer regions are more blacky.
(use-package smeargle
:general
(jf-git-def
"H t" 'smeargle
"H h" 'smeargle-commits
"H c" 'smeargle-clear))
Projects
Projectile provides project-level features like make shortcuts and file switching
(use-package projectile
:defer t
:preface
(defvar jf-projects-path "~/Documents/dev")
:general
(jf-leader-def
"p" '(:keymap projectile-command-map))
:config
(projectile-mode 1)
;; Discover projects in jf-projects-path
(let ((subdirs (directory-files jf-projects-path t)))
(dolist (dir subdirs)
(unless (member (file-name-nondirectory dir) '(".." "."))
(when (file-directory-p dir)
(let ((default-directory dir)
(projectile-cached-project-root dir))
(when (projectile-project-p)
(projectile-add-known-project (projectile-project-root))))))))
:custom
(projectile-completion-system 'ivy)
(projectile-project-search-path (list jf-projects-path)))
Languages
Language Server Protocol
Mode for integration with lots of language servers, interacting with company, flycheck, projectile, and the works.
(use-package lsp-mode
:commands lsp)
(use-package lsp-ui
:commands lsp-ui-mode)
(use-package company-lsp
:commands company-lsp)
Fish
Mode for editing of scripts for the fish shell.
(use-package fish-mode
:mode "\\.fish\\'")
Markdown
Mode for editing markdown.
(use-package markdown-mode
:mode "\\.md\\'")
Python
Jedi for autocompletion sources in python-mode.
(use-package company-jedi
:company python-mode)
Javascript
js2-mode improves the default js mode.
(use-package js2-mode
:mode "\\.js\\'"
:interpreter "node")
Web
Web-mode should give everything you need for a web-dev major mode. Company integration is done with company-web.
(use-package web-mode
:mode ("\\.html\\'"
"\\.php\\'"
"\\.blade\\.")
:custom
(web-mode-code-indent-offset 4)
(web-mode-indent-style 4))
(use-package company-web
:company web-mode)
JSON
Mode for editing JSON files.
(use-package json-mode
:mode "\\.json\\'")
YAML
Mode for editing YAML files.
(use-package yaml-mode
:mode "\\.yaml\\'")
Arch PKGBUILD
Mode for editing PKGBUILD files.
(use-package pkgbuild-mode
:mode ".*PKGBUILD\\'")
LaTeX
AUCTeX
AUCTeX is a major mode for editing TeX. Company completions are handled by company-auctex and company-math.
(use-package tex
:defer t
:ensure auctex
:general
(jf-major-def
:keymaps 'TeX-mode-map
"e" 'TeX-command-run-all)
:custom
(TeX-auto-save t))
(use-package company-auctex
:company LaTeX-mode)
(use-package company-math
:company ((TeX-mode . company-math-symbols-latex)
(TeX-mode . company-math-symbols-unicode)
(TeX-mode . company-latex-commands)))
Cdlatex
cdlatex adds better TeX-specific template expansions and other niceties.
Environment
(setq jf-cdlatex-envs nil)
Commands
(setq jf-cdlatex-commands nil)
Math Symbols
(setq jf-cdlatex-symbols
'((?I ("\\infty"))))
Setup
(use-package cdlatex
:hook (LaTeX-mode . cdlatex-mode)
:custom
(cdlatex-env-alist jf-cdlatex-envs)
(cdlatex-command-alist jf-cdlatex-commands)
(cdlatex-math-symbol-alist jf-cdlatex-symbols))
Rust
(use-package rust-mode
:mode "\\.rs\\'"
:general)
(use-package flycheck-rust
:after flycheck
:hook (rust-mode . flycheck-rust-setup))
(use-package racer
:hook ((rust-mode . racer-mode)
(rust-mode . eldoc-mode))
:custom
(racer-cmd "~/.cargo/bin/racer")
(racer-rust-src-path "~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src"))
(use-package cargo
:hook (rust-mode . cargo-minor-mode)
:general
(jf-major-def
:keymaps 'rust-mode-map
"b b" #'cargo-process-build
"b r" #'cargo-process-run
"b t" #'cargo-process-test))
C/C++
Irony
Irony handles enhanced C/C++ operations powered by clang company-irony for company integration
(use-package irony
:hook ((c-mode c++-mode) . irony-mode)
(irony-mode . irony-cdb-autosetup-compile-options))
(use-package flycheck-irony
:after flycheck
:hook (irony-mode . flycheck-irony-setup))
(use-package company-irony
:company irony-mode)
(use-package company-irony-c-headers
:company irony-mode)
Lua
(use-package lua-mode
:mode "\\.lua\\'")
(use-package company-lua
:company lua-mode)
Elixir
(use-package elixir-mode
:mode "\\.exs?\\'"
:hook (elixir-mode . lsp))
Java
Eclim
Secretly actually use eclipse in the background in the form of eclimd for all of the IDE like features.
(use-package eclim
:hook ((java-mode . eclim-mode)
(java-mode . jf-indent-4-spaces))
:custom
(eclimd-default-workspace "~/Documents/dev/workspace")
(eclimd-autostart-with-default-workspace t)
(eclimd-autostart t))
(use-package company-emacs-eclim
:company java-mode)
Gradle
The std:: java build system
(use-package gradle-mode
:commands gradle-mode
:preface
(defun jf-gradle-run-main ()
(gradle-execute "run"))
:general
(jf-major-def
:keymaps 'gradle-mode-map
"b b" #'gradle-build
"b r" #'jf-gradle-run-main))