mirror of
https://github.com/Foltik/dotfiles
synced 2024-11-30 14:32:08 -05:00
1618 lines
49 KiB
Org Mode
1618 lines
49 KiB
Org Mode
* Packaging
|
||
** Package.el
|
||
[[http://wikemacs.org/wiki/Package.el][Package.el]] is the built-in package manager in Emacs. This is where the fun begins.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
** use-package
|
||
[[https://github.com/jwiegley/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.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
*** Custom Keywords
|
||
A few useful =:keyword= macros that extend the vanilla =use-package= functionality.
|
||
**** :company
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))))
|
||
#+END_SRC
|
||
* Keybinds
|
||
** which-key
|
||
[[https://github.com/justbur/emacs-which-key][which-key]] displays a popup in the minibuffer that shows
|
||
keybindings following incomplete commands.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package which-key
|
||
:diminish
|
||
:config
|
||
(which-key-mode))
|
||
#+END_SRC
|
||
** General
|
||
[[https://github.com/noctuid/general.el][General]] is an excellent keybind manager that adds *tons* of useful macros.
|
||
Also set up a leader key and prefixes, like =\= in Vim.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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"))))
|
||
#+END_SRC
|
||
** Macros
|
||
A helper for defining procedural keyboard macros
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
* Vim Emulation
|
||
** Evil
|
||
[[https://github.com/emacs-evil/evil][Evil]] is pretty much the entirety of Vim in Emacs.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
** Evil Collection
|
||
[[https://github.com/emacs-evil/evil-collection][Evil Collection]] adds Evil bindings for all the parts of Emacs that Evil
|
||
doesn't cover properly by default.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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
|
||
rjsx-mode
|
||
log-view
|
||
man
|
||
neotree
|
||
python
|
||
racer
|
||
realgud
|
||
which-key)))
|
||
#+END_SRC
|
||
** Evil Extensions
|
||
*** Avy
|
||
An enhanced version of =f= in Vim.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package avy
|
||
:general
|
||
(:keymaps 'override
|
||
:states 'normal
|
||
"C-f" 'avy-goto-char-in-line
|
||
"C-F" 'avy-goto-char))
|
||
#+END_SRC
|
||
*** Subword
|
||
Make boundaries between words in camelCase act as separate words for evil motions.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
*** evil-surround
|
||
Use =S= and a delimiter to surround in visual mode.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package evil-surround
|
||
:after evil
|
||
:diminish
|
||
:config
|
||
(global-evil-surround-mode 1))
|
||
#+END_SRC
|
||
*** evil-goggles
|
||
Visual highlighting on evil motions
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package evil-goggles
|
||
:config
|
||
(evil-goggles-mode)
|
||
(evil-goggles-use-diff-faces))
|
||
#+END_SRC
|
||
* Emacs
|
||
** Defaults
|
||
*** Configuration Editing
|
||
Add functions for editing and reloading the Emacs config files.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
*** 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.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
*** File Not Found Functions
|
||
Offer to create parent folders when a file is opened
|
||
Offer to create nonexistant parent directories.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
*** Customize Location
|
||
Make changes in =M-x customize= go somewhere other than being schlunked into =init.el=.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq custom-file (concat user-emacs-directory "_customize.el"))
|
||
(load custom-file t)
|
||
#+END_SRC
|
||
*** Disable Bell
|
||
Shut up, emacs.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq ring-bell-function #'ignore)
|
||
#+END_SRC
|
||
*** Shorter Prompts
|
||
Make =yes-or-no= prompts ask for =y-or-n= instead. Saves loads of time™.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defalias 'yes-or-no-p #'y-or-n-p)
|
||
#+END_SRC
|
||
*** Move Backup Files
|
||
By default, emacs gunks up every folder with =file~= backups
|
||
and =#file#= lockfiles. Schlunk them all in =.emacs.d/saves= instead.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(let ((save-dir (locate-user-emacs-file "saves")))
|
||
(setq backup-directory-alist
|
||
`((".*" . ,save-dir)))
|
||
(setq auto-save-file-name-transforms
|
||
`((".*" ,(concat save-dir "/") t))))
|
||
#+END_SRC
|
||
*** Secure auth-source
|
||
GPG encrypt stored auth tokens from [[https://www.gnu.org/software/emacs/manual/html_mono/auth.html][auth-source]] instead of storing them in plaintext.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq auth-sources '("~/.emacs.d/authinfo.gpg"))
|
||
#+END_SRC
|
||
*** Use UTF-8
|
||
Pleeeease default to UTF-8, Emacs.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
*** Trash when Deleting
|
||
Don't permanently delete stuff unless asked.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq delete-by-moving-to-trash t)
|
||
#+END_SRC
|
||
*** Open Compressed Files
|
||
...automatically.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq auto-compression-mode t)
|
||
#+END_SRC
|
||
*** Save Minibuffer History
|
||
#+BEGIN_SRC emacs-lisp
|
||
(savehist-mode 1)
|
||
(setq history-length 1000)
|
||
#+END_SRC
|
||
*** Double Spaces
|
||
Why sentences would need double spaces to end I do not know.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(set-default 'sentence-end-double-space nil)
|
||
#+END_SRC
|
||
*** Eval Print Level
|
||
Print more stuff when running =C-x C-e= or =(eval-last-sexp)=
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq eval-expression-print-level 100)
|
||
#+END_SRC
|
||
*** 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.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-hook 'minibuffer-setup-hook #'jf-inhibit-gc)
|
||
(add-hook 'minibuffer-exit-hook #'jf-resume-gc)
|
||
#+END_SRC
|
||
*** Default Shell
|
||
Fish breaks some things when used as the default shell, so just use bash.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq-default shell-file-name "/bin/bash")
|
||
#+END_SRC
|
||
** UI
|
||
*** Font
|
||
Engage a nice coding font.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-to-list 'default-frame-alist '(font . "Fira Code 12"))
|
||
(set-face-attribute 'default t :font "Fira Code 12")
|
||
#+END_SRC
|
||
*** Menu Bar
|
||
Disable the useless cruft at the top of the screen.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(menu-bar-mode -1)
|
||
(tool-bar-mode -1)
|
||
(scroll-bar-mode -1)
|
||
#+END_SRC
|
||
*** Modeline
|
||
**** Diminish
|
||
Adds support for =:diminish= in use-package declarations, which hides a mode from the modeline.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package diminish)
|
||
#+END_SRC
|
||
**** Column Number
|
||
Show line and column numbers in the modeline.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq line-number-mode t)
|
||
(setq column-number-mode t)
|
||
#+END_SRC
|
||
*** Line Numbers
|
||
Use the default emacs relative line numbers, but switch to absolute lines when in insert mode.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(add-hook 'prog-mode-hook (lambda () (setq display-line-numbers 'absolute)))
|
||
(add-hook 'evil-insert-state-entry-hook (lambda () (when (bound-and-true-p display-line-numbers) (setq display-line-numbers 'absolute))))
|
||
(add-hook 'evil-insert-state-exit-hook (lambda () (when (bound-and-true-p display-line-numbers) (setq display-line-numbers 'relative))))
|
||
(add-hook 'evil-normal-state-entry-hook (lambda () (when (bound-and-true-p display-line-numbers) (setq display-line-numbers 'relative))))
|
||
(add-hook 'evil-normal-state-entry-hook (lambda () (when (bound-and-true-p display-line-numbers) (setq display-line-numbers 'absolute))))
|
||
(add-hook 'evil-visual-state-entry-hook (lambda () (when (bound-and-true-p display-line-numbers) (setq display-line-numbers 'relative))))
|
||
(add-hook 'evil-visual-state-entry-hook (lambda () (when (bound-and-true-p display-line-numbers) (setq display-line-numbers 'absolute))))
|
||
(add-hook 'display-line-numbers-hook (lambda () (when (evil-normal-state-p) (setq display-line-numbers 'relative))))
|
||
#+END_SRC
|
||
*** Show Matching Parens
|
||
Shows matching parenthesis
|
||
#+BEGIN_SRC emacs-lisp
|
||
(require 'paren)
|
||
(setq show-paren-delay 0)
|
||
(show-paren-mode)
|
||
#+END_SRC
|
||
*** Scrolling
|
||
Scroll smooth-ish-ly instead of jarring jumps.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package smooth-scroll
|
||
:config
|
||
(smooth-scroll-mode t))
|
||
#+END_SRC
|
||
*** Dashboard
|
||
Show a cool custom dashboard buffer on startup.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))))
|
||
#+END_SRC
|
||
** Themes
|
||
*** pywal
|
||
Fancy dynamic color scheme generation from desktop wallpapers.
|
||
Requires additional setup on the machine itself.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
*** spacemacs
|
||
This theme is pretty fancy and has lots of supported modes.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(unless (package-installed-p 'spacemacs-theme)
|
||
(package-install 'spacemacs-theme))
|
||
|
||
(defun jf-theme-spacemacs ()
|
||
(load-theme 'spacemacs-dark))
|
||
#+END_SRC
|
||
*** 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.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(set-frame-parameter (selected-frame) 'alpha 85)
|
||
(add-to-list 'default-frame-alist '(alpha . 85))
|
||
#+END_SRC
|
||
|
||
*** Helpers
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
* Organization
|
||
** Capture Templates
|
||
All capture templates, from tasks to bookmarks.
|
||
*** Tasks
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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\nDue: %^t\n%a\n%?\n")
|
||
("tT" "General (Date+Time)" entry
|
||
(file "refile.org")
|
||
"**** TODO %^{task}\n%U\nDue: %^T\n%a\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")))
|
||
#+END_SRC
|
||
*** Bookmarks
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-org-capture-bookmark-templates
|
||
'(("b" "Bookmark" entry
|
||
(file "refile.org")
|
||
"** [[%^{link}][%^{name}]] :LINK:\n%U\n%?")))
|
||
#+END_SRC
|
||
*** Personal
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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%?")))
|
||
#+END_SRC
|
||
*** Protocol
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-org-capture-protocol-templates
|
||
'(("w" "Website" entry
|
||
(file "refile.org")
|
||
"** [[%:link][%:description%?]] :LINK:\n%U\n%a\n%i\n%?")))
|
||
#+END_SRC
|
||
*** All
|
||
Tie it all together.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
*** Hooks
|
||
Temporarily widens the capture mode buffer and loads the tag completion alist with
|
||
the full buffer tags.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun jf-update-capture-tags ()
|
||
(save-restriction
|
||
(widen)
|
||
(setq-local org-tag-alist (org-get-buffer-tags))))
|
||
#+END_SRC
|
||
** Structure Templates
|
||
Defines expansions with =<= followed by a string in org-mode.
|
||
*** Source Blocks
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-org-source-structure-templates
|
||
'(("el" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC")
|
||
("ipy" "#+BEGIN_SRC ipython :session :results raw drawer\n?\n#+END_SRC")))
|
||
#+END_SRC
|
||
*** All
|
||
Tie it all together.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-org-structure-templates
|
||
(append
|
||
jf-org-source-structure-templates))
|
||
#+END_SRC
|
||
** Structure Editing
|
||
*** Refile/Copy Targets
|
||
Goodize the refiling targets to allow refiling and copying to arbitrary subtrees.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
** TODOs
|
||
*** States
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
*** 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
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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")))))
|
||
#+END_SRC
|
||
** Org Languages
|
||
Languages which can be evaluated in Org buffers.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-org-babel-languages
|
||
'((emacs-lisp . t) (ipython . t)))
|
||
#+END_SRC
|
||
** Org-mode
|
||
Keep org-mode up to date straight from the cow's utters.
|
||
If the manual is not on your computer, it's [[https://orgmode.org/manual/][here]].
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
(org-babel-after-execute . org-display-inline-images))
|
||
|
||
: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
|
||
"A" 'org-archive-to-archive-sibling
|
||
"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)
|
||
(org-babel-load-languages jf-org-babel-languages)
|
||
(org-confirm-babel-evaluate nil)
|
||
(org-startup-with-inline-images t))
|
||
#+END_SRC
|
||
** Evil Org-mode
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
** Pretty org-mode bullets
|
||
Make bullets look choice
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org-bullets
|
||
:hook (org-mode . org-bullets-mode))
|
||
#+END_SRC
|
||
* Communication
|
||
* Web
|
||
* Tools
|
||
** Fuzzy Matching
|
||
Most facilities are provided by [[https://github.com/abo-abo/swiper][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.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package smex)
|
||
#+END_SRC
|
||
*** Ivy
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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
|
||
"B" 'ibuffer
|
||
"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"))
|
||
#+END_SRC
|
||
*** Counsel
|
||
A collection of ivy enhanced versions of common Emacs commands.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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" 'describe-key
|
||
"K" 'counsel-descbinds
|
||
"l" 'counsel-find-library
|
||
"s" 'counsel-info-lookup-symbol
|
||
"u" 'counsel-unicode-char
|
||
"v" 'counsel-describe-variable))
|
||
#+END_SRC
|
||
*** Swiper
|
||
An ivy-ified replacement for isearch.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package swiper
|
||
:after evil
|
||
:general
|
||
(:keymaps 'override
|
||
:states 'normal
|
||
"/" 'swiper
|
||
"n" 'evil-search-previous
|
||
"N" 'evil-search-next))
|
||
#+END_SRC
|
||
|
||
** Neotree
|
||
A cool toggleable directory structure sidebar.
|
||
It needs icon fonts, installed with =M-x all-the-icons-install-fonts=.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
** Ranger
|
||
Brings the glory of [[https://github.com/ralesi/ranger.el][Ranger]] to Emacs.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ranger
|
||
:commands (ranger deer))
|
||
#+END_SRC
|
||
** Sunshine
|
||
Allows retrieving OpenWeatherMap forecasts in the minibuffer.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
** Kubernetes
|
||
A porcelain like magit for kubernetes.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package kubernetes
|
||
:commands kubernetes-overview)
|
||
|
||
(use-package kubernetes-evil
|
||
:after kubernetes)
|
||
#+END_SRC
|
||
* Programming
|
||
** Formatting
|
||
*** Word Wrap
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
*** Indentation
|
||
Set some *sane* defaults
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
Define some *useful* helper functions
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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 js2-basic-offset num)
|
||
(setq tab-width num)
|
||
(setq indent-tabs-mode nil))
|
||
|
||
(setq-default indent-tabs-mode nil)
|
||
(setq-default tab-width 4)
|
||
|
||
;; 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)
|
||
#+END_SRC
|
||
*** Parentheses
|
||
**** Smartparens
|
||
[[https://github.com/Fuco1/smartparens][Smartparens]] handles parens for languages that aren't lispy.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package smartparens
|
||
:diminish
|
||
:commands smartparens-mode
|
||
:config
|
||
(require 'smartparens-config))
|
||
#+END_SRC
|
||
**** ParEdit
|
||
And [[https://www.emacswiki.org/emacs/ParEdit][ParEdit]] handles the rest.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package paredit
|
||
:diminish
|
||
:commands enable-paredit-mode)
|
||
#+END_SRC
|
||
**** Lispyville
|
||
And now Lispyville handles the rest.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))))
|
||
#+END_SRC
|
||
**** Evil-Cleverparens
|
||
[[https://github.com/luxbock/evil-cleverparens][Evil-Cleverparens]] adds additional features to Evil all about
|
||
working with sexps, including keeping parens balanced when
|
||
using commands like =dd=.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package evil-cleverparens
|
||
:diminish
|
||
:commands evil-cleverparens-mode)
|
||
#+END_SRC
|
||
**** Activation
|
||
Add a hook to enable paren helper modes for any prog-mode buffer
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
**** Helpers
|
||
Helpers for wrangling sexps
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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^")
|
||
#+END_SRC
|
||
*** Whitespace
|
||
**** ws-butler
|
||
Unobtrusively cleans up whitespace before EOLs
|
||
as you edit, stopping the noisy commits generated
|
||
from blanket trimming entire files.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ws-butler
|
||
:hook (prog-mode . ws-butler-mode))
|
||
#+END_SRC
|
||
*** pretty-mode
|
||
[[https://github.com/pretty-mode/pretty-mode][pretty-mode]] redisplays parts of the Emacs buffer as pretty symbols.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
|
||
*** Prettify-Symbols-Mode
|
||
Allows custom unicode replacement of symbols. Fill in the gaps where
|
||
pretty-mode left off.
|
||
**** Python
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
** Checkers
|
||
*** Flycheck
|
||
Flycheck highlights syntax errors in a few languages.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package flycheck
|
||
:hook (prog-mode . flycheck-mode)
|
||
:custom (flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
|
||
#+END_SRC
|
||
*** Column 80 Highlight
|
||
Add a hotkey for highlighting column 80
|
||
and activate it in =prog-mode=
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
|
||
** Completion
|
||
*** Company
|
||
Company auto-completes stuff in the buffer, and company-quickhelp shows
|
||
documentation popups when idling on a completion candidate.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
** Snippets
|
||
Yasnippet adds support for custom snippets
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package yasnippet
|
||
:hook (prog-mode . yas-minor-mode)
|
||
:custom
|
||
(yas-snippet-dirs
|
||
'("~/.emacs.d/snippets"
|
||
"~/.emacs.d/elpa/yasnippet-snippets-0.6/snippets")))
|
||
#+END_SRC
|
||
|
||
** Debugging
|
||
*** Realgud
|
||
[[https://github.com/realgud/realgud][Realgud]] is a modular frontend for many debuggers, right in Emacs.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package realgud
|
||
:commands
|
||
(realgud:gdb
|
||
realgud:lldb
|
||
realgud:node-inspect
|
||
realgud:pdb
|
||
realgud:trepan3k))
|
||
#+END_SRC
|
||
*** RMSbolt
|
||
[[https://github.com/emacsmirror/rmsbolt][RMSbolt]] Shows disassembly in a buffer next to code, highlighting relevant regions.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package rmsbolt
|
||
:commands rmsbolt-mode)
|
||
#+END_SRC
|
||
** Git
|
||
*** Magit
|
||
**** Core
|
||
It's magic git!
|
||
Keybinds [[https://github.com/emacs-evil/evil-magit][here]]
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package magit
|
||
:general
|
||
(jf-git-def
|
||
"b" 'magit-blame-addition
|
||
"B" 'magit-blame-reverse
|
||
"s" 'magit-status)
|
||
(:keymaps 'magit-status-mode-map
|
||
"i" 'jf-lcsr-issue-dispatch)
|
||
:config
|
||
(jf-lcsr-setup))
|
||
#+END_SRC
|
||
It's *evil* magic git!
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package evil-magit
|
||
:after (evil magit))
|
||
#+END_SRC
|
||
**** LCSR Issues
|
||
My workplace has a very specific git workflow that basically boils down
|
||
to creating =issue/$id/$description= and branching off it to =issue/id/$person= for
|
||
each developer. What follows are some convenience functions for dealing with this.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun jf-lcsr-setup ()
|
||
(defvar jf-lcsr-me "jwf78")
|
||
|
||
;;; Predicate Functions
|
||
(defun jf-lcsr-branch-base-p (branch)
|
||
(string-match "^\\(origin/\\)?issue/[0-9]\\{3,4\\}/[A-Za-z-]+$" branch))
|
||
|
||
(defun jf-lcsr-branch-user-p (branch)
|
||
(string-match "^\\(origin/\\)?issue/[0-9]\\{3,4\\}/[a-z]\\{2,3\\}[0-9]\\{1,5\\}$" branch))
|
||
|
||
(defun jf-lcsr-branch-origin-p (branch)
|
||
(string-match "^origin/issue/[0-9]\\{3,4\\}/[A-Za-z-]+$" branch))
|
||
|
||
;;; Splitting and Joining Functions
|
||
(defun jf-lcsr-branch-id (branch)
|
||
(let ((lst (split-string branch "/")))
|
||
(if (jf-lcsr-branch-origin-p branch)
|
||
(elt lst 2)
|
||
(elt lst 1))))
|
||
|
||
(defun jf-lcsr-branch-tag (branch)
|
||
(let ((lst (split-string branch "/")))
|
||
(if (jf-lcsr-branch-origin-p branch)
|
||
(elt lst 3)
|
||
(elt lst 2))))
|
||
|
||
(defun jf-lcsr-branch (id tag)
|
||
(string-join `("issue" ,id ,tag) "/"))
|
||
|
||
(defun jf-lcsr-branch-my-p (branch)
|
||
(and (jf-lcsr-branch-user-p branch) (string= jf-lcsr-me (jf-lcsr-branch-tag branch))))
|
||
|
||
(defun jf-lcsr-branch-p (branch)
|
||
(or (jf-lcsr-branch-base-p branch) (jf-lcsr-branch-user-p branch)))
|
||
|
||
(defun jf-lcsr-branch-id= (a b)
|
||
(string= (jf-lcsr-branch-id a) (jf-lcsr-branch-id b)))
|
||
|
||
;;; Utility Functions
|
||
(defun jf-lcsr-branches ()
|
||
(seq-filter #'jf-lcsr-branch-p (magit-list-branch-names)))
|
||
|
||
(defun jf-lcsr-base-branches ()
|
||
(seq-filter #'jf-lcsr-branch-base-p (jf-lcsr-branches)))
|
||
|
||
(defun jf-lcsr-find-id (id branches)
|
||
(seq-find
|
||
(lambda (b) (string= (jf-lcsr-branch-id b) id))
|
||
branches))
|
||
|
||
(defun jf-lcsr-find-tag (tag branches)
|
||
(seq-find
|
||
(lambda (b) (string= (jf-lcsr-branch-tag b) tag))
|
||
branches))
|
||
|
||
(defun jf-lcsr-branch-to-base (branch)
|
||
(if (jf-lcsr-branch-user-p branch)
|
||
(jf-lcsr-find-id (jf-lcsr-branch-id branch) (jf-lcsr-base-branches))
|
||
branch))
|
||
|
||
(defun jf-lcsr-branch-to-my (branch)
|
||
(jf-lcsr-branch (jf-lcsr-branch-id branch) jf-lcsr-me))
|
||
|
||
(defun jf-lcsr-branch-to-toggle (branch)
|
||
(if (jf-lcsr-branch-base-p branch)
|
||
(jf-lcsr-branch-to-my branch)
|
||
(jf-lcsr-branch-to-base branch)))
|
||
|
||
(defun jf-lcsr-prepend-id (msg branch)
|
||
(if (jf-lcsr-branch-p branch)
|
||
(concat "#" (jf-lcsr-branch-id branch) " " msg)
|
||
msg))
|
||
|
||
(defun jf-lcsr-commit-message (msg)
|
||
(jf-lcsr-prepend-id msg (magit-get-current-branch)))
|
||
|
||
(defun jf-lcsr-merge-message (current source)
|
||
(let ((message (concat "Merge branch " source " into " current)))
|
||
(if (jf-lcsr-branch-id= source current)
|
||
(jf-lcsr-prepend-id message current)
|
||
(jf-lcsr-prepend-id (jf-lcsr-prepend-id message source) current))))
|
||
|
||
;;; Navigation Functions
|
||
(defun jf-lcsr-checkout-base ()
|
||
(interactive)
|
||
(magit-checkout (jf-lcsr-branch-to-base (magit-get-current-branch))))
|
||
|
||
(defun jf-lcsr-checkout-my ()
|
||
(interactive)
|
||
(magit-checkout (jf-lcsr-branch-to-my (magit-get-current-branch))))
|
||
|
||
(defun jf-lcsr-checkout-toggle ()
|
||
(interactive)
|
||
(magit-checkout (jf-lcsr-branch-to-toggle (magit-get-current-branch))))
|
||
|
||
(defun jf-lcsr-checkout-id (id)
|
||
(interactive
|
||
(list
|
||
(completing-read
|
||
"ID: "
|
||
(mapcar (lambda (b) (jf-lcsr-branch-id b))
|
||
(jf-lcsr-base-branches)))))
|
||
(magit-checkout
|
||
(jf-lcsr-find-id id (jf-lcsr-base-branches))))
|
||
|
||
(defun jf-lcsr-checkout-tag (tag)
|
||
(interactive
|
||
(list
|
||
(completing-read
|
||
"Tag: "
|
||
(mapcar (lambda (b) (jf-lcsr-branch-tag b))
|
||
(jf-lcsr-base-branches)))))
|
||
(magit-checkout
|
||
(jf-lcsr-find-tag tag (jf-lcsr-base-branches))))
|
||
|
||
;;; Committing Functions
|
||
(defun jf-lcsr-commit (msg)
|
||
(interactive "sMessage: ")
|
||
(let ((default-directory (magit-toplevel)))
|
||
(magit-run-git
|
||
"commit"
|
||
`(,(concat "-m" (jf-lcsr-commit-message msg))))))
|
||
|
||
(defun jf-lcsr-merge-toggle ()
|
||
(interactive)
|
||
(let ((current (magit-get-current-branch))
|
||
(source (jf-lcsr-branch-to-toggle (magit-get-current-branch))))
|
||
(magit-run-git-async
|
||
"merge"
|
||
`(,(concat "-m " (jf-lcsr-merge-message current source))) source)))
|
||
|
||
(defun jf-lcsr-mergeback ()
|
||
(interactive)
|
||
(jf-lcsr-checkout-base)
|
||
(jf-lcsr-merge-toggle))
|
||
|
||
(defun jf-lcsr-merge (source)
|
||
(interactive
|
||
(list
|
||
(completing-read
|
||
"Branch: "
|
||
(magit-list-branch-names))))
|
||
(magit-run-git-async
|
||
"merge"
|
||
`(,(concat "-m " (jf-lcsr-merge-message (magit-get-current-branch) source))) source))
|
||
|
||
;; Misc functions
|
||
(defun jf-lcsr-issue-new (id tag source)
|
||
(interactive
|
||
(list
|
||
(read-string "ID: ")
|
||
(read-string "Tag: ")
|
||
(let ((input
|
||
(completing-read
|
||
"Branch Off (default master): "
|
||
(mapcar (lambda (b) (jf-lcsr-branch-tag b))
|
||
(jf-lcsr-base-branches))
|
||
nil nil nil nil "master")))
|
||
(if (string= input "master")
|
||
input
|
||
(jf-lcsr-find-tag input (jf-lcsr-base-branches))))))
|
||
(let ((base-branch (jf-lcsr-branch id tag))
|
||
(my-branch (jf-lcsr-branch id jf-lcsr-me)))
|
||
(magit-branch-create base-branch source)
|
||
(magit-checkout base-branch)
|
||
(magit-branch-create my-branch base-branch)
|
||
(magit-checkout my-branch)))
|
||
|
||
(define-transient-command jf-lcsr-issue-dispatch ()
|
||
["Navigation"
|
||
("b b" "Checkout Feature <-> User" jf-lcsr-checkout-toggle)
|
||
("b i" "Checkout ID" jf-lcsr-checkout-id)
|
||
("b t" "Checkout Tag" jf-lcsr-checkout-tag)]
|
||
["Commits"
|
||
("c" "Commit with Tag" jf-lcsr-commit)
|
||
("m t" "Merge Feature <-> User" jf-lcsr-merge-toggle)
|
||
("m b" "Merge User -> Feature" jf-lcsr-mergeback)
|
||
("m m" "Merge" jf-lcsr-merge)]))
|
||
#+END_SRC
|
||
*** Forge
|
||
Magic GitHub facilities for git forges such as GitHub and GitLab!
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package forge
|
||
:after magit)
|
||
#+END_SRC
|
||
*** Smeargle
|
||
Highlights regions in files by last update time.
|
||
Older regions are more whitey and newer regions are more blacky.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package smeargle
|
||
:general
|
||
(jf-git-def
|
||
"H t" 'smeargle
|
||
"H h" 'smeargle-commits
|
||
"H c" 'smeargle-clear))
|
||
#+END_SRC
|
||
** Projects
|
||
*** Projectile
|
||
Projectile provides project-level features like
|
||
make shortcuts and file switching
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
*** Projectile ibuffer
|
||
Groups buffers in ibuffer by their project root directory.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ibuffer-projectile
|
||
:preface
|
||
(defun jf-ibuffer-hook ()
|
||
(ibuffer-projectile-set-filter-groups)
|
||
(unless (eq ibuffer-sorting-mode 'alphabetic)
|
||
(ibuffer-do-sort-by-alphabetic)))
|
||
:hook (ibuffer . #'jf-ibuffer-hook))
|
||
#+END_SRC
|
||
** Languages
|
||
*** Language Server Protocol
|
||
Mode for integration with lots of language servers, interacting with company,
|
||
flycheck, projectile, and the works.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package lsp-mode
|
||
:commands lsp)
|
||
|
||
(use-package lsp-ui
|
||
:commands lsp-ui-mode)
|
||
|
||
(use-package company-lsp
|
||
:commands company-lsp)
|
||
#+END_SRC
|
||
*** Fish
|
||
Mode for editing of scripts for the fish shell.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package fish-mode
|
||
:mode "\\.fish\\'")
|
||
#+END_SRC
|
||
*** Markdown
|
||
Mode for editing markdown.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package markdown-mode
|
||
:mode "\\.md\\'")
|
||
#+END_SRC
|
||
|
||
*** Python
|
||
Jedi for autocompletion sources in python-mode.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package company-jedi
|
||
:company python-mode)
|
||
#+END_SRC
|
||
*** Javascript
|
||
rjsx-mode includes a javascript mode with support for react jsx files.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package rjsx-mode
|
||
:pin melpa
|
||
:mode "\\.js\\'"
|
||
:interpreter "node")
|
||
#+END_SRC
|
||
*** Web
|
||
Web-mode should give everything you need for a web-dev major mode.
|
||
Company integration is done with company-web.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
|
||
*** JSON
|
||
Mode for editing JSON files.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package json-mode
|
||
:mode "\\.json\\'")
|
||
#+END_SRC
|
||
*** YAML
|
||
Mode for editing YAML files.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package yaml-mode
|
||
:mode "\\.yaml\\'")
|
||
**** ob-ipython
|
||
Allows embedding ipython in org mode files. See the [[https://github.com/gregsexton/ob-ipython][github]] for tips, tricks, and tutorials.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package ob-ipython)
|
||
#+END_SRC
|
||
#+END_SRC
|
||
|
||
*** Arch PKGBUILD
|
||
Mode for editing PKGBUILD files.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package pkgbuild-mode
|
||
:mode ".*PKGBUILD\\'")
|
||
#+END_SRC
|
||
|
||
*** LaTeX
|
||
**** AUCTeX
|
||
AUCTeX is a major mode for editing TeX.
|
||
Company completions are handled by company-auctex and company-math.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
**** Cdlatex
|
||
cdlatex adds better TeX-specific template expansions and other niceties.
|
||
***** Environment
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-cdlatex-envs nil)
|
||
#+END_SRC
|
||
***** Commands
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-cdlatex-commands nil)
|
||
#+END_SRC
|
||
***** Math Symbols
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq jf-cdlatex-symbols
|
||
'((?I ("\\infty"))))
|
||
#+END_SRC
|
||
***** Setup
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
*** Rust
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
*** C/C++
|
||
**** Irony
|
||
Irony handles enhanced C/C++ operations powered by clang
|
||
company-irony for company integration
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
*** Lua
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package lua-mode
|
||
:mode "\\.lua\\'")
|
||
|
||
(use-package company-lua
|
||
:company lua-mode)
|
||
#+END_SRC
|
||
*** Elixir
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package elixir-mode
|
||
:mode "\\.exs?\\'"
|
||
:hook (elixir-mode . lsp))
|
||
#+END_SRC
|
||
*** Java
|
||
**** Eclim
|
||
Secretly actually use eclipse in the background in the form of eclimd
|
||
for all of the IDE like features.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
**** Gradle
|
||
The std:: java build system
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
*** GLSL
|
||
Support for editing GLSL shader files.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package glsl-mode
|
||
:mode ("\\.vert\\'"
|
||
"\\.frag\\'"
|
||
"\\.comp\\'"
|
||
"\\.glsl\\'"))
|
||
|
||
(use-package company-glsl
|
||
:company glsl-mode)
|
||
#+END_SRC
|